home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / CLISP / CLISPSRC.TAR / clisp-1995-01-01 / src / readline / vi_mode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-31  |  24.5 KB  |  1,271 lines

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