@@ -37,52 +37,91 @@ pub enum GraphemeSource {
37
37
} ,
38
38
}
39
39
40
+ impl GraphemeSource {
41
+ /// Returns whether this grapheme is virtual inline text
42
+ pub fn is_virtual ( self ) -> bool {
43
+ matches ! ( self , GraphemeSource :: VirtualText { .. } )
44
+ }
45
+
46
+ pub fn doc_chars ( self ) -> usize {
47
+ match self {
48
+ GraphemeSource :: Document { codepoints } => codepoints as usize ,
49
+ GraphemeSource :: VirtualText { .. } => 0 ,
50
+ }
51
+ }
52
+ }
53
+
40
54
#[ derive( Debug , Clone ) ]
41
55
pub struct FormattedGrapheme < ' a > {
42
- pub grapheme : Grapheme < ' a > ,
56
+ pub raw : Grapheme < ' a > ,
43
57
pub source : GraphemeSource ,
58
+ pub visual_pos : Position ,
59
+ /// Document line at the start of the grapheme
60
+ pub line_idx : usize ,
61
+ /// Document char position at the start of the grapheme
62
+ pub char_idx : usize ,
44
63
}
45
64
46
- impl < ' a > FormattedGrapheme < ' a > {
47
- pub fn new (
65
+ impl FormattedGrapheme < ' _ > {
66
+ pub fn is_virtual ( & self ) -> bool {
67
+ self . source . is_virtual ( )
68
+ }
69
+
70
+ pub fn doc_chars ( & self ) -> usize {
71
+ self . source . doc_chars ( )
72
+ }
73
+
74
+ pub fn is_whitespace ( & self ) -> bool {
75
+ self . raw . is_whitespace ( )
76
+ }
77
+
78
+ pub fn width ( & self ) -> usize {
79
+ self . raw . width ( )
80
+ }
81
+
82
+ pub fn is_word_boundary ( & self ) -> bool {
83
+ self . raw . is_word_boundary ( )
84
+ }
85
+ }
86
+
87
+ #[ derive( Debug , Clone ) ]
88
+ struct GraphemeWithSource < ' a > {
89
+ grapheme : Grapheme < ' a > ,
90
+ source : GraphemeSource ,
91
+ }
92
+
93
+ impl < ' a > GraphemeWithSource < ' a > {
94
+ fn new (
48
95
g : GraphemeStr < ' a > ,
49
96
visual_x : usize ,
50
97
tab_width : u16 ,
51
98
source : GraphemeSource ,
52
- ) -> FormattedGrapheme < ' a > {
53
- FormattedGrapheme {
99
+ ) -> GraphemeWithSource < ' a > {
100
+ GraphemeWithSource {
54
101
grapheme : Grapheme :: new ( g, visual_x, tab_width) ,
55
102
source,
56
103
}
57
104
}
58
- /// Returns whether this grapheme is virtual inline text
59
- pub fn is_virtual ( & self ) -> bool {
60
- matches ! ( self . source, GraphemeSource :: VirtualText { .. } )
61
- }
62
-
63
- pub fn placeholder ( ) -> Self {
64
- FormattedGrapheme {
105
+ fn placeholder ( ) -> Self {
106
+ GraphemeWithSource {
65
107
grapheme : Grapheme :: Other { g : " " . into ( ) } ,
66
108
source : GraphemeSource :: Document { codepoints : 0 } ,
67
109
}
68
110
}
69
111
70
- pub fn doc_chars ( & self ) -> usize {
71
- match self . source {
72
- GraphemeSource :: Document { codepoints } => codepoints as usize ,
73
- GraphemeSource :: VirtualText { .. } => 0 ,
74
- }
112
+ fn doc_chars ( & self ) -> usize {
113
+ self . source . doc_chars ( )
75
114
}
76
115
77
- pub fn is_whitespace ( & self ) -> bool {
116
+ fn is_whitespace ( & self ) -> bool {
78
117
self . grapheme . is_whitespace ( )
79
118
}
80
119
81
- pub fn width ( & self ) -> usize {
120
+ fn width ( & self ) -> usize {
82
121
self . grapheme . width ( )
83
122
}
84
123
85
- pub fn is_word_boundary ( & self ) -> bool {
124
+ fn is_word_boundary ( & self ) -> bool {
86
125
self . grapheme . is_word_boundary ( )
87
126
}
88
127
}
@@ -139,9 +178,9 @@ pub struct DocumentFormatter<'t> {
139
178
indent_level : Option < usize > ,
140
179
/// In case a long word needs to be split a single grapheme might need to be wrapped
141
180
/// while the rest of the word stays on the same line
142
- peeked_grapheme : Option < ( FormattedGrapheme < ' t > , usize ) > ,
181
+ peeked_grapheme : Option < GraphemeWithSource < ' t > > ,
143
182
/// A first-in first-out (fifo) buffer for the Graphemes of any given word
144
- word_buf : Vec < FormattedGrapheme < ' t > > ,
183
+ word_buf : Vec < GraphemeWithSource < ' t > > ,
145
184
/// The index of the next grapheme that will be yielded from the `word_buf`
146
185
word_i : usize ,
147
186
}
@@ -157,32 +196,33 @@ impl<'t> DocumentFormatter<'t> {
157
196
text_fmt : & ' t TextFormat ,
158
197
annotations : & ' t TextAnnotations ,
159
198
char_idx : usize ,
160
- ) -> ( Self , usize ) {
199
+ ) -> Self {
161
200
// TODO divide long lines into blocks to avoid bad performance for long lines
162
201
let block_line_idx = text. char_to_line ( char_idx. min ( text. len_chars ( ) ) ) ;
163
202
let block_char_idx = text. line_to_char ( block_line_idx) ;
164
203
annotations. reset_pos ( block_char_idx) ;
165
- (
166
- DocumentFormatter {
167
- text_fmt,
168
- annotations,
169
- visual_pos : Position { row : 0 , col : 0 } ,
170
- graphemes : RopeGraphemes :: new ( text. slice ( block_char_idx..) ) ,
171
- char_pos : block_char_idx,
172
- exhausted : false ,
173
- virtual_lines : 0 ,
174
- indent_level : None ,
175
- peeked_grapheme : None ,
176
- word_buf : Vec :: with_capacity ( 64 ) ,
177
- word_i : 0 ,
178
- line_pos : block_line_idx,
179
- inline_anntoation_graphemes : None ,
180
- } ,
181
- block_char_idx,
182
- )
204
+
205
+ DocumentFormatter {
206
+ text_fmt,
207
+ annotations,
208
+ visual_pos : Position { row : 0 , col : 0 } ,
209
+ graphemes : RopeGraphemes :: new ( text. slice ( block_char_idx..) ) ,
210
+ char_pos : block_char_idx,
211
+ exhausted : false ,
212
+ virtual_lines : 0 ,
213
+ indent_level : None ,
214
+ peeked_grapheme : None ,
215
+ word_buf : Vec :: with_capacity ( 64 ) ,
216
+ word_i : 0 ,
217
+ line_pos : block_line_idx,
218
+ inline_anntoation_graphemes : None ,
219
+ }
183
220
}
184
221
185
- fn next_inline_annotation_grapheme ( & mut self ) -> Option < ( & ' t str , Option < Highlight > ) > {
222
+ fn next_inline_annotation_grapheme (
223
+ & mut self ,
224
+ char_pos : usize ,
225
+ ) -> Option < ( & ' t str , Option < Highlight > ) > {
186
226
loop {
187
227
if let Some ( & mut ( ref mut annotation, highlight) ) =
188
228
self . inline_anntoation_graphemes . as_mut ( )
@@ -193,7 +233,7 @@ impl<'t> DocumentFormatter<'t> {
193
233
}
194
234
195
235
if let Some ( ( annotation, highlight) ) =
196
- self . annotations . next_inline_annotation_at ( self . char_pos )
236
+ self . annotations . next_inline_annotation_at ( char_pos)
197
237
{
198
238
self . inline_anntoation_graphemes = Some ( (
199
239
UnicodeSegmentation :: graphemes ( & * annotation. text , true ) ,
@@ -205,21 +245,20 @@ impl<'t> DocumentFormatter<'t> {
205
245
}
206
246
}
207
247
208
- fn advance_grapheme ( & mut self , col : usize ) -> Option < FormattedGrapheme < ' t > > {
248
+ fn advance_grapheme ( & mut self , col : usize , char_pos : usize ) -> Option < GraphemeWithSource < ' t > > {
209
249
let ( grapheme, source) =
210
- if let Some ( ( grapheme, highlight) ) = self . next_inline_annotation_grapheme ( ) {
250
+ if let Some ( ( grapheme, highlight) ) = self . next_inline_annotation_grapheme ( char_pos ) {
211
251
( grapheme. into ( ) , GraphemeSource :: VirtualText { highlight } )
212
252
} else if let Some ( grapheme) = self . graphemes . next ( ) {
213
253
self . virtual_lines += self . annotations . annotation_lines_at ( self . char_pos ) ;
214
254
let codepoints = grapheme. len_chars ( ) as u32 ;
215
255
216
- let overlay = self . annotations . overlay_at ( self . char_pos ) ;
256
+ let overlay = self . annotations . overlay_at ( char_pos) ;
217
257
let grapheme = match overlay {
218
258
Some ( ( overlay, _) ) => overlay. grapheme . as_str ( ) . into ( ) ,
219
259
None => Cow :: from ( grapheme) . into ( ) ,
220
260
} ;
221
261
222
- self . char_pos += codepoints as usize ;
223
262
( grapheme, GraphemeSource :: Document { codepoints } )
224
263
} else {
225
264
if self . exhausted {
@@ -228,19 +267,19 @@ impl<'t> DocumentFormatter<'t> {
228
267
self . exhausted = true ;
229
268
// EOF grapheme is required for rendering
230
269
// and correct position computations
231
- return Some ( FormattedGrapheme {
270
+ return Some ( GraphemeWithSource {
232
271
grapheme : Grapheme :: Other { g : " " . into ( ) } ,
233
272
source : GraphemeSource :: Document { codepoints : 0 } ,
234
273
} ) ;
235
274
} ;
236
275
237
- let grapheme = FormattedGrapheme :: new ( grapheme, col, self . text_fmt . tab_width , source) ;
276
+ let grapheme = GraphemeWithSource :: new ( grapheme, col, self . text_fmt . tab_width , source) ;
238
277
239
278
Some ( grapheme)
240
279
}
241
280
242
281
/// Move a word to the next visual line
243
- fn wrap_word ( & mut self , virtual_lines_before_word : usize ) -> usize {
282
+ fn wrap_word ( & mut self ) -> usize {
244
283
// softwrap this word to the next line
245
284
let indent_carry_over = if let Some ( indent) = self . indent_level {
246
285
if indent as u16 <= self . text_fmt . max_indent_retain {
@@ -255,14 +294,13 @@ impl<'t> DocumentFormatter<'t> {
255
294
} ;
256
295
257
296
self . visual_pos . col = indent_carry_over as usize ;
258
- self . virtual_lines -= virtual_lines_before_word;
259
- self . visual_pos . row += 1 + virtual_lines_before_word;
297
+ self . visual_pos . row += 1 + take ( & mut self . virtual_lines ) ;
260
298
let mut i = 0 ;
261
299
let mut word_width = 0 ;
262
300
let wrap_indicator = UnicodeSegmentation :: graphemes ( & * self . text_fmt . wrap_indicator , true )
263
301
. map ( |g| {
264
302
i += 1 ;
265
- let grapheme = FormattedGrapheme :: new (
303
+ let grapheme = GraphemeWithSource :: new (
266
304
g. into ( ) ,
267
305
self . visual_pos . col + word_width,
268
306
self . text_fmt . tab_width ,
@@ -288,8 +326,7 @@ impl<'t> DocumentFormatter<'t> {
288
326
fn advance_to_next_word ( & mut self ) {
289
327
self . word_buf . clear ( ) ;
290
328
let mut word_width = 0 ;
291
- let virtual_lines_before_word = self . virtual_lines ;
292
- let mut virtual_lines_before_grapheme = self . virtual_lines ;
329
+ let mut word_chars = 0 ;
293
330
294
331
loop {
295
332
// softwrap word if necessary
@@ -301,27 +338,24 @@ impl<'t> DocumentFormatter<'t> {
301
338
// However if the last grapheme is multiple columns wide it might extend beyond the EOL.
302
339
// The condition below ensures that this grapheme is not cutoff and instead wrapped to the next line
303
340
if word_width + self . visual_pos . col > self . text_fmt . viewport_width as usize {
304
- self . peeked_grapheme = self . word_buf . pop ( ) . map ( |grapheme| {
305
- ( grapheme, self . virtual_lines - virtual_lines_before_grapheme)
306
- } ) ;
307
- self . virtual_lines = virtual_lines_before_grapheme;
341
+ self . peeked_grapheme = self . word_buf . pop ( ) ;
308
342
}
309
343
return ;
310
344
}
311
345
312
- word_width = self . wrap_word ( virtual_lines_before_word ) ;
346
+ word_width = self . wrap_word ( ) ;
313
347
}
314
348
315
- virtual_lines_before_grapheme = self . virtual_lines ;
316
-
317
- let grapheme = if let Some ( ( grapheme, virtual_lines) ) = self . peeked_grapheme . take ( ) {
318
- self . virtual_lines += virtual_lines;
349
+ let grapheme = if let Some ( grapheme) = self . peeked_grapheme . take ( ) {
319
350
grapheme
320
- } else if let Some ( grapheme) = self . advance_grapheme ( self . visual_pos . col + word_width) {
351
+ } else if let Some ( grapheme) =
352
+ self . advance_grapheme ( self . visual_pos . col + word_width, self . char_pos + word_chars)
353
+ {
321
354
grapheme
322
355
} else {
323
356
return ;
324
357
} ;
358
+ word_chars += grapheme. doc_chars ( ) ;
325
359
326
360
// Track indentation
327
361
if !grapheme. is_whitespace ( ) && self . indent_level . is_none ( ) {
@@ -340,19 +374,19 @@ impl<'t> DocumentFormatter<'t> {
340
374
}
341
375
}
342
376
343
- /// returns the document line pos of the **next** grapheme that will be yielded
344
- pub fn line_pos ( & self ) -> usize {
345
- self . line_pos
377
+ /// returns the char index at the end of the last yielded grapheme
378
+ pub fn next_char_pos ( & self ) -> usize {
379
+ self . char_pos
346
380
}
347
381
348
- /// returns the visual pos of the **next** grapheme that will be yielded
349
- pub fn visual_pos ( & self ) -> Position {
382
+ /// returns the visual position at the end of the last yielded grapheme
383
+ pub fn next_visual_pos ( & self ) -> Position {
350
384
self . visual_pos
351
385
}
352
386
}
353
387
354
388
impl < ' t > Iterator for DocumentFormatter < ' t > {
355
- type Item = ( FormattedGrapheme < ' t > , Position ) ;
389
+ type Item = FormattedGrapheme < ' t > ;
356
390
357
391
fn next ( & mut self ) -> Option < Self :: Item > {
358
392
let grapheme = if self . text_fmt . soft_wrap {
@@ -362,15 +396,18 @@ impl<'t> Iterator for DocumentFormatter<'t> {
362
396
}
363
397
let grapheme = replace (
364
398
self . word_buf . get_mut ( self . word_i ) ?,
365
- FormattedGrapheme :: placeholder ( ) ,
399
+ GraphemeWithSource :: placeholder ( ) ,
366
400
) ;
367
401
self . word_i += 1 ;
368
402
grapheme
369
403
} else {
370
- self . advance_grapheme ( self . visual_pos . col ) ?
404
+ self . advance_grapheme ( self . visual_pos . col , self . char_pos ) ?
371
405
} ;
372
406
373
- let pos = self . visual_pos ;
407
+ let visual_pos = self . visual_pos ;
408
+ let char_pos = self . char_pos ;
409
+ self . char_pos += grapheme. doc_chars ( ) ;
410
+ let line_idx = self . line_pos ;
374
411
if grapheme. grapheme == Grapheme :: Newline {
375
412
self . visual_pos . row += 1 ;
376
413
self . visual_pos . row += take ( & mut self . virtual_lines ) ;
@@ -379,6 +416,12 @@ impl<'t> Iterator for DocumentFormatter<'t> {
379
416
} else {
380
417
self . visual_pos . col += grapheme. width ( ) ;
381
418
}
382
- Some ( ( grapheme, pos) )
419
+ Some ( FormattedGrapheme {
420
+ raw : grapheme. grapheme ,
421
+ source : grapheme. source ,
422
+ visual_pos,
423
+ line_idx,
424
+ char_idx : char_pos,
425
+ } )
383
426
}
384
427
}
0 commit comments