@@ -146,21 +146,21 @@ def do(self) -> None:
146146# Find Commands (f/F/t/T)
147147# ============================================================================
148148
149- def _make_find_char_keymap ( ) -> tuple [tuple [str , str ], ...]:
150- """Create a keymap where all printable ASCII maps to vi-find-execute .
149+ def _make_char_capture_keymap ( execute_cmd : str , cancel_cmd : str ) -> tuple [tuple [str , str ], ...]:
150+ """Create a keymap where all printable ASCII maps to execute_cmd .
151151
152- Once vi-find-execute is called, it will pop our input translator."""
152+ Once execute_cmd is called, it will pop our input translator."""
153153 entries = []
154154 for i in range (32 , 127 ):
155155 if i == 92 : # backslash needs escaping
156- entries .append ((r"\\" , "vi-find-execute" ))
156+ entries .append ((r"\\" , execute_cmd ))
157157 else :
158- entries .append ((chr (i ), "vi-find-execute" ))
159- entries .append ((r"\<escape>" , "vi-find-cancel" ))
158+ entries .append ((chr (i ), execute_cmd ))
159+ entries .append ((r"\<escape>" , cancel_cmd ))
160160 return tuple (entries )
161161
162-
163- _find_char_keymap = _make_find_char_keymap ( )
162+ _find_char_keymap = _make_char_capture_keymap ( "vi-find-execute" , "vi-find-cancel" )
163+ _replace_char_keymap = _make_char_capture_keymap ( "vi-replace-execute" , "vi-replace-cancel" )
164164
165165
166166class vi_find_char (Command ):
@@ -327,3 +327,51 @@ def do(self) -> None:
327327 new_pos += 1
328328 if new_pos < r .pos :
329329 r .pos = new_pos
330+
331+
332+ # ============================================================================
333+ # Change Commands
334+ # ============================================================================
335+
336+ class vi_change_word (KillCommand ):
337+ """Change from cursor to end of word (cw)."""
338+ def do (self ) -> None :
339+ r = self .reader
340+ for _ in range (r .get_arg ()):
341+ end = r .vi_eow () + 1 # +1 to include last char
342+ if end > r .pos :
343+ self .kill_range (r .pos , end )
344+ r .enter_insert_mode ()
345+
346+
347+ # ============================================================================
348+ # Replace Commands
349+ # ============================================================================
350+
351+ class vi_replace_char (Command ):
352+ """Replace character under cursor with next typed character (r)."""
353+ def do (self ) -> None :
354+ r = self .reader
355+ translator = _input .KeymapTranslator (
356+ _replace_char_keymap ,
357+ invalid_cls = "vi-replace-cancel" ,
358+ character_cls = "vi-replace-execute"
359+ )
360+ r .push_input_trans (translator )
361+
362+ class vi_replace_execute (Command ):
363+ """Execute character replacement with the pressed character."""
364+ def do (self ) -> None :
365+ r = self .reader
366+ r .pop_input_trans ()
367+ pending_char = self .event [- 1 ]
368+ if not pending_char or r .pos >= len (r .buffer ):
369+ return
370+ r .buffer [r .pos ] = pending_char
371+ r .dirty = True
372+
373+ class vi_replace_cancel (Command ):
374+ """Cancel pending replace operation."""
375+ def do (self ) -> None :
376+ r = self .reader
377+ r .pop_input_trans ()
0 commit comments