@@ -2,6 +2,7 @@ use super::{edit_stack::EditStack, Clipboard, ClipboardMode, LineBuffer};
22#[ cfg( feature = "system_clipboard" ) ]
33use crate :: core_editor:: get_system_clipboard;
44use crate :: enums:: { EditType , UndoBehavior } ;
5+ use crate :: prompt:: { PromptEditMode , PromptViMode } ;
56use crate :: { core_editor:: get_local_clipboard, EditCommand } ;
67use std:: ops:: DerefMut ;
78
@@ -17,6 +18,7 @@ pub struct Editor {
1718 edit_stack : EditStack < LineBuffer > ,
1819 last_undo_behavior : UndoBehavior ,
1920 selection_anchor : Option < usize > ,
21+ edit_mode : PromptEditMode ,
2022}
2123
2224impl Default for Editor {
@@ -29,6 +31,7 @@ impl Default for Editor {
2931 edit_stack : EditStack :: new ( ) ,
3032 last_undo_behavior : UndoBehavior :: CreateUndoPoint ,
3133 selection_anchor : None ,
34+ edit_mode : PromptEditMode :: Default ,
3235 }
3336 }
3437}
@@ -212,6 +215,11 @@ impl Editor {
212215 None
213216 } ;
214217 }
218+
219+ /// Updates the current edit mode for mode-aware selection behavior
220+ pub fn set_edit_mode ( & mut self , mode : PromptEditMode ) {
221+ self . edit_mode = mode;
222+ }
215223 fn move_to_position ( & mut self , position : usize , select : bool ) {
216224 self . update_selection_anchor ( select) ;
217225 self . line_buffer . set_insertion_point ( position)
@@ -625,8 +633,10 @@ impl Editor {
625633
626634 /// If a selection is active returns the selected range, otherwise None.
627635 /// The range is guaranteed to be ascending.
636+ /// Automatically determines inclusive/exclusive based on current edit mode.
628637 pub fn get_selection ( & self ) -> Option < ( usize , usize ) > {
629- self . get_selection_with_mode ( true )
638+ let inclusive = matches ! ( self . edit_mode, PromptEditMode :: Vi ( PromptViMode :: Normal ) ) ;
639+ self . get_selection_with_mode ( inclusive)
630640 }
631641
632642 /// If a selection is active returns the selected range, otherwise None.
@@ -638,19 +648,21 @@ impl Editor {
638648 let buffer_len = self . line_buffer . len ( ) ;
639649 if self . insertion_point ( ) > selection_anchor {
640650 let end_pos = if inclusive {
641- // Only extend for Vi normal mode where cursor is on the character
642- // For Emacs and Vi insert modes, use cursor position directly
643- self . insertion_point ( ) . min ( buffer_len)
651+ // Vi normal mode: extend selection to include character under cursor
652+ self . line_buffer . grapheme_right_index ( ) . min ( buffer_len)
644653 } else {
654+ // Emacs/Vi insert mode: cursor is between characters
645655 self . insertion_point ( ) . min ( buffer_len)
646656 } ;
647657 ( selection_anchor, end_pos)
648658 } else {
649659 let end_pos = if inclusive {
650- // Only extend for Vi normal mode where cursor is on the character
651- // For Emacs and Vi insert modes, use anchor position directly
652- selection_anchor. min ( buffer_len)
660+ // Vi normal mode: extend selection to include character under cursor
661+ self . line_buffer
662+ . grapheme_right_index_from_pos ( selection_anchor)
663+ . min ( buffer_len)
653664 } else {
665+ // Emacs/Vi insert mode: cursor is between characters
654666 selection_anchor. min ( buffer_len)
655667 } ;
656668 ( self . insertion_point ( ) , end_pos)
@@ -1175,6 +1187,22 @@ mod test {
11751187 assert_eq ! ( editor. get_selection( ) , Some ( ( 0 , 3 ) ) ) ;
11761188 }
11771189
1190+ #[ test]
1191+ fn test_vi_normal_mode_inclusive_selection ( ) {
1192+ let mut editor = editor_with ( "This is some test content" ) ;
1193+ editor. line_buffer . set_insertion_point ( 0 ) ;
1194+ editor. set_edit_mode ( PromptEditMode :: Vi ( PromptViMode :: Normal ) ) ;
1195+ editor. update_selection_anchor ( true ) ;
1196+
1197+ for _ in 0 ..3 {
1198+ editor. run_edit_command ( & EditCommand :: MoveRight { select : true } ) ;
1199+ }
1200+ assert_eq ! ( editor. selection_anchor, Some ( 0 ) ) ;
1201+ assert_eq ! ( editor. insertion_point( ) , 3 ) ;
1202+ // In Vi normal mode, selection should be inclusive (include character at position 3)
1203+ assert_eq ! ( editor. get_selection( ) , Some ( ( 0 , 4 ) ) ) ;
1204+ }
1205+
11781206 #[ cfg( feature = "system_clipboard" ) ]
11791207 mod without_system_clipboard {
11801208 use super :: * ;
0 commit comments