@@ -23,8 +23,13 @@ mod lines {
2323 pub fn empty ( ) -> LoadedLine {
2424 LoadedLine { chars : vec ! [ ] }
2525 }
26- pub fn new ( chars : Vec < char > ) -> LoadedLine {
27- LoadedLine { chars }
26+ pub fn new ( chars : & [ char ] ) -> LoadedLine {
27+ LoadedLine {
28+ chars : Vec :: from ( chars) ,
29+ }
30+ }
31+ pub fn from_vec ( chars : Vec < char > ) -> LoadedLine {
32+ LoadedLine { chars : chars }
2833 }
2934 pub fn len ( & self ) -> usize {
3035 self . chars . len ( )
@@ -56,6 +61,136 @@ mod lines {
5661 }
5762}
5863
64+ mod chunks {
65+
66+ use std:: slice:: { RSplit , Split } ;
67+
68+ use crate :: lines:: LoadedLine ;
69+
70+ pub struct Chunk < ' a > {
71+ file_offset : u64 ,
72+ is_modified : bool ,
73+ data : & ' a [ char ] ,
74+ }
75+
76+ impl Chunk < ' _ > {
77+ pub fn from_disk ( file_offset : u64 , data : & [ char ] ) -> Chunk {
78+ Chunk {
79+ file_offset,
80+ is_modified : false ,
81+ data,
82+ }
83+ }
84+
85+ pub fn lines_iter ( & self ) -> ChunkLinesIter {
86+ ChunkLinesIter {
87+ chunk : self ,
88+ forward : self . data . split ( Box :: new ( |c : & char | * c == '\n' ) ) ,
89+ back : self . data . rsplit ( Box :: new ( |c : & char | * c == '\n' ) ) ,
90+ }
91+ }
92+ }
93+
94+ pub struct ChunkLinesIter < ' a > {
95+ chunk : & ' a Chunk < ' a > ,
96+ forward : Split < ' a , char , Box < dyn FnMut ( & char ) -> bool > > ,
97+ back : RSplit < ' a , char , Box < dyn FnMut ( & char ) -> bool > > ,
98+ }
99+
100+ impl < ' a > Iterator for ChunkLinesIter < ' a > {
101+ type Item = LoadedLine ;
102+
103+ fn next ( & mut self ) -> Option < Self :: Item > {
104+ let line = self . forward . next ( ) ;
105+ return line. map ( LoadedLine :: new) ;
106+ }
107+ }
108+
109+ impl < ' a > DoubleEndedIterator for ChunkLinesIter < ' a > {
110+ fn next_back ( & mut self ) -> Option < Self :: Item > {
111+ let line = self . back . next ( ) ;
112+ return line. map ( LoadedLine :: new) ;
113+ }
114+ }
115+ }
116+
117+ #[ cfg( test) ]
118+ mod tests {
119+
120+ use chunks:: Chunk ;
121+
122+ #[ test]
123+ fn test_chunk_lines_iter ( ) {
124+ let data: Vec < char > = "line1\n line2\n line3\n " . chars ( ) . collect ( ) ;
125+ let chunk = Chunk :: from_disk ( 0 , & data) ;
126+ let mut iter = chunk. lines_iter ( ) ;
127+
128+ assert_eq ! (
129+ iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
130+ "line1"
131+ ) ;
132+ assert_eq ! (
133+ iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
134+ "line2"
135+ ) ;
136+ assert_eq ! (
137+ iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
138+ "line3"
139+ ) ;
140+
141+ assert_eq ! ( iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) , "" ) ;
142+ assert ! ( iter. next( ) . is_none( ) ) ;
143+ }
144+
145+ #[ test]
146+ fn test_chunk_lines_iter_empty ( ) {
147+ let data: Vec < char > = "" . chars ( ) . collect ( ) ;
148+ let chunk = Chunk :: from_disk ( 0 , & data) ;
149+ let mut iter = chunk. lines_iter ( ) ;
150+
151+ assert_eq ! ( iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) , "" ) ;
152+ assert ! ( iter. next( ) . is_none( ) ) ;
153+ }
154+
155+ #[ test]
156+ fn test_chunk_lines_iter_no_newline ( ) {
157+ let data: Vec < char > = "line1" . chars ( ) . collect ( ) ;
158+ let chunk = Chunk :: from_disk ( 0 , & data) ;
159+ let mut iter = chunk. lines_iter ( ) ;
160+
161+ assert_eq ! (
162+ iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
163+ "line1"
164+ ) ;
165+ assert ! ( iter. next( ) . is_none( ) ) ;
166+ }
167+
168+ #[ test]
169+ fn test_chunk_lines_iter_double_ended ( ) {
170+ let data: Vec < char > = "line1\n line2\n line3\n " . chars ( ) . collect ( ) ;
171+ let chunk = Chunk :: from_disk ( 0 , & data) ;
172+ let mut iter = chunk. lines_iter ( ) ;
173+
174+ assert_eq ! (
175+ iter. next_back( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
176+ ""
177+ ) ;
178+ assert_eq ! (
179+ iter. next_back( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
180+ "line3"
181+ ) ;
182+ assert_eq ! (
183+ iter. next_back( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
184+ "line2"
185+ ) ;
186+ assert_eq ! (
187+ iter. next_back( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
188+ "line1"
189+ ) ;
190+ assert ! ( iter. next_back( ) . is_none( ) ) ;
191+ }
192+ }
193+
59194use lines:: LoadedLine ;
60195
61196// TODO
@@ -65,7 +200,7 @@ use lines::LoadedLine;
65200//
66201// Other editors:
67202// - emacs: gap buffer
68- // - vim: rope
203+ // - vim: rope (https://github.com/vim/vim/blob/master/src/memline.c and https://github.com/vim/vim/blob/master/src/memfile.c)
69204//
70205// Idea:
71206// List of contiguous chunks: (disk_offset, data, is_modified).
@@ -340,7 +475,7 @@ impl State {
340475 self . cursor . y += 1 ;
341476 self . cursor . x = 0 ;
342477 self . lines
343- . insert ( self . cursor . y as usize , LoadedLine :: new ( new_line) ) ;
478+ . insert ( self . cursor . y as usize , LoadedLine :: from_vec ( new_line) ) ;
344479 }
345480
346481 fn draw_frame ( & self , frame : & mut Frame ) {
0 commit comments