@@ -12,7 +12,9 @@ use tui::text::Span;
12
12
use tui:: widgets:: { Block , Widget } ;
13
13
14
14
use helix_core:: {
15
- unicode:: segmentation:: GraphemeCursor , unicode:: width:: UnicodeWidthStr , Position ,
15
+ unicode:: segmentation:: { GraphemeCursor , UnicodeSegmentation } ,
16
+ unicode:: width:: UnicodeWidthStr ,
17
+ Position ,
16
18
} ;
17
19
use helix_view:: {
18
20
graphics:: { CursorKind , Margin , Rect } ,
@@ -535,21 +537,51 @@ impl Prompt {
535
537
. into ( ) ;
536
538
text. render ( self . line_area , surface, cx) ;
537
539
} else {
538
- if self . line . len ( ) < self . line_area . width as usize {
540
+ let line_width = self . line_area . width as usize ;
541
+
542
+ if self . line . width ( ) < line_width {
539
543
self . anchor = 0 ;
540
- } else if self . cursor < self . anchor {
541
- self . anchor = self . cursor ;
542
- } else if self . cursor - self . anchor > self . line_area . width as usize {
543
- self . anchor = self . cursor - self . line_area . width as usize ;
544
+ } else if self . cursor <= self . anchor {
545
+ // Ensure the grapheme under the cursor is in view.
546
+ self . anchor = self . line [ ..self . cursor ]
547
+ . grapheme_indices ( true )
548
+ . next_back ( )
549
+ . map ( |( i, _) | i)
550
+ . unwrap_or_default ( ) ;
551
+ } else if self . line [ self . anchor ..self . cursor ] . width ( ) > line_width {
552
+ // Set the anchor to the last grapheme cluster before the width is exceeded.
553
+ let mut width = 0 ;
554
+ self . anchor = self . line [ ..self . cursor ]
555
+ . grapheme_indices ( true )
556
+ . rev ( )
557
+ . find_map ( |( idx, g) | {
558
+ width += g. width ( ) ;
559
+ if width > line_width {
560
+ Some ( idx + g. len ( ) )
561
+ } else {
562
+ None
563
+ }
564
+ } )
565
+ . unwrap ( ) ;
544
566
}
545
567
546
568
self . truncate_start = self . anchor > 0 ;
547
- self . truncate_end = self . line . len ( ) - self . anchor > self . line_area . width as usize ;
569
+ self . truncate_end = self . line [ self . anchor .. ] . width ( ) > line_width ;
548
570
549
571
// if we keep inserting characters just before the end elipsis, we move the anchor
550
572
// so that those new characters are displayed
551
- if self . truncate_end && self . cursor - self . anchor >= self . line_area . width as usize {
552
- self . anchor += 1 ;
573
+ if self . truncate_end && self . line [ self . anchor ..self . cursor ] . width ( ) >= line_width {
574
+ // Move the anchor forward by one non-zero-width grapheme.
575
+ self . anchor += self . line [ self . anchor ..]
576
+ . grapheme_indices ( true )
577
+ . find_map ( |( idx, g) | {
578
+ if g. width ( ) > 0 {
579
+ Some ( idx + g. len ( ) )
580
+ } else {
581
+ None
582
+ }
583
+ } )
584
+ . unwrap ( ) ;
553
585
}
554
586
555
587
surface. set_string_anchored (
@@ -558,7 +590,7 @@ impl Prompt {
558
590
self . truncate_start ,
559
591
self . truncate_end ,
560
592
& self . line . as_str ( ) [ self . anchor ..] ,
561
- self . line_area . width as usize - self . truncate_end as usize ,
593
+ line_width ,
562
594
|_| prompt_color,
563
595
) ;
564
596
}
@@ -734,17 +766,21 @@ impl Component for Prompt {
734
766
. clip_left ( self . prompt . len ( ) as u16 )
735
767
. clip_right ( if self . prompt . is_empty ( ) { 2 } else { 0 } ) ;
736
768
737
- let anchor = self . anchor . min ( self . line . len ( ) . saturating_sub ( 1 ) ) ;
738
- let mut col = area. left ( ) as usize
739
- + UnicodeWidthStr :: width ( & self . line [ anchor..self . cursor . max ( anchor) ] ) ;
769
+ let mut col = area. left ( ) as usize + self . line [ self . anchor ..self . cursor ] . width ( ) ;
740
770
741
771
// ensure the cursor does not go beyond elipses
742
- if self . truncate_end && self . cursor - self . anchor >= self . line_area . width as usize {
772
+ if self . truncate_end
773
+ && self . line [ self . anchor ..self . cursor ] . width ( ) >= self . line_area . width as usize
774
+ {
743
775
col -= 1 ;
744
776
}
745
777
746
778
if self . truncate_start && self . cursor == self . anchor {
747
- col += 1 ;
779
+ col += self . line [ self . cursor ..]
780
+ . graphemes ( true )
781
+ . next ( )
782
+ . unwrap ( )
783
+ . width ( ) ;
748
784
}
749
785
750
786
let line = area. height as usize - 1 ;
0 commit comments