1 /* vi_mode.c -- A vi emulation mode for Bash.
3 Derived from code written by Jeff Sparkes (jeff1@????).
7 /* **************************************************************** */
9 /* VI Emulation Mode */
11 /* **************************************************************** */
13 /* Last string searched for from `/' or `?'. */
14 static char *vi_last_search
= (char *)NULL
;
15 static int vi_histpos
;
17 /* Non-zero means enter insertion mode. */
18 int vi_doing_insert
= 0;
21 /* Command keys which do movement for xxx_to commands. */
22 static char *vi_motion
= " hl^$0ftFt;,%wbeWBE|";
24 /* Keymap used for vi replace characters. Created dynamically since
26 static Keymap vi_replace_map
= (Keymap
)NULL
;
28 /* The number of characters inserted in the last replace operation. */
29 static vi_replace_count
= 0;
31 /* Yank the nth arg from the previous line into this line at point. */
32 rl_vi_yank_arg (count
)
35 rl_yank_nth_arg (count
, 0);
38 /* Search again for the last thing searched for. */
39 rl_vi_search_again (ignore
, key
)
45 rl_vi_dosearch (vi_last_search
, -1);
49 rl_vi_dosearch (vi_last_search
, 1);
54 /* Do a vi style search. */
55 rl_vi_search (count
, key
)
76 vi_histpos
= where_history ();
80 /* Reuse the line input buffer to read the search string. */
82 rl_end
= rl_point
= 0;
83 p
= (char *)alloca (2 + (rl_prompt
? strlen (rl_prompt
) : 0));
85 sprintf (p
, "%s%c", rl_prompt
? rl_prompt
: "", key
);
89 while (c
= rl_read_key ())
105 rl_dispatch (c
, keymap
);
115 maybe_unsave_line ();
129 free (vi_last_search
);
131 vi_last_search
= savestring (the_line
);
132 rl_vi_dosearch (the_line
, dir
);
135 rl_vi_dosearch (string
, dir
)
139 int old
, save
= vi_histpos
;
142 if (string
== 0 || *string
== 0 || vi_histpos
< 0)
148 if ((save
= history_search_pos (string
, dir
, vi_histpos
+ dir
)) == -1)
150 maybe_unsave_line ();
159 old
= where_history ();
160 history_set_pos (vi_histpos
);
161 h
= current_history ();
162 history_set_pos (old
);
164 strcpy (the_line
, h
->line
);
165 rl_undo_list
= (UNDO_LIST
*)h
->data
;
166 rl_end
= strlen (the_line
);
171 /* Completion, from vi's point of view. */
172 rl_vi_complete (ignore
, key
)
175 if (!whitespace (the_line
[rl_point
]))
177 if (!whitespace (the_line
[rl_point
+ 1]))
178 rl_vi_end_word (1, 'E');
183 rl_complete_internal ('*');
185 rl_complete (0, key
);
187 rl_vi_insertion_mode ();
190 /* Previous word in vi mode. */
191 rl_vi_prev_word (count
, key
)
196 rl_vi_next_word (-count
, key
);
200 if (uppercase_p (key
))
206 /* Next word in vi mode. */
207 rl_vi_next_word (count
, key
)
212 rl_vi_prev_word (-count
, key
);
216 if (uppercase_p (key
))
222 /* Move to the end of the ?next? word. */
223 rl_vi_end_word (count
, key
)
232 if (uppercase_p (key
))
238 /* Move forward a word the way that 'W' does. */
242 while (count
-- && rl_point
< (rl_end
- 1))
244 /* Skip until whitespace. */
245 while (!whitespace (the_line
[rl_point
]) && rl_point
< rl_end
)
248 /* Now skip whitespace. */
249 while (whitespace (the_line
[rl_point
]) && rl_point
< rl_end
)
257 while (count
-- && rl_point
> 0)
259 while (rl_point
-- >= 0 && whitespace (the_line
[rl_point
]));
260 while (rl_point
>= 0 && !whitespace (the_line
[rl_point
]))
269 while (count
-- && rl_point
< (rl_end
- 1))
271 while (rl_point
++ < rl_end
&& whitespace (the_line
[rl_point
]));
272 while (rl_point
++ < rl_end
&& !whitespace (the_line
[rl_point
]));
280 while (count
-- && rl_point
< (rl_end
- 1))
282 if (isident (the_line
[rl_point
]))
284 while (isident (the_line
[rl_point
]) && rl_point
< rl_end
)
287 else if (!whitespace (the_line
[rl_point
]))
289 while (!isident (the_line
[rl_point
]) &&
290 !whitespace (the_line
[rl_point
]) && rl_point
< rl_end
)
294 while (whitespace (the_line
[rl_point
]) && rl_point
< rl_end
)
302 while (count
-- && rl_point
> 0)
304 while (--rl_point
> 0 && whitespace (the_line
[rl_point
]));
307 if (isident (the_line
[rl_point
]))
308 while (--rl_point
>= 0 && isident (the_line
[rl_point
]));
310 while (--rl_point
>= 0 && !isident (the_line
[rl_point
]) &&
311 !whitespace (the_line
[rl_point
]));
320 while (count
-- && rl_point
< rl_end
- 1)
322 while (++rl_point
< rl_end
&& whitespace (the_line
[rl_point
]));
324 if (rl_point
< rl_end
)
326 if (isident (the_line
[rl_point
]))
327 while (++rl_point
< rl_end
&& isident (the_line
[rl_point
]));
329 while (++rl_point
< rl_end
&& !isident (the_line
[rl_point
])
330 && !whitespace (the_line
[rl_point
]));
339 rl_vi_insertion_mode ();
345 if (rl_point
< rl_end
)
347 rl_vi_insertion_mode ();
354 rl_vi_append_mode ();
358 /* What to do in the case of C-d. */
359 rl_vi_eof_maybe (count
, c
)
362 rl_newline (1, '\n');
365 /* Insertion mode stuff. */
367 /* Switching from one mode to the other really just involves
368 switching keymaps. */
369 rl_vi_insertion_mode ()
371 keymap
= vi_insertion_keymap
;
374 rl_vi_movement_mode ()
379 keymap
= vi_movement_keymap
;
380 vi_done_inserting ();
387 rl_end_undo_group ();
392 rl_vi_arg_digit (count
, c
)
395 if (c
== '0' && rl_numeric_arg
== 1 && !rl_explicit_arg
)
398 rl_digit_argument (count
, c
);
401 /* Doesn't take an arg count in vi */
402 rl_vi_change_case (ignore1
, ignore2
)
403 int ignore1
, ignore2
;
407 if (uppercase_p (the_line
[rl_point
]))
408 c
= to_lower (the_line
[rl_point
]);
409 else if (lowercase_p (the_line
[rl_point
]))
410 c
= to_upper (the_line
[rl_point
]);
412 /* Vi is kind of strange here. */
415 rl_begin_undo_group ();
418 rl_end_undo_group ();
425 rl_vi_put (count
, key
)
428 if (!uppercase_p (key
))
437 if (rl_point
&& rl_point
== rl_end
)
446 rl_point
= count
- 1;
450 rl_vi_domove (key
, nextkey
)
459 if (!member (c
, vi_motion
))
463 save
= rl_numeric_arg
;
465 rl_numeric_arg
*= save
;
467 else if ((key
== 'd' && c
== 'd') ||
468 (key
== 'c' && c
== 'c'))
478 rl_dispatch (c
, keymap
);
480 /* No change in position means the command failed. */
481 if (rl_mark
== rl_point
)
484 if ((c
== 'w' || c
== 'W') && rl_point
< rl_end
)
487 if (rl_mark
< rl_point
)
488 exchange (rl_point
, rl_mark
);
493 /* A simplified loop for vi. Don't dispatch key at end.
494 Don't recognize minus sign? */
501 rl_message ("(arg: %d) ", arg_sign
* rl_numeric_arg
, 0);
502 key
= c
= rl_read_key ();
504 if (keymap
[c
].type
== ISFUNC
&&
505 keymap
[c
].function
== rl_universal_argument
)
514 rl_numeric_arg
= (rl_numeric_arg
* 10) + (c
- '0');
516 rl_numeric_arg
= (c
- '0');
527 rl_vi_delete_to (count
, key
)
532 if (uppercase_p (key
))
535 if (rl_vi_domove (key
, &c
))
541 if ((c
!= '|') && (c
!= 'h') && rl_mark
< rl_end
)
544 rl_kill_text (rl_point
, rl_mark
);
547 rl_vi_change_to (count
, key
)
552 if (uppercase_p (key
))
555 if (rl_vi_domove (key
, &c
))
561 if ((c
!= '|') && (c
!= 'h') && rl_mark
< rl_end
)
564 rl_begin_undo_group ();
566 rl_kill_text (rl_point
, rl_mark
);
567 rl_vi_insertion_mode ();
570 rl_vi_yank_to (count
, key
)
573 int c
, save
= rl_point
;
575 if (uppercase_p (key
))
578 if (rl_vi_domove (key
, &c
))
584 rl_begin_undo_group ();
585 rl_kill_text (rl_point
, rl_mark
);
586 rl_end_undo_group ();
593 if (rl_point
>= rl_end
- 1)
595 rl_delete (count
, 0);
600 rl_delete (count
, 0);
603 /* Turn the current line into a comment in shell history. A ksh function */
607 rl_insert_text (": "); /* # doesn't work in interactive mode */
609 rl_newline (1, '\010');
614 rl_back_to_indent ();
617 rl_back_to_indent (ignore1
, ignore2
)
618 int ignore1
, ignore2
;
621 while (rl_point
< rl_end
&& whitespace (the_line
[rl_point
]))
625 /* NOTE: it is necessary that opposite directions are inverses */
626 #define FTO 1 /* forward to */
627 #define BTO -1 /* backward to */
628 #define FFIND 2 /* forward find */
629 #define BFIND -2 /* backward find */
631 rl_vi_char_search (count
, key
)
635 static int orig_dir
, dir
;
638 if (key
== ';' || key
== ',')
639 dir
= (key
== ';' ? orig_dir
: -orig_dir
);
642 target
= rl_getc (in_stream
);
647 orig_dir
= dir
= FTO
;
651 orig_dir
= dir
= BTO
;
655 orig_dir
= dir
= FFIND
;
659 orig_dir
= dir
= BFIND
;
671 if (the_line
[pos
] == target
)
693 if (the_line
[pos
] == target
)
702 while (++pos
< rl_end
);
704 if (pos
>= (rl_end
- 1))
712 int count
= 1, brack
, pos
;
715 if ((brack
= rl_vi_bracktype (the_line
[rl_point
])) == 0)
717 while ((brack
= rl_vi_bracktype (the_line
[rl_point
])) == 0 &&
718 rl_point
< rl_end
- 1)
737 int b
= rl_vi_bracktype (the_line
[pos
]);
756 int b
= rl_vi_bracktype (the_line
[pos
]);
792 c
= rl_getc (in_stream
);
801 rl_begin_undo_group ();
804 rl_end_undo_group ();
809 rl_vi_subst (count
, key
)
812 rl_begin_undo_group ();
815 if (uppercase_p (key
))
823 rl_vi_insertion_mode ();
826 rl_vi_overstrike (count
, key
)
831 if (vi_doing_insert
== 0)
834 rl_begin_undo_group ();
837 for (i
= 0; i
< count
; i
++)
840 rl_begin_undo_group ();
842 if (rl_point
< rl_end
)
850 rl_end_undo_group ();
854 rl_vi_overstrike_delete (count
)
859 for (i
= 0; i
< count
; i
++)
861 if (vi_replace_count
== 0)
875 if (vi_replace_count
== 0 && vi_doing_insert
)
877 rl_end_undo_group ();
887 vi_replace_count
= 0;
889 vi_replace_map
= rl_make_bare_keymap ();
891 for (i
= ' '; i
< 127; i
++)
892 vi_replace_map
[i
].function
= rl_vi_overstrike
;
894 vi_replace_map
[RUBOUT
].function
= rl_vi_overstrike_delete
;
895 vi_replace_map
[ESC
].function
= rl_vi_movement_mode
;
896 vi_replace_map
[RETURN
].function
= rl_newline
;
897 vi_replace_map
[NEWLINE
].function
= rl_newline
;
898 keymap
= vi_replace_map
;
902 * Try to complete the word we are standing on or the word that ends with
903 * the previous character. A space matches everything.
904 * Word delimiters are space and ;.
906 rl_vi_possible_completions()
908 int save_pos
= rl_point
;
910 if (!index (" ;", the_line
[rl_point
]))
912 while (!index(" ;", the_line
[++rl_point
]))
915 else if (the_line
[rl_point
-1] == ';')
921 rl_possible_completions ();
This page took 0.048274 seconds and 4 git commands to generate.