@@ -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,154 @@ mod lines {
5661 }
5762}
5863
64+ mod chunks {
65+
66+ use crate :: lines:: LoadedLine ;
67+
68+ pub struct Chunk < ' a > {
69+ file_offset : u64 ,
70+ is_modified : bool ,
71+ data : & ' a [ char ] ,
72+ }
73+
74+ impl Chunk < ' _ > {
75+ pub fn from_disk ( file_offset : u64 , data : & [ char ] ) -> Chunk {
76+ Chunk {
77+ file_offset,
78+ is_modified : false ,
79+ data,
80+ }
81+ }
82+
83+ pub fn lines_iter ( & self ) -> ChunkLinesIter {
84+ ChunkLinesIter {
85+ chunk : self ,
86+ offset_in_chunk : 0 ,
87+ }
88+ }
89+ }
90+
91+ pub struct ChunkLinesIter < ' a > {
92+ chunk : & ' a Chunk < ' a > ,
93+ offset_in_chunk : usize ,
94+ }
95+
96+ impl < ' a > Iterator for ChunkLinesIter < ' a > {
97+ type Item = LoadedLine ;
98+
99+ fn next ( & mut self ) -> Option < Self :: Item > {
100+ for ( i, c) in self
101+ . chunk
102+ . data
103+ . iter ( )
104+ . skip ( self . offset_in_chunk )
105+ . enumerate ( )
106+ {
107+ if * c != '\n' {
108+ continue ;
109+ }
110+ let slice = & self . chunk . data [ self . offset_in_chunk ..i] ;
111+ let line = LoadedLine :: new ( slice) ;
112+ self . offset_in_chunk = i;
113+ return Some ( line) ;
114+ }
115+ self . offset_in_chunk = self . chunk . data . len ( ) ;
116+ return None ;
117+ }
118+ }
119+ impl < ' a > DoubleEndedIterator for ChunkLinesIter < ' a > {
120+ fn next_back ( & mut self ) -> Option < Self :: Item > {
121+ for ( i, c) in self
122+ . chunk
123+ . data
124+ . iter ( )
125+ . skip ( self . offset_in_chunk )
126+ . rev ( )
127+ . enumerate ( )
128+ {
129+ if * c != '\n' {
130+ continue ;
131+ }
132+ let slice = & self . chunk . data [ self . offset_in_chunk ..i] ;
133+ let line = LoadedLine :: new ( slice) ;
134+ self . offset_in_chunk = i;
135+ return Some ( line) ;
136+ }
137+ self . offset_in_chunk = self . chunk . data . len ( ) ;
138+ return None ;
139+ }
140+ }
141+ }
142+ #[ cfg( test) ]
143+ mod tests {
144+
145+ use chunks:: Chunk ;
146+
147+ #[ test]
148+ fn test_chunk_lines_iter ( ) {
149+ let data: Vec < char > = "line1\n line2\n line3\n " . chars ( ) . collect ( ) ;
150+ let chunk = Chunk :: from_disk ( 0 , & data) ;
151+ let mut iter = chunk. lines_iter ( ) ;
152+
153+ assert_eq ! (
154+ iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
155+ "line1"
156+ ) ;
157+ assert_eq ! (
158+ iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
159+ "line2"
160+ ) ;
161+ assert_eq ! (
162+ iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
163+ "line3"
164+ ) ;
165+ assert ! ( iter. next( ) . is_none( ) ) ;
166+ }
167+
168+ #[ test]
169+ fn test_chunk_lines_iter_empty ( ) {
170+ let data: Vec < char > = "" . chars ( ) . collect ( ) ;
171+ let chunk = Chunk :: from_disk ( 0 , & data) ;
172+ let mut iter = chunk. lines_iter ( ) ;
173+
174+ assert ! ( iter. next( ) . is_none( ) ) ;
175+ }
176+
177+ #[ test]
178+ fn test_chunk_lines_iter_no_newline ( ) {
179+ let data: Vec < char > = "line1" . chars ( ) . collect ( ) ;
180+ let chunk = Chunk :: from_disk ( 0 , & data) ;
181+ let mut iter = chunk. lines_iter ( ) ;
182+
183+ assert_eq ! (
184+ iter. next( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
185+ "line1"
186+ ) ;
187+ assert ! ( iter. next( ) . is_none( ) ) ;
188+ }
189+
190+ #[ test]
191+ fn test_chunk_lines_iter_double_ended ( ) {
192+ let data: Vec < char > = "line1\n line2\n line3\n " . chars ( ) . collect ( ) ;
193+ let chunk = Chunk :: from_disk ( 0 , & data) ;
194+ let mut iter = chunk. lines_iter ( ) ;
195+
196+ assert_eq ! (
197+ iter. next_back( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
198+ "line3"
199+ ) ;
200+ assert_eq ! (
201+ iter. next_back( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
202+ "line2"
203+ ) ;
204+ assert_eq ! (
205+ iter. next_back( ) . unwrap( ) . chars_iter( ) . collect:: <String >( ) ,
206+ "line1"
207+ ) ;
208+ assert ! ( iter. next_back( ) . is_none( ) ) ;
209+ }
210+ }
211+
59212use lines:: LoadedLine ;
60213
61214// TODO
@@ -65,7 +218,7 @@ use lines::LoadedLine;
65218//
66219// Other editors:
67220// - emacs: gap buffer
68- // - vim: rope
221+ // - vim: rope (https://github.com/vim/vim/blob/master/src/memline.c and https://github.com/vim/vim/blob/master/src/memfile.c)
69222//
70223// Idea:
71224// List of contiguous chunks: (disk_offset, data, is_modified).
@@ -340,7 +493,7 @@ impl State {
340493 self . cursor . y += 1 ;
341494 self . cursor . x = 0 ;
342495 self . lines
343- . insert ( self . cursor . y as usize , LoadedLine :: new ( new_line) ) ;
496+ . insert ( self . cursor . y as usize , LoadedLine :: from_vec ( new_line) ) ;
344497 }
345498
346499 fn draw_frame ( & self , frame : & mut Frame ) {
0 commit comments