jeff1@garfield.mun.edu (Jeff Sparkes) (11/20/89)
This set of patches contains: 1. a bunch of fixes for vi mode, including the two recent reports. There are also extra bindings (in input mode): C-e to list completions, and C-x to do a * expansion. I made some hook functions to more completely isolate vi code. 2. undoable undos. These work the same as in emacs (I hope). BTW, anyone compiled bash under MIPS 4.[01]? I can't deal with dbx anymore. diff -rc readline.orig/funmap.c readline/funmap.c *** readline.orig/funmap.c Tue Nov 14 15:07:47 1989 --- readline/funmap.c Sun Nov 19 16:43:19 1989 *************** *** 122,127 **** --- 122,128 ---- { "vi-change-to", rl_vi_change_to }, { "vi-yank-to", rl_vi_yank_to }, { "vi-complete", rl_vi_complete }, + { "vi-rubout", rl_vi_rubout, }, #endif /* VI_MODE */ {(char *)NULL, (Function *)NULL } diff -rc readline.orig/readline.c readline/readline.c *** readline.orig/readline.c Tue Nov 14 15:07:50 1989 --- readline/readline.c Fri Nov 17 19:53:41 1989 *************** *** 159,164 **** --- 159,167 ---- /* Non-zero if the previous command was a kill command. */ static int last_command_was_kill = 0; + /* Non-zero if the previous commands was undo. */ + static int last_command_was_undo = 0; + /* The current value of the numeric argument specified by the user. */ int rl_numeric_arg = 1; *************** *** 312,317 **** --- 315,321 ---- while (!rl_done) { int lk = last_command_was_kill; + int lu = last_command_was_undo; int code = setjmp (readline_top_level); if (code) *************** *** 348,360 **** { if (lk == last_command_was_kill) last_command_was_kill = 0; } #ifdef VI_MODE ! /* In vi mode, when you exit insert mode, the cursor moves back ! over the previous character. We explicitly check for that here. */ ! if (rl_editing_mode == vi_mode && keymap == vi_movement_keymap) ! rl_vi_check (); #endif if (!rl_done) --- 352,363 ---- { if (lk == last_command_was_kill) last_command_was_kill = 0; + if (lu == last_command_was_undo) + last_command_was_undo = 0; } #ifdef VI_MODE ! rl_vi_display_hook (); #endif if (!rl_done) *************** *** 2248,2253 **** --- 2251,2259 ---- rl_point += l; rl_end += l; the_line[rl_end] = '\0'; + #ifdef VI_MODE + rl_vi_insert_hook (); + #endif } /* Delete the string between FROM and TO. FROM is *************** *** 2591,2604 **** rl_done = 1; #ifdef VI_MODE ! { ! extern int vi_doing_insert; ! if (vi_doing_insert) ! { ! rl_end_undo_group (); ! vi_doing_insert = 0; ! } ! } #endif /* VI_MODE */ if (readline_echoing_p) --- 2597,2603 ---- rl_done = 1; #ifdef VI_MODE ! rl_vi_newline_hook (); #endif /* VI_MODE */ if (readline_echoing_p) *************** *** 3520,3525 **** --- 3519,3527 ---- /* The current undo list for THE_LINE. */ UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; + /* Current position in the undo list during multiple undos. */ + UNDO_LIST *rl_undo_p = (UNDO_LIST *)NULL; + /* Remember how to undo something. Concatenate some undos if that seems right. */ rl_add_undo (what, start, end, text) *************** *** 3550,3609 **** } } ! /* Undo the next thing in the list. Return 0 if there ! is nothing to undo, or non-zero if there was. */ ! int ! rl_do_undo () ! { ! UNDO_LIST *release; ! int waiting_for_begin = 0; ! ! undo_thing: ! if (!rl_undo_list) ! return (0); ! ! doing_an_undo = 1; ! switch (rl_undo_list->what) { - /* Undoing deletes means inserting some text. */ case UNDO_DELETE: ! rl_point = rl_undo_list->start; ! rl_insert_text (rl_undo_list->text); ! free (rl_undo_list->text); break; - /* Undoing inserts means deleting some text. */ case UNDO_INSERT: ! rl_delete_text (rl_undo_list->start, rl_undo_list->end); ! rl_point = rl_undo_list->start; break; - /* Undoing an END means undoing everything 'til we get to - a BEGIN. */ case UNDO_END: ! waiting_for_begin++; break; - /* Undoing a BEGIN means that we are done with this group. */ case UNDO_BEGIN: ! if (waiting_for_begin) ! waiting_for_begin--; ! else ! abort (); break; ! } ! ! doing_an_undo = 0; ! ! release = rl_undo_list; ! rl_undo_list = rl_undo_list->next; ! free (release); ! ! if (waiting_for_begin) ! goto undo_thing; ! ! return (1); } /* Begin a group. Subsequent undos are undone as an atomic operation. */ --- 3552,3595 ---- } } ! /* Undo the next thing in the list. Note that these undos are undoable. */ ! UNDO_LIST * ! rl_do_undo (head, looking) ! UNDO_LIST *head; ! int looking; ! { ! UNDO_LIST *temp = head->next; ! if (!head) ! return; ! switch (head->what) { case UNDO_DELETE: ! rl_point = head->start; ! rl_insert_text (savestring(head->text)); ! if (looking) ! temp = rl_do_undo (head->next, looking); break; case UNDO_INSERT: ! rl_delete_text (head->start, head->end); ! rl_point = head->start; ! if (looking) ! temp = rl_do_undo (head->next, looking); break; case UNDO_END: ! rl_begin_undo_group (); ! temp = rl_do_undo (head->next, looking + 1); break; case UNDO_BEGIN: ! rl_end_undo_group (); ! if (--looking) ! temp = rl_do_undo (head->next, looking); break; ! } ! return temp; } /* Begin a group. Subsequent undos are undone as an atomic operation. */ *************** *** 3644,3671 **** { if (!rl_undo_list) ding (); else { while (rl_undo_list) ! rl_do_undo (); } } /* Do some undoing of things that were done. */ ! rl_undo_command (count) { ! if (count < 0) return; /* Nothing to do. */ ! ! while (count) ! { ! if (rl_do_undo ()) ! { ! count--; ! } ! else ! { ! ding (); ! break; ! } } } /* **************************************************************** */ --- 3630,3662 ---- { if (!rl_undo_list) ding (); else { + doing_an_undo = 1; while (rl_undo_list) ! rl_undo_list = rl_do_undo (rl_undo_list, 0); ! doing_an_undo = 0; } } /* Do some undoing of things that were done. */ ! rl_undo_command (count, key) { ! if (count < 0 ||!rl_undo_list) ! return ding(); ! if (!last_command_was_undo++) ! rl_undo_p = rl_undo_list; ! #ifdef VI_MODE ! /* Vi undo only undos last action. Shouldn't add to undo list though. */ ! if (rl_editing_mode == vi_mode && key == 'u') ! rl_undo_p = rl_undo_list; ! #endif ! while (count--) { ! if (rl_undo_p) ! rl_undo_p = rl_do_undo (rl_undo_p, 0); ! else { ! ding (); ! break; } + } } /* **************************************************************** */ *************** *** 3841,3850 **** strcpy (the_line, temp->line); rl_undo_list = (UNDO_LIST *)temp->data; rl_end = rl_point = strlen (the_line); - #ifdef VI_MODE - if (rl_editing_mode == vi_mode) - rl_point = 0; - #endif /* VI_MODE */ } } --- 3832,3837 ---- diff -rc readline.orig/readline.h readline/readline.h *** readline.orig/readline.h Tue Nov 14 15:07:51 1989 --- readline/readline.h Tue Nov 14 15:21:27 1989 *************** *** 43,49 **** rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (), rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (), rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (), ! rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete (); #endif /* VI_MODE */ /* Keyboard macro commands. */ --- 43,50 ---- rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (), rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (), rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (), ! rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete (), ! rl_vi_delete (), rl_vi_rubout (), rl_vi_newline_hook (), rl_vi_insert_hook (); #endif /* VI_MODE */ /* Keyboard macro commands. */ diff -rc readline.orig/vi_keymap.c readline/vi_keymap.c *** readline.orig/vi_keymap.c Tue Nov 14 15:07:52 1989 --- readline/vi_keymap.c Tue Nov 14 15:21:26 1989 *************** *** 128,134 **** { ISFUNC, rl_revert_line }, /* U */ { ISFUNC, (Function *)0x0 }, /* V */ { ISFUNC, rl_vi_next_word }, /* W */ ! { ISFUNC, rl_rubout }, /* X */ { ISFUNC, rl_vi_yank_to }, /* Y */ { ISFUNC, (Function *)0x0 }, /* Z */ --- 128,134 ---- { ISFUNC, rl_revert_line }, /* U */ { ISFUNC, (Function *)0x0 }, /* V */ { ISFUNC, rl_vi_next_word }, /* W */ ! { ISFUNC, rl_vi_rubout }, /* X */ { ISFUNC, rl_vi_yank_to }, /* Y */ { ISFUNC, (Function *)0x0 }, /* Z */ *************** *** 185,192 **** { ISFUNC, rl_insert }, /* Control-b */ { ISFUNC, rl_insert }, /* Control-c */ { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ ! { ISFUNC, rl_insert }, /* Control-e */ ! { ISFUNC, rl_insert }, /* Control-f */ { ISFUNC, rl_insert }, /* Control-g */ { ISFUNC, rl_insert }, /* Control-h */ { ISFUNC, rl_complete }, /* Control-i */ --- 185,192 ---- { ISFUNC, rl_insert }, /* Control-b */ { ISFUNC, rl_insert }, /* Control-c */ { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ ! { ISFUNC, rl_possible_completions }, /* Control-e */ ! { ISFUNC, rl_complete }, /* Control-f */ { ISFUNC, rl_insert }, /* Control-g */ { ISFUNC, rl_insert }, /* Control-h */ { ISFUNC, rl_complete }, /* Control-i */ *************** *** 204,210 **** { ISFUNC, rl_unix_line_discard }, /* Control-u */ { ISFUNC, rl_quoted_insert }, /* Control-v */ { ISFUNC, rl_unix_word_rubout }, /* Control-w */ ! { ISFUNC, rl_insert }, /* Control-x */ { ISFUNC, rl_yank }, /* Control-y */ { ISFUNC, rl_insert }, /* Control-z */ --- 204,210 ---- { ISFUNC, rl_unix_line_discard }, /* Control-u */ { ISFUNC, rl_quoted_insert }, /* Control-v */ { ISFUNC, rl_unix_word_rubout }, /* Control-w */ ! { ISFUNC, rl_vi_complete }, /* Control-x */ { ISFUNC, rl_yank }, /* Control-y */ { ISFUNC, rl_insert }, /* Control-z */ diff -rc readline.orig/vi_mode.c readline/vi_mode.c *** readline.orig/vi_mode.c Tue Nov 14 15:07:52 1989 --- readline/vi_mode.c Sun Nov 19 16:48:12 1989 *************** *** 1,5 **** /* vi_mode.c -- A vi emulation mode for Bash. ! Mostly written by Jeff Sparkes (jeff1@????). */ --- 1,5 ---- /* vi_mode.c -- A vi emulation mode for Bash. ! Mostly written by Jeff Sparkes (jeff1@garfield.mun.edu). */ *************** *** 16,21 **** --- 16,24 ---- /* Non-zero means enter insertion mode. */ static vi_doing_insert = 0; + /* To allow undo of input expansion. */ + static vi_just_expanded = 0; + /* *** UNCLEAN *** */ /* Command keys which do movement for xxx_to commands. */ static char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; *************** *** 162,173 **** --- 165,186 ---- rl_vi_complete (ignore, key) int ignore, key; { + if (vi_just_expanded) { + rl_do_undo (); + vi_just_expanded = 0; + } + if (keymap == vi_insertion_keymap) + rl_vi_insertion_mode (); if (!whitespace (the_line[rl_point])) { rl_vi_end_word (1, 'E'); rl_point++; } + rl_begin_undo_group (); + /* If this returned a status value, we could avoid changing modes. */ rl_complete_internal ('*'); + rl_end_undo_group (); + vi_just_expanded = 1; rl_vi_insertion_mode (); } *************** *** 355,371 **** keymap = vi_insertion_keymap; } rl_vi_movement_mode () { if (rl_point > 0) rl_backward (1); - - keymap = vi_movement_keymap; - if (vi_doing_insert) - { - rl_end_undo_group (); - vi_doing_insert = 0; - } } rl_vi_arg_digit (count, c) --- 368,387 ---- keymap = vi_insertion_keymap; } + rl_vi_end_insertion_mode () + { + if (vi_doing_insert) { + rl_end_undo_group (); + vi_doing_insert = 0; + } + } + rl_vi_movement_mode () { + rl_vi_end_insertion_mode (); + keymap = vi_movement_keymap; if (rl_point > 0) rl_backward (1); } rl_vi_arg_digit (count, c) *************** *** 426,462 **** } int ! rl_vi_domove () { int c, save; rl_mark = rl_point; c = rl_read_key (in_stream); ! if (!member (c, vi_motion)) ! { if (digit (c)) ! { ! save = rl_numeric_arg; ! rl_digit_loop1 (); ! rl_numeric_arg *= save; ! } else return (-1); ! } ! ! rl_dispatch (c, keymap); ! ! /* No change in position means the command failed. */ ! if (rl_mark == rl_point) ! return (-1); ! if ((c == 'w' || c == 'W') && rl_point < rl_end) ! rl_point--; ! if (rl_mark < rl_point) ! exchange (rl_point, rl_mark); return (0); } --- 442,488 ---- } int ! rl_vi_domove (invoked) ! int invoked; { + /* Don't increment rl_point after these chars. */ + static char *not_after = " hl^$wbWB"; int c, save; rl_mark = rl_point; c = rl_read_key (in_stream); ! if (c == invoked) { ! rl_mark = rl_end; ! rl_point = 0; ! } else { ! if (!member (c, vi_motion)) if (digit (c)) ! rl_digit_argument (0, c); else return (-1); ! else ! rl_dispatch (c, keymap); ! /* No change in position means the command failed. */ ! if (rl_mark == rl_point) ! return (-1); ! ! /* Fix word wierdness for change command. */ ! if (invoked == 'c' && (c == 'w' || c == 'W') && rl_point < rl_end) ! if (!whitespace (the_line[rl_point])) { ! rl_point--; ! while (whitespace (the_line[rl_point])) ! rl_point--; ! rl_point++; ! } ! if (rl_mark < rl_point && !member(c, not_after)) ! rl_point++; + if (rl_mark < rl_point) + exchange (rl_point, rl_mark); + } return (0); } *************** *** 548,565 **** rl_point = save; } rl_vi_delete (count) { ! if (rl_point >= rl_end - 1) ! { ! rl_delete (count); ! if (rl_point > 0) ! rl_backward (1); ! } ! else ! rl_delete (count); } - /* Turn the current line into a comment in shell history. A ksh function */ rl_vi_comment () { --- 574,599 ---- rl_point = save; } + /* Even single char deletes kill text. */ rl_vi_delete (count) { ! if ((rl_point +count) > rl_end - 1) { ! rl_kill_text (rl_point, rl_end); ! if (rl_point > 0) ! rl_backward (1); ! } else ! rl_kill_text (rl_point, rl_point + count); ! } ! ! rl_vi_rubout (count) ! { ! rl_point -= count; ! if (rl_point < 0) { ! count += rl_point; ! rl_point = 0; ! } ! rl_kill_text (rl_point, rl_point + count); } /* Turn the current line into a comment in shell history. A ksh function */ rl_vi_comment () { *************** *** 856,859 **** --- 890,909 ---- vi_replace_map[RETURN].function = rl_newline; vi_replace_map[NEWLINE].function = rl_newline; keymap = vi_replace_map; + } + + rl_vi_display_hook () + { + if (rl_editing_mode == vi_mode && keymap == vi_movement_keymap) + rl_vi_check (); + } + + rl_vi_insert_hook () + { + vi_just_expanded = 0; + } + + rl_vi_newline_hook () + { + rl_vi_end_insertion_mode (); } -- Jeff Sparkes jeff1@garfield.mun.edu || uunet!garfield!jeff1 Humans couldn't have invented golf without alien intervention--Kids in the Hall