home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / gdb-4.12.tar.gz / gdb-4.12.tar / gdb-4.12 / readline / vi_mode.c < prev   
C/C++ Source or Header  |  1994-02-03  |  24KB  |  1,217 lines

  1. /* vi_mode.c -- A vi emulation mode for Bash.
  2.    Derived from code written by Jeff Sparkes (jsparkes@bnr.ca).  */
  3.  
  4. /* Copyright (C) 1988, 1991 Free Software Foundation, Inc.
  5.  
  6.    This file is part of the GNU Readline Library (the Library), a set of
  7.    routines for providing Emacs style line input to programs that ask
  8.    for it.
  9.  
  10.    The Library is free software; you can redistribute it and/or modify
  11.    it under the terms of the GNU General Public License as published by
  12.    the Free Software Foundation; either version 2 of the License, or
  13.    (at your option) any later version.
  14.  
  15.    The Library is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.    GNU General Public License for more details.
  19.  
  20.    You should have received a copy of the GNU General Public License
  21.    along with this program; if not, write to the Free Software
  22.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  23.  
  24.  
  25. /* **************************************************************** */
  26. /*                                    */
  27. /*            VI Emulation Mode                */
  28. /*                                    */
  29. /* **************************************************************** */
  30. #if defined (VI_MODE)
  31.  
  32. /* Some standard library routines. */
  33. #include "sysdep.h"
  34. #include <stdio.h>
  35. #include "readline.h"
  36. #include "history.h"
  37.  
  38. #ifndef digit
  39. #define digit(c)  ((c) >= '0' && (c) <= '9')
  40. #endif
  41.  
  42. #ifndef isletter
  43. #define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
  44. #endif
  45.  
  46. #ifndef digit_value
  47. #define digit_value(c) ((c) - '0')
  48. #endif
  49.  
  50. #ifndef member
  51. #define member(c, s) ((c) ? index ((s), (c)) : 0)
  52. #endif
  53.  
  54. #ifndef isident
  55. #define isident(c) ((isletter(c) || digit(c) || c == '_'))
  56. #endif
  57.  
  58. #ifndef exchange
  59. #define exchange(x, y) {int temp = x; x = y; y = temp;}
  60. #endif
  61.  
  62. /* Variables imported from readline.c */
  63. extern int rl_point, rl_end, rl_mark, rl_done;
  64. extern FILE *rl_instream;
  65. extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
  66. extern Keymap keymap;
  67. extern char *rl_prompt;
  68. extern char *rl_line_buffer;
  69. extern int rl_arg_sign;
  70.  
  71. extern char *xmalloc (), *xrealloc ();
  72. extern void rl_extend_line_buffer ();
  73.  
  74. /* Last string searched for from `/' or `?'. */
  75. static char *vi_last_search = (char *)NULL;
  76. static int vi_histpos;
  77.  
  78. /* Non-zero means enter insertion mode. */
  79. int vi_doing_insert = 0;
  80.  
  81. /* String inserted into the line by rl_vi_comment (). */
  82. char *rl_vi_comment_begin = (char *)NULL;
  83.  
  84. /* *** UNCLEAN *** */
  85. /* Command keys which do movement for xxx_to commands. */
  86. static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
  87.  
  88. /* Keymap used for vi replace characters.  Created dynamically since
  89.    rarely used. */
  90. static Keymap vi_replace_map = (Keymap)NULL;
  91.  
  92. /* The number of characters inserted in the last replace operation. */
  93. static int vi_replace_count = 0;
  94.  
  95. /* Yank the nth arg from the previous line into this line at point. */
  96. rl_vi_yank_arg (count)
  97.      int count;
  98. {
  99.   /* Readline thinks that the first word on a line is the 0th, while vi
  100.      thinks the first word on a line is the 1st.  Compensate. */
  101.   if (rl_explicit_arg)
  102.     rl_yank_nth_arg (count - 1, 0);
  103.   else
  104.     rl_yank_nth_arg ('$', 0);
  105. }
  106.  
  107. /* With an argument, move back that many history lines, else move to the
  108.    beginning of history. */
  109. rl_vi_fetch_history (count, c)
  110.      int count, c;
  111. {
  112.   extern int rl_explicit_arg;
  113.   int current = where_history ();
  114.  
  115.   /* Giving an argument of n means we want the nth command in the history
  116.      file.  The command number is interpreted the same way that the bash
  117.      `history' command does it -- that is, giving an argument count of 450
  118.      to this command would get the command listed as number 450 in the
  119.      output of `history'. */
  120.   if (rl_explicit_arg)
  121.     {
  122.       int wanted = history_base + current - count;
  123.       if (wanted <= 0)
  124.         rl_beginning_of_history (0, 0);
  125.       else
  126.         rl_get_previous_history (wanted);
  127.     }
  128.   else
  129.     rl_beginning_of_history (count, 0);
  130. }
  131.  
  132. /* Search again for the last thing searched for. */
  133. rl_vi_search_again (ignore, key)
  134.      int ignore, key;
  135. {
  136.   switch (key)
  137.     {
  138.     case 'n':
  139.       rl_vi_dosearch (vi_last_search, -1);
  140.       break;
  141.  
  142.     case 'N':
  143.       rl_vi_dosearch (vi_last_search, 1);
  144.       break;
  145.     }
  146. }
  147.  
  148. /* Do a vi style search. */
  149. rl_vi_search (count, key)
  150.      int count, key;
  151. {
  152.   int dir, c, save_pos;
  153.   char *p;
  154.  
  155.   switch (key)
  156.     {
  157.     case '?':
  158.       dir = 1;
  159.       break;
  160.  
  161.     case '/':
  162.       dir = -1;
  163.       break;
  164.  
  165.     default:
  166.       ding ();
  167.       return;
  168.     }
  169.  
  170.   vi_histpos = where_history ();
  171.   maybe_save_line ();
  172.   save_pos = rl_point;
  173.  
  174.   /* Reuse the line input buffer to read the search string. */
  175.   rl_line_buffer[0] = 0;
  176.   rl_end = rl_point = 0;
  177.   p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0));
  178.  
  179.   sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
  180.  
  181.   rl_message (p, 0, 0);
  182.  
  183.   while (c = rl_read_key ())
  184.     {
  185.       switch (c)
  186.     {
  187.     case CTRL('H'):
  188.     case RUBOUT:
  189.       if (rl_point == 0)
  190.         {
  191.           maybe_unsave_line ();
  192.           rl_clear_message ();
  193.           rl_point = save_pos;
  194.           return;
  195.         }
  196.  
  197.     case CTRL('W'):
  198.     case CTRL('U'):
  199.       rl_dispatch (c, keymap);
  200.       break;
  201.  
  202.     case ESC:
  203.     case RETURN:
  204.     case NEWLINE:
  205.       goto dosearch;
  206.       break;
  207.  
  208.     case CTRL('C'):
  209.       maybe_unsave_line ();
  210.       rl_clear_message ();
  211.       rl_point = 0;
  212.       ding ();
  213.       return;
  214.  
  215.     default:
  216.       rl_insert (1, c);
  217.       break;
  218.     }
  219.       rl_redisplay ();
  220.     }
  221.  dosearch:
  222.   if (vi_last_search)
  223.     free (vi_last_search);
  224.  
  225.   vi_last_search = savestring (rl_line_buffer);
  226.   rl_vi_dosearch (rl_line_buffer, dir);
  227. }
  228.  
  229. /* Search for STRING in the history list.  DIR is < 0 for searching
  230.    backwards.  POS is an absolute index into the history list at
  231.    which point to begin searching.  If the first character of STRING
  232.    is `^', the string must match a prefix of a history line, otherwise
  233.    a full substring match is performed. */
  234. static int
  235. vi_history_search_pos (string, dir, pos)
  236.      char *string;
  237.      int dir, pos;
  238. {
  239.   int ret, old = where_history ();
  240.  
  241.   history_set_pos (pos);
  242.  
  243.   if (*string == '^')
  244.     ret = history_search_prefix (string + 1, dir);
  245.   else
  246.     ret = history_search (string, dir);
  247.     
  248.   if (ret == -1)
  249.     {
  250.       history_set_pos (old);
  251.       return (-1);
  252.     }
  253.  
  254.   ret = where_history ();
  255.   history_set_pos (old);
  256.   return ret;
  257. }
  258.  
  259. rl_vi_dosearch (string, dir)
  260.      char *string;
  261.      int dir;
  262. {
  263.   int old, save = vi_histpos;
  264.   HIST_ENTRY *h;
  265.  
  266.   if (string == 0 || *string == 0 || vi_histpos < 0)
  267.     {
  268.       ding ();
  269.       return;
  270.     }
  271.  
  272.   if ((save = vi_history_search_pos (string, dir, vi_histpos + dir)) == -1)
  273.     {
  274.       maybe_unsave_line ();
  275.       rl_clear_message ();
  276.       rl_point = 0;
  277.       ding ();
  278.       return;
  279.     }
  280.  
  281.   vi_histpos = save;
  282.  
  283.   old = where_history ();
  284.   history_set_pos (vi_histpos);
  285.   h = current_history ();
  286.   history_set_pos (old);
  287.  
  288.   {
  289.     int line_len = strlen (h->line);
  290.  
  291.     if (line_len >= rl_line_buffer_len)
  292.       rl_extend_line_buffer (line_len);
  293.     strcpy (rl_line_buffer, h->line);
  294.   }
  295.  
  296.   rl_undo_list = (UNDO_LIST *)h->data;
  297.   rl_end = strlen (rl_line_buffer);
  298.   rl_point = 0;
  299.   rl_clear_message ();
  300. }
  301.  
  302. /* Completion, from vi's point of view. */
  303. rl_vi_complete (ignore, key)
  304.      int ignore, key;
  305. {
  306.   if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
  307.     {
  308.       if (!whitespace (rl_line_buffer[rl_point + 1]))
  309.     rl_vi_end_word (1, 'E');
  310.       rl_point++;
  311.     }
  312.  
  313.   if (key == '*')
  314.     rl_complete_internal ('*');    /* Expansion and replacement. */
  315.   else if (key == '=')
  316.     rl_complete_internal ('?');    /* List possible completions. */
  317.   else if (key == '\\')
  318.     rl_complete_internal (TAB);    /* Standard Readline completion. */
  319.   else
  320.     rl_complete (0, key);
  321. }
  322.  
  323. /* Previous word in vi mode. */
  324. rl_vi_prev_word (count, key)
  325.      int count, key;
  326. {
  327.   if (count < 0)
  328.     {
  329.       rl_vi_next_word (-count, key);
  330.       return;
  331.     }
  332.  
  333.   if (rl_point == 0)
  334.     {
  335.       ding ();
  336.       return;
  337.     }
  338.  
  339.   if (uppercase_p (key))
  340.     rl_vi_bWord (count);
  341.   else
  342.     rl_vi_bword (count);
  343. }
  344.  
  345. /* Next word in vi mode. */
  346. rl_vi_next_word (count, key)
  347.      int count;
  348. {
  349.   if (count < 0)
  350.     {
  351.       rl_vi_prev_word (-count, key);
  352.       return;
  353.     }
  354.  
  355.   if (rl_point >= (rl_end - 1))
  356.     {
  357.       ding ();
  358.       return;
  359.     }
  360.  
  361.   if (uppercase_p (key))
  362.     rl_vi_fWord (count);
  363.   else
  364.     rl_vi_fword (count);
  365. }
  366.  
  367. /* Move to the end of the ?next? word. */
  368. rl_vi_end_word (count, key)
  369.      int count, key;
  370. {
  371.   if (count < 0)
  372.     {
  373.       ding ();
  374.       return;
  375.     }
  376.  
  377.   if (uppercase_p (key))
  378.     rl_vi_eWord (count);
  379.   else
  380.     rl_vi_eword (count);
  381. }
  382.  
  383. /* Move forward a word the way that 'W' does. */
  384. rl_vi_fWord (count)
  385.      int count;
  386. {
  387.   while (count-- && rl_point < (rl_end - 1))
  388.     {
  389.       /* Skip until whitespace. */
  390.       while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  391.     rl_point++;
  392.  
  393.       /* Now skip whitespace. */
  394.       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  395.     rl_point++;
  396.     }
  397. }
  398.  
  399. rl_vi_bWord (count)
  400.      int count;
  401. {
  402.   while (count-- && rl_point > 0)
  403.     {
  404.       /* If we are at the start of a word, move back to whitespace so
  405.      we will go back to the start of the previous word. */
  406.       if (!whitespace (rl_line_buffer[rl_point]) &&
  407.       whitespace (rl_line_buffer[rl_point - 1]))
  408.     rl_point--;
  409.  
  410.       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
  411.     rl_point--;
  412.  
  413.       if (rl_point > 0)
  414.     {
  415.       while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
  416.       rl_point++;
  417.     }
  418.     }
  419. }
  420.  
  421. rl_vi_eWord (count)
  422.      int count;
  423. {
  424.   while (count-- && rl_point < (rl_end - 1))
  425.     {
  426.       if (!whitespace (rl_line_buffer[rl_point]))
  427.     rl_point++;
  428.  
  429.       /* Move to the next non-whitespace character (to the start of the
  430.      next word). */
  431.       while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
  432.  
  433.       if (rl_point && rl_point < rl_end)
  434.     {
  435.       /* Skip whitespace. */
  436.       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
  437.         rl_point++;
  438.  
  439.       /* Skip until whitespace. */
  440.       while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
  441.         rl_point++;
  442.  
  443.       /* Move back to the last character of the word. */
  444.       rl_point--;
  445.     }
  446.     }
  447. }
  448.  
  449. rl_vi_fword (count)
  450.      int count;
  451. {
  452.   while (count-- && rl_point < (rl_end - 1))
  453.     {
  454.       /* Move to white space (really non-identifer). */
  455.       if (isident (rl_line_buffer[rl_point]))
  456.     {
  457.       while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
  458.         rl_point++;
  459.     }
  460.       else /* if (!whitespace (rl_line_buffer[rl_point])) */
  461.     {
  462.       while (!isident (rl_line_buffer[rl_point]) &&
  463.          !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  464.         rl_point++;
  465.     }
  466.  
  467.       /* Move past whitespace. */
  468.       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  469.     rl_point++;
  470.     }
  471. }
  472.  
  473. rl_vi_bword (count)
  474.      int count;
  475. {
  476.   while (count-- && rl_point > 0)
  477.     {
  478.       int last_is_ident;
  479.  
  480.       /* If we are at the start of a word, move back to whitespace
  481.      so we will go back to the start of the previous word. */
  482.       if (!whitespace (rl_line_buffer[rl_point]) &&
  483.       whitespace (rl_line_buffer[rl_point - 1]))
  484.     rl_point--;
  485.  
  486.       /* If this character and the previous character are `opposite', move
  487.      back so we don't get messed up by the rl_point++ down there in
  488.      the while loop.  Without this code, words like `l;' screw up the
  489.      function. */
  490.       last_is_ident = isident (rl_line_buffer[rl_point - 1]);
  491.       if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
  492.       (!isident (rl_line_buffer[rl_point]) && last_is_ident))
  493.     rl_point--;
  494.  
  495.       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
  496.     rl_point--;
  497.  
  498.       if (rl_point > 0)
  499.     {
  500.       if (isident (rl_line_buffer[rl_point]))
  501.         while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
  502.       else
  503.         while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
  504.            !whitespace (rl_line_buffer[rl_point]));
  505.       rl_point++;
  506.     }
  507.     }
  508. }
  509.  
  510. rl_vi_eword (count)
  511.      int count;
  512. {
  513.   while (count-- && rl_point < rl_end - 1)
  514.     {
  515.       if (!whitespace (rl_line_buffer[rl_point]))
  516.     rl_point++;
  517.  
  518.       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
  519.     rl_point++;
  520.  
  521.       if (rl_point < rl_end)
  522.     {
  523.       if (isident (rl_line_buffer[rl_point]))
  524.         while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
  525.       else
  526.         while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
  527.            && !whitespace (rl_line_buffer[rl_point]));
  528.     }
  529.       rl_point--;
  530.     }
  531. }
  532.  
  533. rl_vi_insert_beg ()
  534. {
  535.   rl_beg_of_line ();
  536.   rl_vi_insertion_mode ();
  537.   return 0;
  538. }
  539.  
  540. rl_vi_append_mode ()
  541. {
  542.   if (rl_point < rl_end)
  543.     rl_point += 1;
  544.   rl_vi_insertion_mode ();
  545.   return 0;
  546. }
  547.  
  548. rl_vi_append_eol ()
  549. {
  550.   rl_end_of_line ();
  551.   rl_vi_append_mode ();
  552.   return 0;
  553. }
  554.  
  555. /* What to do in the case of C-d. */
  556. rl_vi_eof_maybe (count, c)
  557.      int count, c;
  558. {
  559.   rl_newline (1, '\n');
  560. }
  561.  
  562. /* Insertion mode stuff. */
  563.  
  564. /* Switching from one mode to the other really just involves
  565.    switching keymaps. */
  566. rl_vi_insertion_mode ()
  567. {
  568.   keymap = vi_insertion_keymap;
  569. }
  570.  
  571. rl_vi_movement_mode ()
  572. {
  573.   if (rl_point > 0)
  574.     rl_backward (1);
  575.  
  576.   keymap = vi_movement_keymap;
  577.   vi_done_inserting ();
  578. }
  579.  
  580. vi_done_inserting ()
  581. {
  582.   if (vi_doing_insert)
  583.     {
  584.       rl_end_undo_group ();
  585.       vi_doing_insert = 0;
  586.     }
  587. }
  588.  
  589. rl_vi_arg_digit (count, c)
  590.      int count, c;
  591. {
  592.   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
  593.     rl_beg_of_line ();
  594.   else
  595.     rl_digit_argument (count, c);
  596. }
  597.  
  598. rl_vi_change_case (count, ignore)
  599.      int count, ignore;
  600. {
  601.   char c = 0;
  602.  
  603.   /* Don't try this on an empty line. */
  604.   if (rl_point >= rl_end)
  605.     return;
  606.  
  607.   while (count-- && rl_point < rl_end)
  608.     {
  609.       if (uppercase_p (rl_line_buffer[rl_point]))
  610.     c = to_lower (rl_line_buffer[rl_point]);
  611.       else if (lowercase_p (rl_line_buffer[rl_point]))
  612.     c = to_upper (rl_line_buffer[rl_point]);
  613.  
  614.       /* Vi is kind of strange here. */
  615.       if (c)
  616.     {
  617.       rl_begin_undo_group ();
  618.       rl_delete (1, c);
  619.       rl_insert (1, c);
  620.       rl_end_undo_group ();
  621.       rl_vi_check ();
  622.         }
  623.       else
  624.     rl_forward (1);
  625.     }
  626. }
  627.  
  628. rl_vi_put (count, key)
  629.      int count, key;
  630. {
  631.   if (!uppercase_p (key) && (rl_point + 1 <= rl_end))
  632.     rl_point++;
  633.  
  634.   rl_yank ();
  635.   rl_backward (1);
  636. }
  637.  
  638. rl_vi_check ()
  639. {
  640.   if (rl_point && rl_point == rl_end)
  641.     rl_point--;
  642. }
  643.  
  644. rl_vi_column (count)
  645. {
  646.   if (count > rl_end)
  647.     rl_end_of_line ();
  648.   else
  649.     rl_point = count - 1;
  650. }
  651.  
  652. int
  653. rl_vi_domove (key, nextkey)
  654.      int key, *nextkey;
  655. {
  656.   int c, save;
  657.   int old_end, added_blank;
  658.  
  659.   added_blank = 0;
  660.  
  661.   rl_mark = rl_point;
  662.   c = rl_read_key ();
  663.   *nextkey = c;
  664.  
  665.   if (!member (c, vi_motion))
  666.     {
  667.       if (digit (c))
  668.     {
  669.       save = rl_numeric_arg;
  670.       rl_numeric_arg = digit_value (c);
  671.       rl_digit_loop1 ();
  672.       rl_numeric_arg *= save;
  673.       c = rl_read_key ();    /* real command */
  674.       *nextkey = c;
  675.     }
  676.       else if ((key == 'd' && c == 'd') ||
  677.            (key == 'y' && c == 'y') ||
  678.            (key == 'c' && c == 'c'))
  679.     {
  680.       rl_mark = rl_end;
  681.       rl_beg_of_line ();
  682.       return (0);
  683.     }
  684.       else
  685.     return (-1);
  686.     }
  687.  
  688.   /* Append a blank character temporarily so that the motion routines
  689.      work right at the end of the line. */
  690.   old_end = rl_end;
  691.   rl_line_buffer[rl_end++] = ' ';    /* This looks pretty bogus to me??? */
  692.   rl_line_buffer[rl_end] = '\0';
  693.   added_blank++;
  694.  
  695.   rl_dispatch (c, keymap);
  696.  
  697.   /* Remove the blank that we added. */
  698.   rl_end = old_end;
  699.   rl_line_buffer[rl_end] = '\0';
  700.   if (rl_point > rl_end)
  701.     rl_point = rl_end - 1;
  702.  
  703.   /* No change in position means the command failed. */
  704.   if (rl_mark == rl_point)
  705.     return (-1);
  706.  
  707.   /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
  708.      word.  If we are not at the end of the line, and we are on a
  709.      non-whitespace character, move back one (presumably to whitespace). */
  710.   if ((c == 'w' || c == 'W') && (rl_point < rl_end) &&
  711.       !whitespace (rl_line_buffer[rl_point]))
  712.     rl_point--;
  713.  
  714.   /* If cw or cW, back up to the end of a word, so the behaviour of ce
  715.      or cE is the actual result.  Brute-force, no subtlety.  Do the same
  716.      thing for dw or dW. */
  717.   if (key == 'c' && (to_upper (c) == 'W'))
  718.     {
  719.       while (rl_point && whitespace (rl_line_buffer[rl_point]))
  720.     rl_point--;
  721.     }
  722.  
  723.   if (rl_mark < rl_point)
  724.     exchange (rl_point, rl_mark);
  725.  
  726.   return (0);
  727. }
  728.  
  729. /* A simplified loop for vi. Don't dispatch key at end.
  730.    Don't recognize minus sign? */
  731. rl_digit_loop1 ()
  732. {
  733.   int key, c;
  734.  
  735.   while (1)
  736.     {
  737.       rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
  738.       key = c = rl_read_key ();
  739.  
  740.       if (keymap[c].type == ISFUNC &&
  741.       keymap[c].function == rl_universal_argument)
  742.     {
  743.       rl_numeric_arg *= 4;
  744.       continue;
  745.     }
  746.  
  747.       c = UNMETA (c);
  748.       if (numeric (c))
  749.     {
  750.       if (rl_explicit_arg)
  751.         rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c);
  752.       else
  753.         rl_numeric_arg = digit_value (c);
  754.       rl_explicit_arg = 1;
  755.     }
  756.       else
  757.     {
  758.       rl_clear_message ();
  759.       rl_stuff_char (key);
  760.       break;
  761.     }
  762.     }
  763. }
  764.  
  765. rl_vi_delete_to (count, key)
  766.      int count, key;
  767. {
  768.   int c;
  769.  
  770.   if (uppercase_p (key))
  771.     rl_stuff_char ('$');
  772.  
  773.   if (rl_vi_domove (key, &c))
  774.     {
  775.       ding ();
  776.       return;
  777.     }
  778.  
  779.   if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end)
  780.     rl_mark++;
  781.  
  782.   rl_kill_text (rl_point, rl_mark);
  783. }
  784.  
  785. rl_vi_change_to (count, key)
  786.      int count, key;
  787. {
  788.   int c;
  789.  
  790.   if (uppercase_p (key))
  791.     rl_stuff_char ('$');
  792.  
  793.   if (rl_vi_domove (key, &c))
  794.     {
  795.       ding ();
  796.       return;
  797.     }
  798.  
  799.   if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end)
  800.     rl_mark++;
  801.  
  802.   rl_begin_undo_group ();
  803.   vi_doing_insert = 1;
  804.   rl_kill_text (rl_point, rl_mark);
  805.   rl_vi_insertion_mode ();
  806. }
  807.  
  808. rl_vi_yank_to (count, key)
  809.      int count, key;
  810. {
  811.   int c, save = rl_point;
  812.  
  813.   if (uppercase_p (key))
  814.     rl_stuff_char ('$');
  815.  
  816.   if (rl_vi_domove (key, &c))
  817.     {
  818.       ding ();
  819.       return;
  820.     }
  821.  
  822.   if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end)
  823.     rl_mark++;
  824.  
  825.   rl_begin_undo_group ();
  826.   rl_kill_text (rl_point, rl_mark);
  827.   rl_end_undo_group ();
  828.   rl_do_undo ();
  829.   rl_point = save;
  830. }
  831.  
  832. rl_vi_delete (count)
  833. {
  834.   int end;
  835.  
  836.   if (rl_end == 0)
  837.     {
  838.       ding ();
  839.       return;
  840.     }
  841.  
  842.   end = rl_point + count;
  843.  
  844.   if (end >= rl_end)
  845.     end = rl_end;
  846.  
  847.   rl_kill_text (rl_point, end);
  848.   
  849.   if (rl_point > 0 && rl_point == rl_end)
  850.     rl_backward (1);
  851. }
  852.  
  853. /* Turn the current line into a comment in shell history.
  854.    A K*rn shell style function. */
  855. rl_vi_comment ()
  856. {
  857.   rl_beg_of_line ();
  858.  
  859.   if (rl_vi_comment_begin != (char *)NULL)
  860.     rl_insert_text (rl_vi_comment_begin);
  861.   else
  862.     rl_insert_text (": ");    /* Default. */
  863.  
  864.   rl_redisplay ();
  865.   rl_newline (1, '\010');
  866. }
  867.  
  868. rl_vi_first_print ()
  869. {
  870.   rl_back_to_indent (0, 0);
  871. }
  872.  
  873. rl_back_to_indent (ignore1, ignore2)
  874.      int ignore1, ignore2;
  875. {
  876.   rl_beg_of_line ();
  877.   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
  878.     rl_point++;
  879. }
  880.  
  881. /* NOTE: it is necessary that opposite directions are inverses */
  882. #define    FTO     1        /* forward to */
  883. #define BTO    -1        /* backward to */
  884. #define FFIND     2        /* forward find */
  885. #define BFIND    -2        /* backward find */
  886.  
  887. rl_vi_char_search (count, key)
  888.      int count, key;
  889. {
  890.   static char target;
  891.   static int orig_dir, dir;
  892.   int pos;
  893.  
  894.   if (key == ';' || key == ',')
  895.     dir = (key == ';' ? orig_dir : -orig_dir);
  896.   else
  897.     {
  898.       target = rl_getc (rl_instream);
  899.  
  900.       switch (key)
  901.         {
  902.         case 't':
  903.           orig_dir = dir = FTO;
  904.           break;
  905.  
  906.         case 'T':
  907.           orig_dir = dir = BTO;
  908.           break;
  909.  
  910.         case 'f':
  911.           orig_dir = dir = FFIND;
  912.           break;
  913.  
  914.         case 'F':
  915.           orig_dir = dir = BFIND;
  916.           break;
  917.         }
  918.     }
  919.  
  920.   pos = rl_point;
  921.  
  922.   while (count--)
  923.     {
  924.       if (dir < 0)
  925.     {
  926.       if (pos == 0)
  927.         {
  928.           ding ();
  929.           return;
  930.         }
  931.  
  932.       pos--;
  933.       do
  934.         {
  935.           if (rl_line_buffer[pos] == target)
  936.         {
  937.           if (dir == BTO)
  938.             rl_point = pos + 1;
  939.           else
  940.             rl_point = pos;
  941.           break;
  942.         }
  943.         }
  944.       while (pos--);
  945.  
  946.       if (pos < 0)
  947.         {
  948.           ding ();
  949.           return;
  950.         }
  951.     }
  952.       else
  953.     {            /* dir > 0 */
  954.       if (pos >= rl_end)
  955.         {
  956.           ding ();
  957.           return;
  958.         }
  959.  
  960.       pos++;
  961.       do
  962.         {
  963.           if (rl_line_buffer[pos] == target)
  964.         {
  965.           if (dir == FTO)
  966.             rl_point = pos - 1;
  967.           else
  968.             rl_point = pos;
  969.           break;
  970.         }
  971.         }
  972.       while (++pos < rl_end);
  973.  
  974.       if (pos >= (rl_end - 1))
  975.         {
  976.           ding ();
  977.           return;
  978.         }
  979.     }
  980.     }
  981. }
  982.  
  983. /* Match brackets */
  984. rl_vi_match ()
  985. {
  986.   int count = 1, brack, pos;
  987.  
  988.   pos = rl_point;
  989.   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
  990.     {
  991.       while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
  992.          rl_point < rl_end - 1)
  993.     rl_forward (1);
  994.  
  995.       if (brack <= 0)
  996.     {
  997.       rl_point = pos;
  998.       ding ();
  999.       return;
  1000.     }
  1001.     }
  1002.  
  1003.   pos = rl_point;
  1004.  
  1005.   if (brack < 0)
  1006.     {
  1007.       while (count)
  1008.     {
  1009.       if (--pos >= 0)
  1010.         {
  1011.           int b = rl_vi_bracktype (rl_line_buffer[pos]);
  1012.           if (b == -brack)
  1013.         count--;
  1014.           else if (b == brack)
  1015.         count++;
  1016.         }
  1017.       else
  1018.         {
  1019.           ding ();
  1020.           return;
  1021.         }
  1022.     }
  1023.     }
  1024.   else
  1025.     {            /* brack > 0 */
  1026.       while (count)
  1027.     {
  1028.       if (++pos < rl_end)
  1029.         {
  1030.           int b = rl_vi_bracktype (rl_line_buffer[pos]);
  1031.           if (b == -brack)
  1032.         count--;
  1033.           else if (b == brack)
  1034.         count++;
  1035.         }
  1036.       else
  1037.         {
  1038.           ding ();
  1039.           return;
  1040.         }
  1041.     }
  1042.     }
  1043.   rl_point = pos;
  1044. }
  1045.  
  1046. int
  1047. rl_vi_bracktype (c)
  1048.      int c;
  1049. {
  1050.   switch (c)
  1051.     {
  1052.     case '(': return  1;
  1053.     case ')': return -1;
  1054.     case '[': return  2;
  1055.     case ']': return -2;
  1056.     case '{': return  3;
  1057.     case '}': return -3;
  1058.     default:  return  0;
  1059.     }
  1060. }
  1061.  
  1062. rl_vi_change_char (count, key)
  1063.      int count, key;
  1064. {
  1065.   int c;
  1066.  
  1067.   c = rl_getc (rl_instream);
  1068.  
  1069.   if (c == '\033' || c == CTRL ('C'))
  1070.     return;
  1071.  
  1072.   while (count-- && rl_point < rl_end)
  1073.     {
  1074.       rl_begin_undo_group ();
  1075.  
  1076.       rl_delete (1, c);
  1077.       rl_insert (1, c);
  1078.       if (count == 0)
  1079.     rl_backward (1);
  1080.  
  1081.       rl_end_undo_group ();
  1082.     }
  1083. }
  1084.  
  1085. rl_vi_subst (count, key)
  1086.      int count, key;
  1087. {
  1088.   rl_begin_undo_group ();
  1089.   vi_doing_insert = 1;
  1090.  
  1091.   if (uppercase_p (key))
  1092.     {
  1093.       rl_beg_of_line ();
  1094.       rl_kill_line (1);
  1095.     }
  1096.   else
  1097.     rl_delete (count, key);
  1098.  
  1099.   rl_end_undo_group ();
  1100.   rl_vi_insertion_mode ();
  1101. }
  1102.  
  1103. rl_vi_overstrike (count, key)
  1104.      int count, key;
  1105. {
  1106.   int i;
  1107.  
  1108.   if (vi_doing_insert == 0)
  1109.     {
  1110.       vi_doing_insert = 1;
  1111.       rl_begin_undo_group ();
  1112.     }
  1113.  
  1114.   for (i = 0; i < count; i++)
  1115.     {
  1116.       vi_replace_count++;
  1117.       rl_begin_undo_group ();
  1118.  
  1119.       if (rl_point < rl_end)
  1120.     {
  1121.       rl_delete (1, key);
  1122.       rl_insert (1, key);
  1123.     }
  1124.       else
  1125.     rl_insert (1, key);
  1126.  
  1127.       rl_end_undo_group ();
  1128.     }
  1129. }
  1130.  
  1131. rl_vi_overstrike_delete (count)
  1132.      int count;
  1133. {
  1134.   int i, s;
  1135.  
  1136.   for (i = 0; i < count; i++)
  1137.     {
  1138.       if (vi_replace_count == 0)
  1139.     {
  1140.       ding ();
  1141.       break;
  1142.     }
  1143.       s = rl_point;
  1144.  
  1145.       if (rl_do_undo ())
  1146.     vi_replace_count--;
  1147.  
  1148.       if (rl_point == s)
  1149.     rl_backward (1);
  1150.     }
  1151.  
  1152.   if (vi_replace_count == 0 && vi_doing_insert)
  1153.     {
  1154.       rl_end_undo_group ();
  1155.       rl_do_undo ();
  1156.       vi_doing_insert = 0;
  1157.     }
  1158. }
  1159.  
  1160. rl_vi_replace (count, key)
  1161.      int count, key;
  1162. {
  1163.   int i;
  1164.  
  1165.   vi_replace_count = 0;
  1166.  
  1167.   if (!vi_replace_map)
  1168.     {
  1169.       vi_replace_map = rl_make_bare_keymap ();
  1170.  
  1171.       for (i = ' '; i < 127; i++)
  1172.     vi_replace_map[i].function = rl_vi_overstrike;
  1173.  
  1174.       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
  1175.       vi_replace_map[ESC].function = rl_vi_movement_mode;
  1176.       vi_replace_map[RETURN].function = rl_newline;
  1177.       vi_replace_map[NEWLINE].function = rl_newline;
  1178.  
  1179.       /* If the normal vi insertion keymap has ^H bound to erase, do the
  1180.          same here.  Probably should remove the assignment to RUBOUT up
  1181.          there, but I don't think it will make a difference in real life. */
  1182.       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
  1183.       vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
  1184.     vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
  1185.  
  1186.     }
  1187.   keymap = vi_replace_map;
  1188. }
  1189.  
  1190. /*
  1191.  * Try to complete the word we are standing on or the word that ends with
  1192.  * the previous character. A space matches everything.
  1193.  * Word delimiters are space and ;.
  1194.  */
  1195. rl_vi_possible_completions()
  1196. {
  1197.   int save_pos = rl_point;
  1198.  
  1199.   if (!index (" ;", rl_line_buffer[rl_point]))
  1200.     {
  1201.       while (!index(" ;", rl_line_buffer[++rl_point]))
  1202.     ;
  1203.     }
  1204.   else if (rl_line_buffer[rl_point-1] == ';')
  1205.     {
  1206.       ding ();
  1207.       return (0);
  1208.     }
  1209.  
  1210.   rl_possible_completions ();
  1211.   rl_point = save_pos;
  1212.  
  1213.   return (0);
  1214. }
  1215.  
  1216. #endif /* VI_MODE */
  1217.