@@ -244,6 +244,8 @@ consume(const string_fragment text)
244
244
static const auto SPACE_RE
245
245
= lnav::pcre2pp::code::from_const (R"( (*UTF)^\s)" );
246
246
247
+ require (text.is_valid ());
248
+
247
249
if (text.empty ()) {
248
250
return eof{text};
249
251
}
@@ -270,16 +272,8 @@ consume(const string_fragment text)
270
272
return space{split_res.first , split_res.second };
271
273
}
272
274
273
- auto csize_res = ww898::utf::utf8::char_size (
274
- [&text]() { return std::make_pair (text.front (), text.length ()); });
275
-
276
- if (csize_res.isErr ()) {
277
- auto split_res = text.split_n (1 );
278
-
279
- return corrupt{split_res->first , split_res->second };
280
- }
281
-
282
- auto split_res = text.split_n (csize_res.unwrap ());
275
+ auto next_char_byte_index = text.column_to_byte_index (1 );
276
+ auto split_res = text.split_n (next_char_byte_index);
283
277
284
278
return word{split_res->first , split_res->second };
285
279
}
@@ -314,6 +308,8 @@ attr_line_t::insert(size_t index,
314
308
const attr_line_t & al,
315
309
text_wrap_settings* tws)
316
310
{
311
+ require (!tws || tws->tws_width > 0 );
312
+
317
313
if (index < this ->al_string .length ()) {
318
314
shift_string_attrs (this ->al_attrs , index , al.al_string .length ());
319
315
}
@@ -323,7 +319,7 @@ attr_line_t::insert(size_t index,
323
319
for (const auto & sa : al.al_attrs ) {
324
320
this ->al_attrs .emplace_back (sa);
325
321
326
- line_range & lr = this ->al_attrs .back ().sa_range ;
322
+ auto & lr = this ->al_attrs .back ().sa_range ;
327
323
328
324
lr.shift (0 , index );
329
325
if (lr.lr_end == -1 ) {
@@ -335,7 +331,8 @@ attr_line_t::insert(size_t index,
335
331
return *this ;
336
332
}
337
333
338
- auto starting_line_index = this ->al_string .rfind (' \n ' , index );
334
+ auto starting_line_index = index == 0 ? std::string::npos
335
+ : this ->al_string .rfind (' \n ' , index - 1 );
339
336
if (starting_line_index == std::string::npos) {
340
337
starting_line_index = 0 ;
341
338
} else {
@@ -378,12 +375,20 @@ attr_line_t::insert(size_t index,
378
375
auto pre_iter = find_string_attr_containing (
379
376
this ->al_attrs , &SA_PREFORMATTED, text_to_wrap.sf_begin );
380
377
if (pre_iter != this ->al_attrs .end ()) {
378
+ require_ge (pre_iter->sa_range .lr_start , text_to_wrap.sf_begin );
381
379
auto pre_len = pre_iter->sa_range .lr_end - text_to_wrap.sf_begin ;
382
380
auto pre_lf = text_to_wrap.find (' \n ' );
383
- if (pre_lf && pre_lf.value () < pre_len) {
381
+ if (pre_lf && pre_lf.value () + 1 < pre_len) {
384
382
pre_len = pre_lf.value () + 1 ;
383
+ auto lr_copy = pre_iter->sa_range ;
384
+ const_cast <int &>(pre_iter->sa_range .lr_end )
385
+ = pre_iter->sa_range .lr_start + pre_len;
386
+ this ->al_attrs .emplace_back (lr_copy, SA_PREFORMATTED.value ());
387
+ this ->al_attrs .back ().sa_range .lr_start
388
+ = lr_copy.lr_start + pre_len;
385
389
}
386
390
391
+ require_ge (text_to_wrap.length (), pre_len);
387
392
auto pre_pair = text_to_wrap.split_n (pre_len);
388
393
next_chunk = text_stream::word{
389
394
pre_pair->first ,
@@ -395,9 +400,8 @@ attr_line_t::insert(size_t index,
395
400
}
396
401
397
402
text_to_wrap = next_chunk.match (
398
- [&](text_stream::word word) {
399
- auto ch_count
400
- = word.w_word .utf8_length ().unwrapOr (word.w_word .length ());
403
+ [&](const text_stream::word& word) {
404
+ auto ch_count = word.w_word .column_width ();
401
405
402
406
if (line_ch_count > line_indent_count && !last_was_pre
403
407
&& (line_ch_count + ch_count) > usable_width)
@@ -421,8 +425,8 @@ attr_line_t::insert(size_t index,
421
425
auto trailing_space_count = 0 ;
422
426
if (!last_word.empty ()) {
423
427
trailing_space_count
424
- = word.w_word .sf_begin - last_word.sf_begin ;
425
- this ->erase (last_word.sf_begin , trailing_space_count);
428
+ = word.w_word .sf_begin - last_word.sf_end ;
429
+ this ->erase (last_word.sf_end , trailing_space_count);
426
430
}
427
431
return word.w_remaining
428
432
.erase_before (this ->al_string .data (),
@@ -439,7 +443,7 @@ attr_line_t::insert(size_t index,
439
443
440
444
return word.w_remaining ;
441
445
},
442
- [&](text_stream::space space) {
446
+ [&](const text_stream::space& space) {
443
447
if (space.s_value == " \n " ) {
444
448
line_ch_count = 0 ;
445
449
line_indent_count = 0 ;
@@ -448,8 +452,7 @@ attr_line_t::insert(size_t index,
448
452
}
449
453
450
454
if (line_ch_count > 0 ) {
451
- auto ch_count = space.s_value .utf8_length ().unwrapOr (
452
- space.s_value .length ());
455
+ auto ch_count = space.s_value .column_width ();
453
456
454
457
if ((line_ch_count + ch_count) > usable_width
455
458
&& find_string_attr_containing (this ->al_attrs ,
@@ -467,15 +470,18 @@ attr_line_t::insert(size_t index,
467
470
auto trailing_space_count = 0 ;
468
471
if (!last_word.empty ()) {
469
472
trailing_space_count
470
- = space.s_value .sf_begin - last_word.sf_begin ;
473
+ = space.s_value .sf_begin - last_word.sf_end ;
471
474
this ->erase (last_word.sf_end , trailing_space_count);
472
475
}
473
-
474
- return space.s_remaining
475
- .erase_before (
476
- this ->al_string .data (),
477
- space.s_value .length () + trailing_space_count)
478
- .prepend (this ->al_string .data (), 1 );
476
+ last_word.clear ();
477
+
478
+ auto retval
479
+ = space.s_remaining
480
+ .erase_before (this ->al_string .data (),
481
+ space.s_value .length ()
482
+ + trailing_space_count)
483
+ .prepend (this ->al_string .data (), 1 );
484
+ return retval;
479
485
}
480
486
line_ch_count += ch_count;
481
487
} else if (find_string_attr_containing (this ->al_attrs ,
@@ -494,7 +500,7 @@ attr_line_t::insert(size_t index,
494
500
[](text_stream::eof eof) { return eof.e_remaining ; });
495
501
496
502
if (next_chunk.is <text_stream::word>()) {
497
- last_word = text_to_wrap ;
503
+ last_word = next_chunk. get <text_stream::word>(). w_word ;
498
504
}
499
505
last_was_pre = (pre_iter != this ->al_attrs .end ());
500
506
0 commit comments