7
7
///|
8
8
/// The main zipper data structure
9
9
pub struct StringZipper {
10
- priv left : Array [@string .View ] // string views to the left of cursor
10
+ priv left : @list . List [@string .View ] // string views to the left of cursor
11
11
priv rel_pos : Int // cursor position within current string view
12
12
priv abs_pos : Int // total length of strings in left
13
13
priv current : @string .View // current string view containing cursor
14
14
priv line : Int // number of '\n' characters traversed
15
- priv right : Array [@string .View ] // string views to the right of cursor
15
+ priv right : @list . List [@string .View ] // string views to the right of cursor
16
16
}
17
17
18
18
///|
19
19
/// Creates a string zipper from a string
20
20
pub fn StringZipper ::of_string (s : String ) -> StringZipper {
21
- { left : [], rel_pos : 0 , abs_pos : 0 , current : s .view (), right : [], line : 0 }
21
+ {
22
+ left : @list .empty (),
23
+ rel_pos : 0 ,
24
+ abs_pos : 0 ,
25
+ current : s .view (),
26
+ right : @list .empty (),
27
+ line : 0 ,
28
+ }
22
29
}
23
30
24
31
///|
@@ -39,19 +46,18 @@ fn to_string_and_pos(self : StringZipper) -> (String, Int, Int) {
39
46
// Use StringBuilder for efficient string building
40
47
let builder = StringBuilder ::new ()
41
48
42
- // Add left string views in reverse order
43
- for i = self .left.length () - 1 ; i >= 0 ; i = i - 1 {
44
- builder .write_string (self .left[i ].to_string ())
49
+ // Add left string views in reverse order (since they were prepended)
50
+ let left_array = self .left.to_array ()
51
+ for i = left_array .length () - 1 ; i >= 0 ; i = i - 1 {
52
+ builder .write_string (left_array [i ].to_string ())
45
53
}
46
54
let final_pos = builder .to_string ().length () + self .rel_pos
47
55
48
56
// Add current string view
49
57
builder .write_string (self .current.to_string ())
50
58
51
59
// Add right string views
52
- for view in self .right {
53
- builder .write_string (view .to_string ())
54
- }
60
+ self .right.each (fn (view ) { builder .write_string (view .to_string ()) })
55
61
(builder .to_string (), final_pos , self .line)
56
62
}
57
63
@@ -63,18 +69,15 @@ pub fn to_string(self : StringZipper) -> String {
63
69
}
64
70
65
71
///|
66
- /// Helper function to add string view to array if not empty
67
- fn cons (view : @string .View , arr : Array [@string .View ]) -> Array [@string .View ] {
72
+ /// Helper function to add string view to list if not empty
73
+ fn cons (
74
+ view : @string .View ,
75
+ list : @list .List [@string .View ],
76
+ ) -> @list .List [@string .View ] {
68
77
if view .length () == 0 {
69
- arr
78
+ list
70
79
} else {
71
- // Use proper Array operations from standard library
72
- let new_arr : Array [@string .View ] = Array ::new (capacity = arr .length () + 1 )
73
- new_arr .push (view )
74
- for elem in arr {
75
- new_arr .push (elem )
76
- }
77
- new_arr
80
+ list .add (view )
78
81
}
79
82
}
80
83
@@ -190,21 +193,20 @@ fn find_next_nl(self : StringZipper) -> StringZipper {
190
193
match index_from_view (self .current, pos = self .rel_pos, '\n ' ) {
191
194
Some (rel_pos ) => { ..self , rel_pos , }
192
195
None =>
193
- if self .right. length () == 0 {
194
- { ..self , rel_pos : self .current.length () }
195
- } else {
196
- let current = self .right[ 0 ]
197
- let new_right = self .right[ 1 :]. to_array ()
198
- let abs_pos = self .abs_pos + self .current. length ()
199
- let new_zipper = {
200
- .. self ,
201
- current ,
202
- left : cons ( self .current, self .left) ,
203
- right : new_right ,
204
- rel_pos : 0 ,
205
- abs_pos ,
196
+ match self .right {
197
+ Empty => { ..self , rel_pos : self .current.length () }
198
+ More ( current , tail = new_right ) => {
199
+ let abs_pos = self .abs_pos + self .current. length ()
200
+ let new_zipper = {
201
+ .. self ,
202
+ current ,
203
+ left : cons ( self .current, self .left) ,
204
+ right : new_right ,
205
+ rel_pos : 0 ,
206
+ abs_pos ,
207
+ }
208
+ new_zipper . find_next_nl ()
206
209
}
207
- new_zipper .find_next_nl ()
208
210
}
209
211
}
210
212
}
@@ -232,20 +234,19 @@ fn prev_newline(self : StringZipper) -> StringZipper {
232
234
match rindex_from_view (self .current, pos = self .rel_pos, '\n ' ) {
233
235
Some (rel_pos ) => { ..self , rel_pos , line : self .line - 1 }
234
236
None =>
235
- if self .left. length () == 0 {
236
- { ..self , rel_pos : 0 }
237
- } else {
238
- let current = self .left[ 0 ]
239
- let new_left = self .left[ 1 :]. to_array ()
240
- let new_zipper = {
241
- .. self ,
242
- current ,
243
- left : new_left ,
244
- rel_pos : current . length ( ),
245
- abs_pos : self .abs_pos + self .current. length (),
246
- right : cons ( self .current, self .right),
237
+ match self .left {
238
+ Empty => { ..self , rel_pos : 0 }
239
+ More ( current , tail = new_left ) => {
240
+ let new_zipper = {
241
+ .. self ,
242
+ current ,
243
+ left : new_left ,
244
+ rel_pos : current . length () ,
245
+ abs_pos : self .abs_pos + self .current. length () ,
246
+ right : cons ( self . current, self .right ),
247
+ }
248
+ new_zipper . prev_newline ()
247
249
}
248
- new_zipper .prev_newline ()
249
250
}
250
251
}
251
252
}
@@ -355,9 +356,10 @@ pub fn squash(self : StringZipper) -> (StringZipper, String) {
355
356
pub fn to_string_debug (self : StringZipper ) -> String {
356
357
let builder = StringBuilder ::new ()
357
358
358
- // Add left string views in reverse order
359
- for i = self .left.length () - 1 ; i >= 0 ; i = i - 1 {
360
- builder .write_string (self .left[i ].to_string ())
359
+ // Add left string views in reverse order (since they were prepended)
360
+ let left_array = self .left.to_array ()
361
+ for i = left_array .length () - 1 ; i >= 0 ; i = i - 1 {
362
+ builder .write_string (left_array [i ].to_string ())
361
363
}
362
364
363
365
// Add current string view up to cursor position
@@ -381,9 +383,7 @@ pub fn to_string_debug(self : StringZipper) -> String {
381
383
builder .write_string (suffix )
382
384
383
385
// Add right string views
384
- for view in self .right {
385
- builder .write_string (view .to_string ())
386
- }
386
+ self .right.each (fn (view ) { builder .write_string (view .to_string ()) })
387
387
builder .to_string ()
388
388
}
389
389
@@ -408,8 +408,9 @@ pub fn StringZipper::add_buffer_between(
408
408
fn StringZipper ::is_end_internal (self : StringZipper ) -> Bool {
409
409
let res = self .current.length () == self .rel_pos
410
410
if res {
411
- if self .right.length () > 0 {
412
- abort ("invalid state: current = \{ self .current.to_string ()} " )
411
+ match self .right {
412
+ Empty => ()
413
+ _ => abort ("invalid state: current = \{ self .current.to_string ()} " )
413
414
}
414
415
}
415
416
res
@@ -418,7 +419,10 @@ fn StringZipper::is_end_internal(self : StringZipper) -> Bool {
418
419
///|
419
420
/// Checks if cursor is at the beginning of the text (internal helper)
420
421
fn StringZipper ::is_begin_internal (self : StringZipper ) -> Bool {
421
- self .left.length () == 0 && self .rel_pos == 0
422
+ match self .left {
423
+ Empty => self .rel_pos == 0
424
+ _ => false
425
+ }
422
426
}
423
427
424
428
///|
@@ -449,18 +453,18 @@ fn StringZipper::advance_char_internal(self : StringZipper) -> StringZipper {
449
453
let rel_pos = self .rel_pos + 1
450
454
if rel_pos < current_len {
451
455
{ ..self , rel_pos , line }
452
- } else if self .right.length () == 0 {
453
- { ..self , rel_pos , line }
454
456
} else {
455
- let current = self .right[0 ]
456
- let new_right = self .right[1 :].to_array ()
457
- {
458
- abs_pos : self .abs_pos + self .current.length (),
459
- left : cons (self .current, self .left),
460
- current ,
461
- line ,
462
- right : new_right ,
463
- rel_pos : 0 ,
457
+ match self .right {
458
+ Empty => { ..self , rel_pos , line }
459
+ More (current , tail = new_right ) =>
460
+ {
461
+ abs_pos : self .abs_pos + self .current.length (),
462
+ left : cons (self .current, self .left),
463
+ current ,
464
+ line ,
465
+ right : new_right ,
466
+ rel_pos : 0 ,
467
+ }
464
468
}
465
469
}
466
470
}
@@ -496,18 +500,19 @@ fn drop_until_internal(
496
500
}
497
501
let right = cons (drop_view (until .current, until .rel_pos), until .right)
498
502
let left = cons (take_view (from .current, from .rel_pos), from .left)
499
- if right .length () > 0 {
500
- let current = right [0 ]
501
- let new_right = right [1 :].to_array ()
502
- let abs_pos = from .abs_pos + from .current.length ()
503
- { ..from, right : new_right , left , abs_pos , current , rel_pos : 0 }
504
- } else if left .length () == 0 {
505
- StringZipper ::of_string ("" )
506
- } else {
507
- let current = left [0 ]
508
- let new_left = left [1 :].to_array ()
509
- let rel_pos = current .length ()
510
- let abs_pos = from .abs_pos + rel_pos
511
- { ..from, right , left : new_left , current , rel_pos , abs_pos }
503
+ match right {
504
+ More (current , tail = new_right ) => {
505
+ let abs_pos = from .abs_pos + from .current.length ()
506
+ { ..from, right : new_right , left , abs_pos , current , rel_pos : 0 }
507
+ }
508
+ Empty =>
509
+ match left {
510
+ Empty => StringZipper ::of_string ("" )
511
+ More (current , tail = new_left ) => {
512
+ let rel_pos = current .length ()
513
+ let abs_pos = from .abs_pos + rel_pos
514
+ { ..from, right , left : new_left , current , rel_pos , abs_pos }
515
+ }
516
+ }
512
517
}
513
518
}
0 commit comments