@@ -30,12 +30,21 @@ struct CursorTrackerImpl<'cursor> {
3030
3131enum TokPos {
3232 /// Position of a cursor inside a token
33- InContent {
33+ Content {
3434 /// Byte offset relative to the start of the token contents (not whitespace)
3535 offset : u32 ,
3636 } ,
37+
38+ /// Position of a cursor inside a multiline token
39+ MultilineContent {
40+ /// Byte distance of the cursor from the next line break
41+ reverse_col : u16 ,
42+ /// The number of line breaks between the cursor and the end of the token content
43+ newlines_after_cursor : u16 ,
44+ } ,
45+
3746 /// Position of a cursor in the whitespace before a token
38- InWhitespace {
47+ Whitespace {
3948 /// Column of the cursor (in bytes), measured from the previous line break
4049 col : u16 ,
4150 /// The number of line breaks between the cursor and the subsequent token
@@ -118,14 +127,40 @@ impl LogicalLinesReconstructor for DelphiLogicalLinesReconstructor {
118127 let cursors = cursor_positions
119128 . into_iter ( )
120129 . map ( |( tok_pos, cursor, tok_idx) | {
121- let tok_idx = tok_idx. unwrap_or ( tokens. len ( ) ) ;
130+ let Some ( tok_idx) = tok_idx else {
131+ return InternalCursor {
132+ cursor,
133+ tok_idx : tokens. len ( ) ,
134+ tok_pos : TokPos :: Content { offset : 0 } ,
135+ } ;
136+ } ;
137+ let tok = & tokens[ tok_idx] ;
122138
123139 let tok_pos = if tok_pos >= 0 {
124- TokPos :: InContent {
125- offset : tok_pos as u32 ,
140+ if matches ! (
141+ tok. get_token_type( ) ,
142+ RawTokenType :: TextLiteral ( TextLiteralKind :: MultiLine )
143+ | RawTokenType :: Comment ( CommentKind :: MultilineBlock )
144+ ) {
145+ let content_after_cursor = & tok. get_content ( ) [ tok_pos as usize ..] ;
146+ let reverse_col = content_after_cursor
147+ . split ( '\n' )
148+ . next ( )
149+ . map ( |line| line. len ( ) )
150+ . unwrap_or ( content_after_cursor. len ( ) ) ;
151+ let newlines_after_cursor =
152+ ( content_after_cursor. split ( '\n' ) . count ( ) - 1 ) as u16 ;
153+
154+ TokPos :: MultilineContent {
155+ reverse_col : reverse_col as u16 ,
156+ newlines_after_cursor,
157+ }
158+ } else {
159+ TokPos :: Content {
160+ offset : tok_pos as u32 ,
161+ }
126162 }
127163 } else {
128- let tok = & tokens[ tok_idx] ;
129164 let leading_ws = tok. get_leading_whitespace ( ) ;
130165 let ( ws_before_cursor, ws_after_cursor) =
131166 & leading_ws. split_at (
@@ -140,7 +175,7 @@ impl LogicalLinesReconstructor for DelphiLogicalLinesReconstructor {
140175 + Self :: col_for_token_end_pre_fmt ( tokens, tok_idx. wrapping_sub ( 1 ) )
141176 } ;
142177
143- TokPos :: InWhitespace {
178+ TokPos :: Whitespace {
144179 col : col as u16 ,
145180 newlines_after_cursor,
146181 }
@@ -253,7 +288,7 @@ impl CursorTracker for CursorTrackerImpl<'_> {
253288 for cursor in & mut self . cursors {
254289 match deleted_token. cmp ( & cursor. tok_idx ) {
255290 Ordering :: Less => cursor. tok_idx -= 1 ,
256- Ordering :: Equal => cursor. tok_pos = TokPos :: InContent { offset : 0 } ,
291+ Ordering :: Equal => cursor. tok_pos = TokPos :: Content { offset : 0 } ,
257292 Ordering :: Greater => { }
258293 }
259294 }
@@ -266,7 +301,7 @@ impl CursorTracker for CursorTrackerImpl<'_> {
266301 None => {
267302 // cursor is out of bounds, set it to the last position in the file, if possible
268303 if let Some ( t) = formatted_tokens. tokens ( ) . next_back ( ) {
269- cursor. tok_pos = TokPos :: InContent {
304+ cursor. tok_pos = TokPos :: Content {
270305 offset : t. 0 . get_content ( ) . len ( ) as u32 ,
271306 } ;
272307 t
@@ -283,11 +318,25 @@ impl CursorTracker for CursorTrackerImpl<'_> {
283318 . offset_for_token ( formatted_tokens, cursor. tok_idx ) ;
284319
285320 cursor. cursor . 0 = match cursor. tok_pos {
286- TokPos :: InContent { offset } => {
321+ TokPos :: Content { offset } => {
287322 // offset into the token content, but don't go over the end of the token if its length has changed
288323 new_token_offset as u32 + offset. min ( tok. get_content ( ) . len ( ) as u32 )
289324 }
290- TokPos :: InWhitespace {
325+ TokPos :: MultilineContent {
326+ reverse_col,
327+ newlines_after_cursor,
328+ } => {
329+ let lines = tok. get_content ( ) . rsplit ( '\n' ) ;
330+ let offset_from_end = lines
331+ . take ( newlines_after_cursor. into ( ) )
332+ // +1 for the separator
333+ . map ( |line| line. len ( ) + 1 )
334+ . sum :: < usize > ( )
335+ + reverse_col as usize ;
336+
337+ ( new_token_offset + tok. get_content ( ) . len ( ) - offset_from_end) as u32
338+ }
339+ TokPos :: Whitespace {
291340 col,
292341 newlines_after_cursor,
293342 } => {
@@ -703,7 +752,18 @@ A := 1 + '''
703752''' + | | | | |Spaces;
704753
705754A := 1 + '''
706- ''' + | | | | | Spaces;" ,
755+ ''' + | | | | | Spaces;
756+
757+ A := '''
758+ |a|aaaa| | |bb| |c|
759+ | | | |a|
760+ |
761+ d|
762+ |''';
763+
764+ A := '''
765+ | d
766+ | |''';" ,
707767 "\
708768 A
709769 = 1
@@ -725,7 +785,20 @@ A :=
725785 +
726786 '''
727787 '''
728- + | | | | |Spaces;" ,
788+ + | | | | |Spaces;
789+
790+ A :=
791+ '''
792+ |a|aaaa| | |bb| |c|
793+ | | | |a|
794+ |
795+ d|
796+ |''';
797+
798+ A :=
799+ '''
800+ | d
801+ | |''';" ,
729802 ) ;
730803 }
731804 }
0 commit comments