File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / vi_mode.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jul 30 08:16:45 2014 UTC (9 years, 11 months ago) by misho
Branches: readline, MAIN
CVS tags: v6_3p10_cross, v6_3p10, v6_3, p6, HEAD
readline 6.3

    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) 1987-2012 Free Software Foundation, Inc.
    5: 
    6:    This file is part of the GNU Readline Library (Readline), a library
    7:    for reading lines of text with interactive input and history editing.      
    8: 
    9:    Readline is free software: you can redistribute it and/or modify
   10:    it under the terms of the GNU General Public License as published by
   11:    the Free Software Foundation, either version 3 of the License, or
   12:    (at your option) any later version.
   13: 
   14:    Readline is distributed in the hope that it will be useful,
   15:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   16:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17:    GNU General Public License for more details.
   18: 
   19:    You should have received a copy of the GNU General Public License
   20:    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
   21: */
   22: 
   23: #define READLINE_LIBRARY
   24: 
   25: /* **************************************************************** */
   26: /*								    */
   27: /*			VI Emulation Mode			    */
   28: /*								    */
   29: /* **************************************************************** */
   30: #include "rlconf.h"
   31: 
   32: #if defined (VI_MODE)
   33: 
   34: #if defined (HAVE_CONFIG_H)
   35: #  include <config.h>
   36: #endif
   37: 
   38: #include <sys/types.h>
   39: 
   40: #if defined (HAVE_STDLIB_H)
   41: #  include <stdlib.h>
   42: #else
   43: #  include "ansi_stdlib.h"
   44: #endif /* HAVE_STDLIB_H */
   45: 
   46: #if defined (HAVE_UNISTD_H)
   47: #  include <unistd.h>
   48: #endif
   49: 
   50: #include <stdio.h>
   51: 
   52: /* Some standard library routines. */
   53: #include "rldefs.h"
   54: #include "rlmbutil.h"
   55: 
   56: #include "readline.h"
   57: #include "history.h"
   58: 
   59: #include "rlprivate.h"
   60: #include "xmalloc.h"
   61: 
   62: #ifndef member
   63: #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
   64: #endif
   65: 
   66: int _rl_vi_last_command = 'i';	/* default `.' puts you in insert mode */
   67: 
   68: _rl_vimotion_cxt *_rl_vimvcxt = 0;
   69: 
   70: /* Non-zero means enter insertion mode. */
   71: static int _rl_vi_doing_insert;
   72: 
   73: /* Command keys which do movement for xxx_to commands. */
   74: static const char * const vi_motion = " hl^$0ftFT;,%wbeWBE|`";
   75: 
   76: /* Keymap used for vi replace characters.  Created dynamically since
   77:    rarely used. */
   78: static Keymap vi_replace_map;
   79: 
   80: /* The number of characters inserted in the last replace operation. */
   81: static int vi_replace_count;
   82: 
   83: /* If non-zero, we have text inserted after a c[motion] command that put
   84:    us implicitly into insert mode.  Some people want this text to be
   85:    attached to the command so that it is `redoable' with `.'. */
   86: static int vi_continued_command;
   87: static char *vi_insert_buffer;
   88: static int vi_insert_buffer_size;
   89: 
   90: static int _rl_vi_last_repeat = 1;
   91: static int _rl_vi_last_arg_sign = 1;
   92: static int _rl_vi_last_motion;
   93: #if defined (HANDLE_MULTIBYTE)
   94: static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
   95: static int _rl_vi_last_search_mblen;
   96: #else
   97: static int _rl_vi_last_search_char;
   98: #endif
   99: static int _rl_vi_last_replacement;
  100: 
  101: static int _rl_vi_last_key_before_insert;
  102: 
  103: static int vi_redoing;
  104: 
  105: /* Text modification commands.  These are the `redoable' commands. */
  106: static const char * const vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
  107: 
  108: /* Arrays for the saved marks. */
  109: static int vi_mark_chars['z' - 'a' + 1];
  110: 
  111: static void _rl_vi_replace_insert PARAMS((int));
  112: static void _rl_vi_save_replace PARAMS((void));
  113: static void _rl_vi_stuff_insert PARAMS((int));
  114: static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
  115: 
  116: static void vi_save_insert_buffer PARAMS ((int, int));
  117: 
  118: static void _rl_vi_backup PARAMS((void));
  119: 
  120: static int _rl_vi_arg_dispatch PARAMS((int));
  121: static int rl_digit_loop1 PARAMS((void));
  122: 
  123: static int _rl_vi_set_mark PARAMS((void));
  124: static int _rl_vi_goto_mark PARAMS((void));
  125: 
  126: static void _rl_vi_append_forward PARAMS((int));
  127: 
  128: static int _rl_vi_callback_getchar PARAMS((char *, int));
  129: 
  130: #if defined (READLINE_CALLBACKS)
  131: static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *));
  132: static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *));
  133: static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *));
  134: static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *));
  135: #endif
  136: 
  137: static int rl_domove_read_callback PARAMS((_rl_vimotion_cxt *));
  138: static int rl_domove_motion_callback PARAMS((_rl_vimotion_cxt *));
  139: static int rl_vi_domove_getchar PARAMS((_rl_vimotion_cxt *));
  140: 
  141: static int vi_change_dispatch PARAMS((_rl_vimotion_cxt *));
  142: static int vi_delete_dispatch PARAMS((_rl_vimotion_cxt *));
  143: static int vi_yank_dispatch PARAMS((_rl_vimotion_cxt *));
  144: 
  145: static int vidomove_dispatch PARAMS((_rl_vimotion_cxt *));
  146: 
  147: void
  148: _rl_vi_initialize_line ()
  149: {
  150:   register int i, n;
  151: 
  152:   n = sizeof (vi_mark_chars) / sizeof (vi_mark_chars[0]);
  153:   for (i = 0; i < n; i++)
  154:     vi_mark_chars[i] = -1;
  155: 
  156:   RL_UNSETSTATE(RL_STATE_VICMDONCE);
  157: }
  158: 
  159: void
  160: _rl_vi_reset_last ()
  161: {
  162:   _rl_vi_last_command = 'i';
  163:   _rl_vi_last_repeat = 1;
  164:   _rl_vi_last_arg_sign = 1;
  165:   _rl_vi_last_motion = 0;
  166: }
  167: 
  168: void
  169: _rl_vi_set_last (key, repeat, sign)
  170:      int key, repeat, sign;
  171: {
  172:   _rl_vi_last_command = key;
  173:   _rl_vi_last_repeat = repeat;
  174:   _rl_vi_last_arg_sign = sign;
  175: }
  176: 
  177: /* A convenience function that calls _rl_vi_set_last to save the last command
  178:    information and enters insertion mode. */
  179: void
  180: rl_vi_start_inserting (key, repeat, sign)
  181:      int key, repeat, sign;
  182: {
  183:   _rl_vi_set_last (key, repeat, sign);
  184:   rl_vi_insertion_mode (1, key);
  185: }
  186: 
  187: /* Is the command C a VI mode text modification command? */
  188: int
  189: _rl_vi_textmod_command (c)
  190:      int c;
  191: {
  192:   return (member (c, vi_textmod));
  193: }
  194: 
  195: static void
  196: _rl_vi_replace_insert (count)
  197:      int count;
  198: {
  199:   int nchars;
  200: 
  201:   nchars = strlen (vi_insert_buffer);
  202: 
  203:   rl_begin_undo_group ();
  204:   while (count--)
  205:     /* nchars-1 to compensate for _rl_replace_text using `end+1' in call
  206:        to rl_delete_text */
  207:     _rl_replace_text (vi_insert_buffer, rl_point, rl_point+nchars-1);
  208:   rl_end_undo_group ();
  209: }
  210: 
  211: static void
  212: _rl_vi_stuff_insert (count)
  213:      int count;
  214: {
  215:   rl_begin_undo_group ();
  216:   while (count--)
  217:     rl_insert_text (vi_insert_buffer);
  218:   rl_end_undo_group ();
  219: }
  220: 
  221: /* Bound to `.'.  Called from command mode, so we know that we have to
  222:    redo a text modification command.  The default for _rl_vi_last_command
  223:    puts you back into insert mode. */
  224: int
  225: rl_vi_redo (count, c)
  226:      int count, c;
  227: {
  228:   int r;
  229: 
  230:   if (rl_explicit_arg == 0)
  231:     {
  232:       rl_numeric_arg = _rl_vi_last_repeat;
  233:       rl_arg_sign = _rl_vi_last_arg_sign;
  234:     }
  235: 
  236:   r = 0;
  237:   vi_redoing = 1;
  238:   /* If we're redoing an insert with `i', stuff in the inserted text
  239:      and do not go into insertion mode. */
  240:   if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
  241:     {
  242:       _rl_vi_stuff_insert (count);
  243:       /* And back up point over the last character inserted. */
  244:       if (rl_point > 0)
  245: 	_rl_vi_backup ();
  246:     }
  247:   else if (_rl_vi_last_command == 'R' && vi_insert_buffer && *vi_insert_buffer)
  248:     {
  249:       _rl_vi_replace_insert (count);
  250:       /* And back up point over the last character inserted. */
  251:       if (rl_point > 0)
  252: 	_rl_vi_backup ();
  253:     }
  254:   /* Ditto for redoing an insert with `I', but move to the beginning of the
  255:      line like the `I' command does. */
  256:   else if (_rl_vi_last_command == 'I' && vi_insert_buffer && *vi_insert_buffer)
  257:     {
  258:       rl_beg_of_line (1, 'I');
  259:       _rl_vi_stuff_insert (count);
  260:       if (rl_point > 0)
  261: 	_rl_vi_backup ();
  262:     }
  263:   /* Ditto for redoing an insert with `a', but move forward a character first
  264:      like the `a' command does. */
  265:   else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
  266:     {
  267:       _rl_vi_append_forward ('a');
  268:       _rl_vi_stuff_insert (count);
  269:       if (rl_point > 0)
  270: 	_rl_vi_backup ();
  271:     }
  272:   /* Ditto for redoing an insert with `A', but move to the end of the line
  273:      like the `A' command does. */
  274:   else if (_rl_vi_last_command == 'A' && vi_insert_buffer && *vi_insert_buffer)
  275:     {
  276:       rl_end_of_line (1, 'A');
  277:       _rl_vi_stuff_insert (count);
  278:       if (rl_point > 0)
  279: 	_rl_vi_backup ();
  280:     }
  281:   else
  282:     r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
  283:   vi_redoing = 0;
  284: 
  285:   return (r);
  286: }
  287: 
  288: /* A placeholder for further expansion. */
  289: int
  290: rl_vi_undo (count, key)
  291:      int count, key;
  292: {
  293:   return (rl_undo_command (count, key));
  294: }
  295:     
  296: /* Yank the nth arg from the previous line into this line at point. */
  297: int
  298: rl_vi_yank_arg (count, key)
  299:      int count, key;
  300: {
  301:   /* Readline thinks that the first word on a line is the 0th, while vi
  302:      thinks the first word on a line is the 1st.  Compensate. */
  303:   if (rl_explicit_arg)
  304:     rl_yank_nth_arg (count - 1, 0);
  305:   else
  306:     rl_yank_nth_arg ('$', 0);
  307: 
  308:   return (0);
  309: }
  310: 
  311: /* With an argument, move back that many history lines, else move to the
  312:    beginning of history. */
  313: int
  314: rl_vi_fetch_history (count, c)
  315:      int count, c;
  316: {
  317:   int wanted;
  318: 
  319:   /* Giving an argument of n means we want the nth command in the history
  320:      file.  The command number is interpreted the same way that the bash
  321:      `history' command does it -- that is, giving an argument count of 450
  322:      to this command would get the command listed as number 450 in the
  323:      output of `history'. */
  324:   if (rl_explicit_arg)
  325:     {
  326:       wanted = history_base + where_history () - count;
  327:       if (wanted <= 0)
  328:         rl_beginning_of_history (0, 0);
  329:       else
  330:         rl_get_previous_history (wanted, c);
  331:     }
  332:   else
  333:     rl_beginning_of_history (count, 0);
  334:   return (0);
  335: }
  336: 
  337: /* Search again for the last thing searched for. */
  338: int
  339: rl_vi_search_again (count, key)
  340:      int count, key;
  341: {
  342:   switch (key)
  343:     {
  344:     case 'n':
  345:       rl_noninc_reverse_search_again (count, key);
  346:       break;
  347: 
  348:     case 'N':
  349:       rl_noninc_forward_search_again (count, key);
  350:       break;
  351:     }
  352:   return (0);
  353: }
  354: 
  355: /* Do a vi style search. */
  356: int
  357: rl_vi_search (count, key)
  358:      int count, key;
  359: {
  360:   switch (key)
  361:     {
  362:     case '?':
  363:       _rl_free_saved_history_line ();
  364:       rl_noninc_forward_search (count, key);
  365:       break;
  366: 
  367:     case '/':
  368:       _rl_free_saved_history_line ();
  369:       rl_noninc_reverse_search (count, key);
  370:       break;
  371: 
  372:     default:
  373:       rl_ding ();
  374:       break;
  375:     }
  376:   return (0);
  377: }
  378: 
  379: /* Completion, from vi's point of view. */
  380: int
  381: rl_vi_complete (ignore, key)
  382:      int ignore, key;
  383: {
  384:   if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
  385:     {
  386:       if (!whitespace (rl_line_buffer[rl_point + 1]))
  387: 	rl_vi_end_word (1, 'E');
  388:       rl_point++;
  389:     }
  390: 
  391:   if (key == '*')
  392:     rl_complete_internal ('*');	/* Expansion and replacement. */
  393:   else if (key == '=')
  394:     rl_complete_internal ('?');	/* List possible completions. */
  395:   else if (key == '\\')
  396:     rl_complete_internal (TAB);	/* Standard Readline completion. */
  397:   else
  398:     rl_complete (0, key);
  399: 
  400:   if (key == '*' || key == '\\')
  401:     rl_vi_start_inserting (key, 1, rl_arg_sign);
  402: 
  403:   return (0);
  404: }
  405: 
  406: /* Tilde expansion for vi mode. */
  407: int
  408: rl_vi_tilde_expand (ignore, key)
  409:      int ignore, key;
  410: {
  411:   rl_tilde_expand (0, key);
  412:   rl_vi_start_inserting (key, 1, rl_arg_sign);
  413:   return (0);
  414: }
  415: 
  416: /* Previous word in vi mode. */
  417: int
  418: rl_vi_prev_word (count, key)
  419:      int count, key;
  420: {
  421:   if (count < 0)
  422:     return (rl_vi_next_word (-count, key));
  423: 
  424:   if (rl_point == 0)
  425:     {
  426:       rl_ding ();
  427:       return (0);
  428:     }
  429: 
  430:   if (_rl_uppercase_p (key))
  431:     rl_vi_bWord (count, key);
  432:   else
  433:     rl_vi_bword (count, key);
  434: 
  435:   return (0);
  436: }
  437: 
  438: /* Next word in vi mode. */
  439: int
  440: rl_vi_next_word (count, key)
  441:      int count, key;
  442: {
  443:   if (count < 0)
  444:     return (rl_vi_prev_word (-count, key));
  445: 
  446:   if (rl_point >= (rl_end - 1))
  447:     {
  448:       rl_ding ();
  449:       return (0);
  450:     }
  451: 
  452:   if (_rl_uppercase_p (key))
  453:     rl_vi_fWord (count, key);
  454:   else
  455:     rl_vi_fword (count, key);
  456:   return (0);
  457: }
  458: 
  459: /* Move to the end of the ?next? word. */
  460: int
  461: rl_vi_end_word (count, key)
  462:      int count, key;
  463: {
  464:   if (count < 0)
  465:     {
  466:       rl_ding ();
  467:       return -1;
  468:     }
  469: 
  470:   if (_rl_uppercase_p (key))
  471:     rl_vi_eWord (count, key);
  472:   else
  473:     rl_vi_eword (count, key);
  474:   return (0);
  475: }
  476: 
  477: /* Move forward a word the way that 'W' does. */
  478: int
  479: rl_vi_fWord (count, ignore)
  480:      int count, ignore;
  481: {
  482:   while (count-- && rl_point < (rl_end - 1))
  483:     {
  484:       /* Skip until whitespace. */
  485:       while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  486: 	rl_point++;
  487: 
  488:       /* Now skip whitespace. */
  489:       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  490: 	rl_point++;
  491:     }
  492:   return (0);
  493: }
  494: 
  495: int
  496: rl_vi_bWord (count, ignore)
  497:      int count, ignore;
  498: {
  499:   while (count-- && rl_point > 0)
  500:     {
  501:       /* If we are at the start of a word, move back to whitespace so
  502: 	 we will go back to the start of the previous word. */
  503:       if (!whitespace (rl_line_buffer[rl_point]) &&
  504: 	  whitespace (rl_line_buffer[rl_point - 1]))
  505: 	rl_point--;
  506: 
  507:       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
  508: 	rl_point--;
  509: 
  510:       if (rl_point > 0)
  511: 	{
  512: 	  while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
  513: 	  rl_point++;
  514: 	}
  515:     }
  516:   return (0);
  517: }
  518: 
  519: int
  520: rl_vi_eWord (count, ignore)
  521:      int count, ignore;
  522: {
  523:   while (count-- && rl_point < (rl_end - 1))
  524:     {
  525:       if (!whitespace (rl_line_buffer[rl_point]))
  526: 	rl_point++;
  527: 
  528:       /* Move to the next non-whitespace character (to the start of the
  529: 	 next word). */
  530:       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
  531: 	rl_point++;
  532: 
  533:       if (rl_point && rl_point < rl_end)
  534: 	{
  535: 	  /* Skip whitespace. */
  536: 	  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
  537: 	    rl_point++;
  538: 
  539: 	  /* Skip until whitespace. */
  540: 	  while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
  541: 	    rl_point++;
  542: 
  543: 	  /* Move back to the last character of the word. */
  544: 	  rl_point--;
  545: 	}
  546:     }
  547:   return (0);
  548: }
  549: 
  550: int
  551: rl_vi_fword (count, ignore)
  552:      int count, ignore;
  553: {
  554:   while (count-- && rl_point < (rl_end - 1))
  555:     {
  556:       /* Move to white space (really non-identifer). */
  557:       if (_rl_isident (rl_line_buffer[rl_point]))
  558: 	{
  559: 	  while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
  560: 	    rl_point++;
  561: 	}
  562:       else /* if (!whitespace (rl_line_buffer[rl_point])) */
  563: 	{
  564: 	  while (!_rl_isident (rl_line_buffer[rl_point]) &&
  565: 		 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  566: 	    rl_point++;
  567: 	}
  568: 
  569:       /* Move past whitespace. */
  570:       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  571: 	rl_point++;
  572:     }
  573:   return (0);
  574: }
  575: 
  576: int
  577: rl_vi_bword (count, ignore)
  578:      int count, ignore;
  579: {
  580:   while (count-- && rl_point > 0)
  581:     {
  582:       int last_is_ident;
  583: 
  584:       /* If we are at the start of a word, move back to whitespace
  585: 	 so we will go back to the start of the previous word. */
  586:       if (!whitespace (rl_line_buffer[rl_point]) &&
  587: 	  whitespace (rl_line_buffer[rl_point - 1]))
  588: 	rl_point--;
  589: 
  590:       /* If this character and the previous character are `opposite', move
  591: 	 back so we don't get messed up by the rl_point++ down there in
  592: 	 the while loop.  Without this code, words like `l;' screw up the
  593: 	 function. */
  594:       last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]);
  595:       if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
  596: 	  (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident))
  597: 	rl_point--;
  598: 
  599:       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
  600: 	rl_point--;
  601: 
  602:       if (rl_point > 0)
  603: 	{
  604: 	  if (_rl_isident (rl_line_buffer[rl_point]))
  605: 	    while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point]));
  606: 	  else
  607: 	    while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
  608: 		   !whitespace (rl_line_buffer[rl_point]));
  609: 	  rl_point++;
  610: 	}
  611:     }
  612:   return (0);
  613: }
  614: 
  615: int
  616: rl_vi_eword (count, ignore)
  617:      int count, ignore;
  618: {
  619:   while (count-- && rl_point < rl_end - 1)
  620:     {
  621:       if (!whitespace (rl_line_buffer[rl_point]))
  622: 	rl_point++;
  623: 
  624:       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
  625: 	rl_point++;
  626: 
  627:       if (rl_point < rl_end)
  628: 	{
  629: 	  if (_rl_isident (rl_line_buffer[rl_point]))
  630: 	    while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
  631: 	  else
  632: 	    while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
  633: 		   && !whitespace (rl_line_buffer[rl_point]));
  634: 	}
  635:       rl_point--;
  636:     }
  637:   return (0);
  638: }
  639: 
  640: int
  641: rl_vi_insert_beg (count, key)
  642:      int count, key;
  643: {
  644:   rl_beg_of_line (1, key);
  645:   rl_vi_insert_mode (1, key);
  646:   return (0);
  647: }
  648: 
  649: static void
  650: _rl_vi_append_forward (key)
  651:      int key;
  652: {
  653:   int point;
  654: 
  655:   if (rl_point < rl_end)
  656:     {
  657:       if (MB_CUR_MAX == 1 || rl_byte_oriented)
  658: 	rl_point++;
  659:       else
  660: 	{
  661: 	  point = rl_point;
  662: #if 0
  663: 	  rl_forward_char (1, key);
  664: #else
  665: 	  rl_point = _rl_forward_char_internal (1);
  666: #endif
  667: 	  if (point == rl_point)
  668: 	    rl_point = rl_end;
  669: 	}
  670:     }
  671: }
  672: 
  673: int
  674: rl_vi_append_mode (count, key)
  675:      int count, key;
  676: {
  677:   _rl_vi_append_forward (key);
  678:   rl_vi_start_inserting (key, 1, rl_arg_sign);
  679:   return (0);
  680: }
  681: 
  682: int
  683: rl_vi_append_eol (count, key)
  684:      int count, key;
  685: {
  686:   rl_end_of_line (1, key);
  687:   rl_vi_append_mode (1, key);
  688:   return (0);
  689: }
  690: 
  691: /* What to do in the case of C-d. */
  692: int
  693: rl_vi_eof_maybe (count, c)
  694:      int count, c;
  695: {
  696:   return (rl_newline (1, '\n'));
  697: }
  698: 
  699: /* Insertion mode stuff. */
  700: 
  701: /* Switching from one mode to the other really just involves
  702:    switching keymaps. */
  703: int
  704: rl_vi_insertion_mode (count, key)
  705:      int count, key;
  706: {
  707:   _rl_keymap = vi_insertion_keymap;
  708:   _rl_vi_last_key_before_insert = key;
  709:   if (_rl_show_mode_in_prompt)
  710:     _rl_reset_prompt ();
  711:   return (0);
  712: }
  713: 
  714: int
  715: rl_vi_insert_mode (count, key)
  716:      int count, key;
  717: {
  718:   rl_vi_start_inserting (key, 1, rl_arg_sign);
  719:   return (0);
  720: }
  721: 
  722: static void
  723: vi_save_insert_buffer (start, len)
  724:      int start, len;
  725: {
  726:   /* Same code as _rl_vi_save_insert below */
  727:   if (len >= vi_insert_buffer_size)
  728:     {
  729:       vi_insert_buffer_size += (len + 32) - (len % 32);
  730:       vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
  731:     }
  732:   strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
  733:   vi_insert_buffer[len-1] = '\0';
  734: }
  735: 
  736: static void
  737: _rl_vi_save_replace ()
  738: {
  739:   int len, start, end;
  740:   UNDO_LIST *up;
  741: 
  742:   up = rl_undo_list;
  743:   if (up == 0 || up->what != UNDO_END || vi_replace_count <= 0)
  744:     {
  745:       if (vi_insert_buffer_size >= 1)
  746: 	vi_insert_buffer[0] = '\0';
  747:       return;
  748:     }
  749:   /* Let's try it the quick and easy way for now.  This should essentially
  750:      accommodate every UNDO_INSERT and save the inserted text to
  751:      vi_insert_buffer */
  752:   end = rl_point;
  753:   start = end - vi_replace_count + 1;
  754:   len = vi_replace_count + 1;
  755: 
  756:   vi_save_insert_buffer (start, len);  
  757: }
  758: 
  759: static void
  760: _rl_vi_save_insert (up)
  761:       UNDO_LIST *up;
  762: {
  763:   int len, start, end;
  764: 
  765:   if (up == 0 || up->what != UNDO_INSERT)
  766:     {
  767:       if (vi_insert_buffer_size >= 1)
  768: 	vi_insert_buffer[0] = '\0';
  769:       return;
  770:     }
  771: 
  772:   start = up->start;
  773:   end = up->end;
  774:   len = end - start + 1;
  775: 
  776:   vi_save_insert_buffer (start, len);
  777: }
  778:     
  779: void
  780: _rl_vi_done_inserting ()
  781: {
  782:   if (_rl_vi_doing_insert)
  783:     {
  784:       /* The `C', `s', and `S' commands set this. */
  785:       rl_end_undo_group ();
  786:       /* Now, the text between rl_undo_list->next->start and
  787: 	 rl_undo_list->next->end is what was inserted while in insert
  788: 	 mode.  It gets copied to VI_INSERT_BUFFER because it depends
  789: 	 on absolute indices into the line which may change (though they
  790: 	 probably will not). */
  791:       _rl_vi_doing_insert = 0;
  792:       if (_rl_vi_last_key_before_insert == 'R')
  793: 	_rl_vi_save_replace ();		/* Half the battle */
  794:       else
  795: 	_rl_vi_save_insert (rl_undo_list->next);
  796:       vi_continued_command = 1;
  797:     }
  798:   else
  799:     {
  800:       if (rl_undo_list && (_rl_vi_last_key_before_insert == 'i' ||
  801: 			   _rl_vi_last_key_before_insert == 'a' ||
  802: 			   _rl_vi_last_key_before_insert == 'I' ||
  803: 			   _rl_vi_last_key_before_insert == 'A'))
  804: 	_rl_vi_save_insert (rl_undo_list);
  805:       /* XXX - Other keys probably need to be checked. */
  806:       else if (_rl_vi_last_key_before_insert == 'C')
  807: 	rl_end_undo_group ();
  808:       while (_rl_undo_group_level > 0)
  809: 	rl_end_undo_group ();
  810:       vi_continued_command = 0;
  811:     }
  812: }
  813: 
  814: int
  815: rl_vi_movement_mode (count, key)
  816:      int count, key;
  817: {
  818:   if (rl_point > 0)
  819:     rl_backward_char (1, key);
  820: 
  821:   _rl_keymap = vi_movement_keymap;
  822:   _rl_vi_done_inserting ();
  823: 
  824:   /* This is how POSIX.2 says `U' should behave -- everything up until the
  825:      first time you go into command mode should not be undone. */
  826:   if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0)
  827:     rl_free_undo_list ();
  828: 
  829:   if (_rl_show_mode_in_prompt)
  830:     _rl_reset_prompt ();
  831: 
  832:   RL_SETSTATE (RL_STATE_VICMDONCE);
  833:   return (0);
  834: }
  835: 
  836: int
  837: rl_vi_arg_digit (count, c)
  838:      int count, c;
  839: {
  840:   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
  841:     return (rl_beg_of_line (1, c));
  842:   else
  843:     return (rl_digit_argument (count, c));
  844: }
  845: 
  846: /* Change the case of the next COUNT characters. */
  847: #if defined (HANDLE_MULTIBYTE)
  848: static int
  849: _rl_vi_change_mbchar_case (count)
  850:      int count;
  851: {
  852:   wchar_t wc;
  853:   char mb[MB_LEN_MAX+1];
  854:   int mlen, p;
  855:   size_t m;
  856:   mbstate_t ps;
  857: 
  858:   memset (&ps, 0, sizeof (mbstate_t));
  859:   if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
  860:     count--;
  861:   while (count-- && rl_point < rl_end)
  862:     {
  863:       m = mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
  864:       if (MB_INVALIDCH (m))
  865: 	wc = (wchar_t)rl_line_buffer[rl_point];
  866:       else if (MB_NULLWCH (m))
  867: 	wc = L'\0';
  868:       if (iswupper (wc))
  869: 	wc = towlower (wc);
  870:       else if (iswlower (wc))
  871: 	wc = towupper (wc);
  872:       else
  873: 	{
  874: 	  /* Just skip over chars neither upper nor lower case */
  875: 	  rl_forward_char (1, 0);
  876: 	  continue;
  877: 	}
  878: 
  879:       /* Vi is kind of strange here. */
  880:       if (wc)
  881: 	{
  882: 	  p = rl_point;
  883: 	  mlen = wcrtomb (mb, wc, &ps);
  884: 	  if (mlen >= 0)
  885: 	    mb[mlen] = '\0';
  886: 	  rl_begin_undo_group ();
  887: 	  rl_vi_delete (1, 0);
  888: 	  if (rl_point < p)	/* Did we retreat at EOL? */
  889: 	    rl_point++;	/* XXX - should we advance more than 1 for mbchar? */
  890: 	  rl_insert_text (mb);
  891: 	  rl_end_undo_group ();
  892: 	  rl_vi_check ();
  893: 	}
  894:       else
  895: 	rl_forward_char (1, 0);
  896:     }
  897: 
  898:   return 0;
  899: }
  900: #endif
  901: 
  902: int
  903: rl_vi_change_case (count, ignore)
  904:      int count, ignore;
  905: {
  906:   int c, p;
  907: 
  908:   /* Don't try this on an empty line. */
  909:   if (rl_point >= rl_end)
  910:     return (0);
  911: 
  912:   c = 0;
  913: #if defined (HANDLE_MULTIBYTE)
  914:   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  915:     return (_rl_vi_change_mbchar_case (count));
  916: #endif
  917: 
  918:   while (count-- && rl_point < rl_end)
  919:     {
  920:       if (_rl_uppercase_p (rl_line_buffer[rl_point]))
  921: 	c = _rl_to_lower (rl_line_buffer[rl_point]);
  922:       else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
  923: 	c = _rl_to_upper (rl_line_buffer[rl_point]);
  924:       else
  925: 	{
  926: 	  /* Just skip over characters neither upper nor lower case. */
  927: 	  rl_forward_char (1, c);
  928: 	  continue;
  929: 	}
  930: 
  931:       /* Vi is kind of strange here. */
  932:       if (c)
  933: 	{
  934: 	  p = rl_point;
  935: 	  rl_begin_undo_group ();
  936: 	  rl_vi_delete (1, c);
  937: 	  if (rl_point < p)	/* Did we retreat at EOL? */
  938: 	    rl_point++;
  939: 	  _rl_insert_char (1, c);
  940: 	  rl_end_undo_group ();
  941: 	  rl_vi_check ();
  942: 	}
  943:       else
  944: 	rl_forward_char (1, c);
  945:     }
  946:   return (0);
  947: }
  948: 
  949: int
  950: rl_vi_put (count, key)
  951:      int count, key;
  952: {
  953:   if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
  954:     rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
  955: 
  956:   while (count--)
  957:     rl_yank (1, key);
  958: 
  959:   rl_backward_char (1, key);
  960:   return (0);
  961: }
  962: 
  963: static void
  964: _rl_vi_backup ()
  965: {
  966:   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  967:     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
  968:   else
  969:     rl_point--;
  970: }
  971: 
  972: int
  973: rl_vi_check ()
  974: {
  975:   if (rl_point && rl_point == rl_end)
  976:     {
  977:       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  978: 	rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
  979:       else
  980: 	rl_point--;
  981:     }
  982:   return (0);
  983: }
  984: 
  985: int
  986: rl_vi_column (count, key)
  987:      int count, key;
  988: {
  989:   if (count > rl_end)
  990:     rl_end_of_line (1, key);
  991:   else
  992:     rl_point = count - 1;
  993:   return (0);
  994: }
  995: 
  996: /* Process C as part of the current numeric argument.  Return -1 if the
  997:    argument should be aborted, 0 if we should not read any more chars, and
  998:    1 if we should continue to read chars. */
  999: static int
 1000: _rl_vi_arg_dispatch (c)
 1001:      int c;
 1002: {
 1003:   int key;
 1004: 
 1005:   key = c;
 1006:   if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
 1007:     {
 1008:       rl_numeric_arg *= 4;
 1009:       return 1;
 1010:     }
 1011: 
 1012:   c = UNMETA (c);
 1013: 
 1014:   if (_rl_digit_p (c))
 1015:     {
 1016:       if (rl_explicit_arg)
 1017: 	rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
 1018:       else
 1019: 	rl_numeric_arg = _rl_digit_value (c);
 1020:       rl_explicit_arg = 1;
 1021:       return 1;		/* keep going */
 1022:     }
 1023:   else
 1024:     {
 1025:       rl_clear_message ();
 1026:       rl_stuff_char (key);
 1027:       return 0;		/* done */
 1028:     }
 1029: }
 1030: 
 1031: /* A simplified loop for vi. Don't dispatch key at end.
 1032:    Don't recognize minus sign?
 1033:    Should this do rl_save_prompt/rl_restore_prompt? */
 1034: static int
 1035: rl_digit_loop1 ()
 1036: {
 1037:   int c, r;
 1038: 
 1039:   while (1)
 1040:     {
 1041:       if (_rl_arg_overflow ())
 1042: 	return 1;
 1043: 
 1044:       c = _rl_arg_getchar ();
 1045: 
 1046:       r = _rl_vi_arg_dispatch (c);
 1047:       if (r <= 0)
 1048: 	break;
 1049:     }
 1050: 
 1051:   RL_UNSETSTATE(RL_STATE_NUMERICARG);
 1052:   return (0);
 1053: }
 1054: 
 1055: static void
 1056: _rl_mvcxt_init (m, op, key)
 1057:      _rl_vimotion_cxt *m;
 1058:      int op, key;
 1059: {
 1060:   m->op = op;
 1061:   m->state = m->flags = 0;
 1062:   m->ncxt = 0;
 1063:   m->numeric_arg = -1;
 1064:   m->start = rl_point;
 1065:   m->end = rl_end;
 1066:   m->key = key;
 1067:   m->motion = -1;
 1068: }
 1069: 
 1070: static _rl_vimotion_cxt *
 1071: _rl_mvcxt_alloc (op, key)
 1072:      int op, key;
 1073: {
 1074:   _rl_vimotion_cxt *m;
 1075: 
 1076:   m = xmalloc (sizeof (_rl_vimotion_cxt));
 1077:   _rl_mvcxt_init (m, op, key);
 1078:   return m;
 1079: }
 1080: 
 1081: static void
 1082: _rl_mvcxt_dispose (m)
 1083:      _rl_vimotion_cxt *m;
 1084: {
 1085:   xfree (m);
 1086: }
 1087: 
 1088: static int
 1089: rl_domove_motion_callback (m)
 1090:      _rl_vimotion_cxt *m;
 1091: {
 1092:   int c, save, r;
 1093:   int old_end;
 1094: 
 1095:   _rl_vi_last_motion = c = m->motion;
 1096: 
 1097:   /* Append a blank character temporarily so that the motion routines
 1098:      work right at the end of the line. */
 1099:   old_end = rl_end;
 1100:   rl_line_buffer[rl_end++] = ' ';
 1101:   rl_line_buffer[rl_end] = '\0';
 1102: 
 1103:   _rl_dispatch (c, _rl_keymap);
 1104: 
 1105:   /* Remove the blank that we added. */
 1106:   rl_end = old_end;
 1107:   rl_line_buffer[rl_end] = '\0';
 1108:   if (rl_point > rl_end)
 1109:     rl_point = rl_end;
 1110: 
 1111:   /* No change in position means the command failed. */
 1112:   if (rl_mark == rl_point)
 1113:     return (-1);
 1114: 
 1115:   /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
 1116:      word.  If we are not at the end of the line, and we are on a
 1117:      non-whitespace character, move back one (presumably to whitespace). */
 1118:   if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
 1119:       !whitespace (rl_line_buffer[rl_point]))
 1120:     rl_point--;
 1121: 
 1122:   /* If cw or cW, back up to the end of a word, so the behaviour of ce
 1123:      or cE is the actual result.  Brute-force, no subtlety. */
 1124:   if (m->key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
 1125:     {
 1126:       /* Don't move farther back than where we started. */
 1127:       while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
 1128: 	rl_point--;
 1129: 
 1130:       /* Posix.2 says that if cw or cW moves the cursor towards the end of
 1131: 	 the line, the character under the cursor should be deleted. */
 1132:       if (rl_point == rl_mark)
 1133: 	rl_point++;
 1134:       else
 1135: 	{
 1136: 	  /* Move past the end of the word so that the kill doesn't
 1137: 	     remove the last letter of the previous word.  Only do this
 1138: 	     if we are not at the end of the line. */
 1139: 	  if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
 1140: 	    rl_point++;
 1141: 	}
 1142:     }
 1143: 
 1144:   if (rl_mark < rl_point)
 1145:     SWAP (rl_point, rl_mark);
 1146: 
 1147: #if defined (READLINE_CALLBACKS)
 1148:   if (RL_ISSTATE (RL_STATE_CALLBACK))
 1149:     (*rl_redisplay_function)();		/* make sure motion is displayed */
 1150: #endif
 1151: 
 1152:   r = vidomove_dispatch (m);
 1153: 
 1154:   return (r);
 1155: }
 1156: 
 1157: #define RL_VIMOVENUMARG()	(RL_ISSTATE (RL_STATE_VIMOTION) && RL_ISSTATE (RL_STATE_NUMERICARG))
 1158: 
 1159: static int
 1160: rl_domove_read_callback (m)
 1161:      _rl_vimotion_cxt *m;
 1162: {
 1163:   int c, save;
 1164: 
 1165:   c = m->motion;
 1166: 
 1167:   if (member (c, vi_motion))
 1168:     {
 1169: #if defined (READLINE_CALLBACKS)
 1170:       /* If we just read a vi-mode motion command numeric argument, turn off
 1171: 	 the `reading numeric arg' state */
 1172:       if (RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
 1173: 	RL_UNSETSTATE (RL_STATE_NUMERICARG);
 1174: #endif
 1175:       /* Should do everything, including turning off RL_STATE_VIMOTION */
 1176:       return (rl_domove_motion_callback (m));
 1177:     }
 1178:   else if (m->key == c && (m->key == 'd' || m->key == 'y' || m->key == 'c'))
 1179:     {
 1180:       rl_mark = rl_end;
 1181:       rl_beg_of_line (1, c);
 1182:       _rl_vi_last_motion = c;
 1183:       RL_UNSETSTATE (RL_STATE_VIMOTION);
 1184:       return (vidomove_dispatch (m));
 1185:     }
 1186: #if defined (READLINE_CALLBACKS)
 1187:   /* XXX - these need to handle rl_universal_argument bindings */
 1188:   /* Reading vi motion char continuing numeric argument */
 1189:   else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
 1190:     {
 1191:       return (_rl_vi_arg_dispatch (c));
 1192:     }
 1193:   /* Readine vi motion char starting numeric argument */
 1194:   else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_ISSTATE (RL_STATE_VIMOTION) && (RL_ISSTATE (RL_STATE_NUMERICARG) == 0))
 1195:     {
 1196:       RL_SETSTATE (RL_STATE_NUMERICARG);
 1197:       return (_rl_vi_arg_dispatch (c));
 1198:     }
 1199: #endif
 1200:   else if (_rl_digit_p (c))
 1201:     {
 1202:       /* This code path taken when not in callback mode */
 1203:       save = rl_numeric_arg;
 1204:       rl_numeric_arg = _rl_digit_value (c);
 1205:       rl_explicit_arg = 1;
 1206:       RL_SETSTATE (RL_STATE_NUMERICARG);
 1207:       rl_digit_loop1 ();
 1208:       rl_numeric_arg *= save;
 1209:       c = rl_vi_domove_getchar (m);
 1210:       if (c < 0)
 1211: 	{
 1212: 	  m->motion = 0;
 1213: 	  return -1;
 1214: 	}
 1215:       m->motion = c;
 1216:       return (rl_domove_motion_callback (m));
 1217:     }
 1218:   else
 1219:     {
 1220:       RL_UNSETSTATE (RL_STATE_VIMOTION);
 1221:       RL_UNSETSTATE (RL_STATE_NUMERICARG);
 1222:       return (1);
 1223:     }
 1224: }
 1225: 
 1226: static int
 1227: rl_vi_domove_getchar (m)
 1228:      _rl_vimotion_cxt *m;
 1229: {
 1230:   int c;
 1231: 
 1232:   RL_SETSTATE(RL_STATE_MOREINPUT);
 1233:   c = rl_read_key ();
 1234:   RL_UNSETSTATE(RL_STATE_MOREINPUT);
 1235: 
 1236:   return c;
 1237: }
 1238: 
 1239: #if defined (READLINE_CALLBACKS)
 1240: int
 1241: _rl_vi_domove_callback (m)
 1242:      _rl_vimotion_cxt *m;
 1243: {
 1244:   int c, r;
 1245: 
 1246:   m->motion = c = rl_vi_domove_getchar (m);
 1247:   /* XXX - what to do if this returns -1?  Should we return 1 for eof to
 1248:      callback code? */
 1249:   r = rl_domove_read_callback (m);
 1250: 
 1251:   return ((r == 0) ? r : 1);	/* normalize return values */
 1252: }
 1253: #endif
 1254: 
 1255: /* This code path taken when not in callback mode. */
 1256: int
 1257: rl_vi_domove (x, ignore)
 1258:      int x, *ignore;
 1259: {
 1260:   int r;
 1261:   _rl_vimotion_cxt *m;
 1262: 
 1263:   m = _rl_vimvcxt;
 1264:   *ignore = m->motion = rl_vi_domove_getchar (m);
 1265: 
 1266:   if (m->motion < 0)
 1267:     {
 1268:       m->motion = 0;
 1269:       return -1;
 1270:     }
 1271: 
 1272:   return (rl_domove_read_callback (m));
 1273: }
 1274: 
 1275: static int
 1276: vi_delete_dispatch (m)
 1277:      _rl_vimotion_cxt *m;
 1278: {
 1279:   /* These are the motion commands that do not require adjusting the
 1280:      mark. */
 1281:   if (((strchr (" l|h^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
 1282:       (rl_mark < rl_end))
 1283:     rl_mark++;
 1284: 
 1285:   rl_kill_text (rl_point, rl_mark);
 1286:   return (0);
 1287: }
 1288: 
 1289: int
 1290: rl_vi_delete_to (count, key)
 1291:      int count, key;
 1292: {
 1293:   int c, r;
 1294: 
 1295:   _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key);
 1296:   _rl_vimvcxt->start = rl_point;
 1297: 
 1298:   rl_mark = rl_point;
 1299:   if (_rl_uppercase_p (key))
 1300:     {
 1301:       _rl_vimvcxt->motion = '$';
 1302:       r = rl_domove_motion_callback (_rl_vimvcxt);
 1303:     }
 1304:   else if (vi_redoing && _rl_vi_last_motion != 'd')	/* `dd' is special */
 1305:     {
 1306:       _rl_vimvcxt->motion = _rl_vi_last_motion;
 1307:       r = rl_domove_motion_callback (_rl_vimvcxt);
 1308:     }
 1309:   else if (vi_redoing)		/* handle redoing `dd' here */
 1310:     {
 1311:       _rl_vimvcxt->motion = _rl_vi_last_motion;
 1312:       rl_mark = rl_end;
 1313:       rl_beg_of_line (1, key);
 1314:       RL_UNSETSTATE (RL_STATE_VIMOTION);
 1315:       r = vidomove_dispatch (_rl_vimvcxt);
 1316:     }
 1317: #if defined (READLINE_CALLBACKS)
 1318:   else if (RL_ISSTATE (RL_STATE_CALLBACK))
 1319:     {
 1320:       RL_SETSTATE (RL_STATE_VIMOTION);
 1321:       return (0);
 1322:     }
 1323: #endif
 1324:   else
 1325:     r = rl_vi_domove (key, &c);
 1326: 
 1327:   if (r < 0)
 1328:     {
 1329:       rl_ding ();
 1330:       r = -1;
 1331:     }
 1332: 
 1333:   _rl_mvcxt_dispose (_rl_vimvcxt);
 1334:   _rl_vimvcxt = 0;
 1335: 
 1336:   return r;
 1337: }
 1338: 
 1339: static int
 1340: vi_change_dispatch (m)
 1341:      _rl_vimotion_cxt *m;
 1342: {
 1343:   /* These are the motion commands that do not require adjusting the
 1344:      mark.  c[wW] are handled by special-case code in rl_vi_domove(),
 1345:      and already leave the mark at the correct location. */
 1346:   if (((strchr (" l|hwW^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
 1347:       (rl_mark < rl_end))
 1348:     rl_mark++;
 1349: 
 1350:   /* The cursor never moves with c[wW]. */
 1351:   if ((_rl_to_upper (m->motion) == 'W') && rl_point < m->start)
 1352:     rl_point = m->start;
 1353: 
 1354:   if (vi_redoing)
 1355:     {
 1356:       if (vi_insert_buffer && *vi_insert_buffer)
 1357: 	rl_begin_undo_group ();
 1358:       rl_delete_text (rl_point, rl_mark);
 1359:       if (vi_insert_buffer && *vi_insert_buffer)
 1360: 	{
 1361: 	  rl_insert_text (vi_insert_buffer);
 1362: 	  rl_end_undo_group ();
 1363: 	}
 1364:     }
 1365:   else
 1366:     {
 1367:       rl_begin_undo_group ();		/* to make the `u' command work */
 1368:       rl_kill_text (rl_point, rl_mark);
 1369:       /* `C' does not save the text inserted for undoing or redoing. */
 1370:       if (_rl_uppercase_p (m->key) == 0)
 1371: 	_rl_vi_doing_insert = 1;
 1372:       /* XXX -- TODO -- use m->numericarg? */
 1373:       rl_vi_start_inserting (m->key, rl_numeric_arg, rl_arg_sign);
 1374:     }
 1375: 
 1376:   return (0);
 1377: }
 1378: 
 1379: int
 1380: rl_vi_change_to (count, key)
 1381:      int count, key;
 1382: {
 1383:   int c, r;
 1384: 
 1385:   _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key);
 1386:   _rl_vimvcxt->start = rl_point;
 1387: 
 1388:   rl_mark = rl_point;
 1389:   if (_rl_uppercase_p (key))
 1390:     {
 1391:       _rl_vimvcxt->motion = '$';
 1392:       r = rl_domove_motion_callback (_rl_vimvcxt);
 1393:     }
 1394:   else if (vi_redoing && _rl_vi_last_motion != 'c')	/* `cc' is special */
 1395:     {
 1396:       _rl_vimvcxt->motion = _rl_vi_last_motion;
 1397:       r = rl_domove_motion_callback (_rl_vimvcxt);
 1398:     }
 1399:   else if (vi_redoing)		/* handle redoing `cc' here */
 1400:     {
 1401:       _rl_vimvcxt->motion = _rl_vi_last_motion;
 1402:       rl_mark = rl_end;
 1403:       rl_beg_of_line (1, key);
 1404:       RL_UNSETSTATE (RL_STATE_VIMOTION);
 1405:       r = vidomove_dispatch (_rl_vimvcxt);
 1406:     }
 1407: #if defined (READLINE_CALLBACKS)
 1408:   else if (RL_ISSTATE (RL_STATE_CALLBACK))
 1409:     {
 1410:       RL_SETSTATE (RL_STATE_VIMOTION);
 1411:       return (0);
 1412:     }
 1413: #endif
 1414:   else
 1415:     r = rl_vi_domove (key, &c);
 1416: 
 1417:   if (r < 0)
 1418:     {
 1419:       rl_ding ();
 1420:       r = -1;	/* normalize return value */
 1421:     }
 1422: 
 1423:   _rl_mvcxt_dispose (_rl_vimvcxt);
 1424:   _rl_vimvcxt = 0;
 1425: 
 1426:   return r;
 1427: }
 1428: 
 1429: static int
 1430: vi_yank_dispatch (m)
 1431:      _rl_vimotion_cxt *m;
 1432: {
 1433:   /* These are the motion commands that do not require adjusting the
 1434:      mark. */
 1435:   if (((strchr (" l|h^0%bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
 1436:       (rl_mark < rl_end))
 1437:     rl_mark++;
 1438: 
 1439:   rl_begin_undo_group ();
 1440:   rl_kill_text (rl_point, rl_mark);
 1441:   rl_end_undo_group ();
 1442:   rl_do_undo ();
 1443:   rl_point = m->start;
 1444: 
 1445:   return (0);
 1446: }
 1447: 
 1448: int
 1449: rl_vi_yank_to (count, key)
 1450:      int count, key;
 1451: {
 1452:   int c, r;
 1453: 
 1454:   _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key);
 1455:   _rl_vimvcxt->start = rl_point;
 1456: 
 1457:   rl_mark = rl_point;
 1458:   if (_rl_uppercase_p (key))
 1459:     {
 1460:       _rl_vimvcxt->motion = '$';
 1461:       r = rl_domove_motion_callback (_rl_vimvcxt);
 1462:     }
 1463:   else if (vi_redoing && _rl_vi_last_motion != 'y')	/* `yy' is special */
 1464:     {
 1465:       _rl_vimvcxt->motion = _rl_vi_last_motion;
 1466:       r = rl_domove_motion_callback (_rl_vimvcxt);
 1467:     }
 1468:   else if (vi_redoing)			/* handle redoing `yy' here */
 1469:     {
 1470:       _rl_vimvcxt->motion = _rl_vi_last_motion;
 1471:       rl_mark = rl_end;
 1472:       rl_beg_of_line (1, key);
 1473:       RL_UNSETSTATE (RL_STATE_VIMOTION);
 1474:       r = vidomove_dispatch (_rl_vimvcxt);
 1475:     }
 1476: #if defined (READLINE_CALLBACKS)
 1477:   else if (RL_ISSTATE (RL_STATE_CALLBACK))
 1478:     {
 1479:       RL_SETSTATE (RL_STATE_VIMOTION);
 1480:       return (0);
 1481:     }
 1482: #endif
 1483:   else
 1484:     r = rl_vi_domove (key, &c);
 1485: 
 1486:   if (r < 0)
 1487:     {
 1488:       rl_ding ();
 1489:       r = -1;
 1490:     }
 1491: 
 1492:   _rl_mvcxt_dispose (_rl_vimvcxt);
 1493:   _rl_vimvcxt = 0;
 1494: 
 1495:   return r;
 1496: }
 1497: 
 1498: static int
 1499: vidomove_dispatch (m)
 1500:      _rl_vimotion_cxt *m;
 1501: {
 1502:   int r;
 1503: 
 1504:   switch (m->op)
 1505:     {
 1506:     case VIM_DELETE:
 1507:       r = vi_delete_dispatch (m);
 1508:       break;
 1509:     case VIM_CHANGE:
 1510:       r = vi_change_dispatch (m);
 1511:       break;
 1512:     case VIM_YANK:
 1513:       r = vi_yank_dispatch (m);
 1514:       break;
 1515:     default:
 1516:       _rl_errmsg ("vidomove_dispatch: unknown operator %d", m->op);
 1517:       r = 1;
 1518:       break;
 1519:     }
 1520: 
 1521:   RL_UNSETSTATE (RL_STATE_VIMOTION);
 1522:   return r;
 1523: }
 1524: 
 1525: int
 1526: rl_vi_rubout (count, key)
 1527:      int count, key;
 1528: {
 1529:   int opoint;
 1530: 
 1531:   if (count < 0)
 1532:     return (rl_vi_delete (-count, key));
 1533: 
 1534:   if (rl_point == 0)
 1535:     {
 1536:       rl_ding ();
 1537:       return -1;
 1538:     }
 1539: 
 1540:   opoint = rl_point;
 1541:   if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
 1542:     rl_backward_char (count, key);
 1543:   else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
 1544:     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
 1545:   else
 1546:     rl_point -= count;
 1547: 
 1548:   if (rl_point < 0)
 1549:     rl_point = 0;
 1550: 
 1551:   rl_kill_text (rl_point, opoint);
 1552:   
 1553:   return (0);
 1554: }
 1555: 
 1556: int
 1557: rl_vi_delete (count, key)
 1558:      int count, key;
 1559: {
 1560:   int end;
 1561: 
 1562:   if (count < 0)
 1563:     return (rl_vi_rubout (-count, key));
 1564: 
 1565:   if (rl_end == 0)
 1566:     {
 1567:       rl_ding ();
 1568:       return -1;
 1569:     }
 1570: 
 1571:   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
 1572:     end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
 1573:   else
 1574:     end = rl_point + count;
 1575: 
 1576:   if (end >= rl_end)
 1577:     end = rl_end;
 1578: 
 1579:   rl_kill_text (rl_point, end);
 1580:   
 1581:   if (rl_point > 0 && rl_point == rl_end)
 1582:     rl_backward_char (1, key);
 1583: 
 1584:   return (0);
 1585: }
 1586: 
 1587: int
 1588: rl_vi_back_to_indent (count, key)
 1589:      int count, key;
 1590: {
 1591:   rl_beg_of_line (1, key);
 1592:   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
 1593:     rl_point++;
 1594:   return (0);
 1595: }
 1596: 
 1597: int
 1598: rl_vi_first_print (count, key)
 1599:      int count, key;
 1600: {
 1601:   return (rl_vi_back_to_indent (1, key));
 1602: }
 1603: 
 1604: static int _rl_cs_dir, _rl_cs_orig_dir;
 1605: 
 1606: #if defined (READLINE_CALLBACKS)
 1607: static int
 1608: _rl_vi_callback_char_search (data)
 1609:      _rl_callback_generic_arg *data;
 1610: {
 1611:   int c;
 1612: #if defined (HANDLE_MULTIBYTE)
 1613:   c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
 1614: #else
 1615:   RL_SETSTATE(RL_STATE_MOREINPUT);
 1616:   c = rl_read_key ();
 1617:   RL_UNSETSTATE(RL_STATE_MOREINPUT);
 1618: #endif
 1619: 
 1620:   if (c <= 0)
 1621:     return -1;
 1622: 
 1623: #if !defined (HANDLE_MULTIBYTE)
 1624:   _rl_vi_last_search_char = c;
 1625: #endif
 1626: 
 1627:   _rl_callback_func = 0;
 1628:   _rl_want_redisplay = 1;
 1629: 
 1630: #if defined (HANDLE_MULTIBYTE)
 1631:   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
 1632: #else
 1633:   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
 1634: #endif  
 1635: }
 1636: #endif
 1637: 
 1638: int
 1639: rl_vi_char_search (count, key)
 1640:      int count, key;
 1641: {
 1642:   int c;
 1643: #if defined (HANDLE_MULTIBYTE)
 1644:   static char *target;
 1645:   static int tlen;
 1646: #else
 1647:   static char target;
 1648: #endif
 1649: 
 1650:   if (key == ';' || key == ',')
 1651:     {
 1652:       if (_rl_cs_orig_dir == 0)
 1653: 	return -1;
 1654: #if defined (HANDLE_MULTIBYTE)
 1655:       if (_rl_vi_last_search_mblen == 0)
 1656: 	return -1;
 1657: #else
 1658:       if (_rl_vi_last_search_char == 0)
 1659: 	return -1;
 1660: #endif
 1661:       _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
 1662:     }
 1663:   else
 1664:     {
 1665:       switch (key)
 1666: 	{
 1667: 	case 't':
 1668: 	  _rl_cs_orig_dir = _rl_cs_dir = FTO;
 1669: 	  break;
 1670: 
 1671: 	case 'T':
 1672: 	  _rl_cs_orig_dir = _rl_cs_dir = BTO;
 1673: 	  break;
 1674: 
 1675: 	case 'f':
 1676: 	  _rl_cs_orig_dir = _rl_cs_dir = FFIND;
 1677: 	  break;
 1678: 
 1679: 	case 'F':
 1680: 	  _rl_cs_orig_dir = _rl_cs_dir = BFIND;
 1681: 	  break;
 1682: 	}
 1683: 
 1684:       if (vi_redoing)
 1685: 	{
 1686: 	  /* set target and tlen below */
 1687: 	}
 1688: #if defined (READLINE_CALLBACKS)
 1689:       else if (RL_ISSTATE (RL_STATE_CALLBACK))
 1690: 	{
 1691: 	  _rl_callback_data = _rl_callback_data_alloc (count);
 1692: 	  _rl_callback_data->i1 = _rl_cs_dir;
 1693: 	  _rl_callback_func = _rl_vi_callback_char_search;
 1694: 	  return (0);
 1695: 	}
 1696: #endif
 1697:       else
 1698: 	{
 1699: #if defined (HANDLE_MULTIBYTE)
 1700: 	  c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
 1701: 	  if (c <= 0)
 1702: 	    return -1;
 1703: 	  _rl_vi_last_search_mblen = c;
 1704: #else
 1705: 	  RL_SETSTATE(RL_STATE_MOREINPUT);
 1706: 	  c = rl_read_key ();
 1707: 	  RL_UNSETSTATE(RL_STATE_MOREINPUT);
 1708: 	  if (c < 0)
 1709: 	    return -1;
 1710: 	  _rl_vi_last_search_char = c;
 1711: #endif
 1712: 	}
 1713:     }
 1714: 
 1715: #if defined (HANDLE_MULTIBYTE)
 1716:   target = _rl_vi_last_search_mbchar;
 1717:   tlen = _rl_vi_last_search_mblen;
 1718: #else
 1719:   target = _rl_vi_last_search_char;
 1720: #endif
 1721: 
 1722: #if defined (HANDLE_MULTIBYTE)
 1723:   return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
 1724: #else
 1725:   return (_rl_char_search_internal (count, _rl_cs_dir, target));
 1726: #endif
 1727: }
 1728: 
 1729: /* Match brackets */
 1730: int
 1731: rl_vi_match (ignore, key)
 1732:      int ignore, key;
 1733: {
 1734:   int count = 1, brack, pos, tmp, pre;
 1735: 
 1736:   pos = rl_point;
 1737:   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
 1738:     {
 1739:       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
 1740: 	{
 1741: 	  while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
 1742: 	    {
 1743: 	      pre = rl_point;
 1744: 	      rl_forward_char (1, key);
 1745: 	      if (pre == rl_point)
 1746: 		break;
 1747: 	    }
 1748: 	}
 1749:       else
 1750: 	while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
 1751: 		rl_point < rl_end - 1)
 1752: 	  rl_forward_char (1, key);
 1753: 
 1754:       if (brack <= 0)
 1755: 	{
 1756: 	  rl_point = pos;
 1757: 	  rl_ding ();
 1758: 	  return -1;
 1759: 	}
 1760:     }
 1761: 
 1762:   pos = rl_point;
 1763: 
 1764:   if (brack < 0)
 1765:     {
 1766:       while (count)
 1767: 	{
 1768: 	  tmp = pos;
 1769: 	  if (MB_CUR_MAX == 1 || rl_byte_oriented)
 1770: 	    pos--;
 1771: 	  else
 1772: 	    {
 1773: 	      pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
 1774: 	      if (tmp == pos)
 1775: 		pos--;
 1776: 	    }
 1777: 	  if (pos >= 0)
 1778: 	    {
 1779: 	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
 1780: 	      if (b == -brack)
 1781: 		count--;
 1782: 	      else if (b == brack)
 1783: 		count++;
 1784: 	    }
 1785: 	  else
 1786: 	    {
 1787: 	      rl_ding ();
 1788: 	      return -1;
 1789: 	    }
 1790: 	}
 1791:     }
 1792:   else
 1793:     {			/* brack > 0 */
 1794:       while (count)
 1795: 	{
 1796: 	  if (MB_CUR_MAX == 1 || rl_byte_oriented)
 1797: 	    pos++;
 1798: 	  else
 1799: 	    pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
 1800: 
 1801: 	  if (pos < rl_end)
 1802: 	    {
 1803: 	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
 1804: 	      if (b == -brack)
 1805: 		count--;
 1806: 	      else if (b == brack)
 1807: 		count++;
 1808: 	    }
 1809: 	  else
 1810: 	    {
 1811: 	      rl_ding ();
 1812: 	      return -1;
 1813: 	    }
 1814: 	}
 1815:     }
 1816:   rl_point = pos;
 1817:   return (0);
 1818: }
 1819: 
 1820: int
 1821: rl_vi_bracktype (c)
 1822:      int c;
 1823: {
 1824:   switch (c)
 1825:     {
 1826:     case '(': return  1;
 1827:     case ')': return -1;
 1828:     case '[': return  2;
 1829:     case ']': return -2;
 1830:     case '{': return  3;
 1831:     case '}': return -3;
 1832:     default:  return  0;
 1833:     }
 1834: }
 1835: 
 1836: static int
 1837: _rl_vi_change_char (count, c, mb)
 1838:      int count, c;
 1839:      char *mb;
 1840: {
 1841:   int p;
 1842: 
 1843:   if (c == '\033' || c == CTRL ('C'))
 1844:     return -1;
 1845: 
 1846:   rl_begin_undo_group ();
 1847:   while (count-- && rl_point < rl_end)
 1848:     {
 1849:       p = rl_point;
 1850:       rl_vi_delete (1, c);
 1851:       if (rl_point < p)		/* Did we retreat at EOL? */
 1852: 	rl_point++;
 1853: #if defined (HANDLE_MULTIBYTE)
 1854:       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
 1855: 	rl_insert_text (mb);
 1856:       else
 1857: #endif
 1858: 	_rl_insert_char (1, c);
 1859:     }
 1860: 
 1861:   /* The cursor shall be left on the last character changed. */
 1862:   rl_backward_char (1, c);
 1863: 
 1864:   rl_end_undo_group ();
 1865: 
 1866:   return (0);
 1867: }
 1868: 
 1869: static int
 1870: _rl_vi_callback_getchar (mb, mlen)
 1871:      char *mb;
 1872:      int mlen;
 1873: {
 1874:   int c;
 1875: 
 1876:   RL_SETSTATE(RL_STATE_MOREINPUT);
 1877:   c = rl_read_key ();
 1878:   RL_UNSETSTATE(RL_STATE_MOREINPUT);
 1879: 
 1880:   if (c < 0)
 1881:     return -1;
 1882: 
 1883: #if defined (HANDLE_MULTIBYTE)
 1884:   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
 1885:     c = _rl_read_mbstring (c, mb, mlen);
 1886: #endif
 1887: 
 1888:   return c;
 1889: }
 1890: 
 1891: #if defined (READLINE_CALLBACKS)
 1892: static int
 1893: _rl_vi_callback_change_char (data)
 1894:      _rl_callback_generic_arg *data;
 1895: {
 1896:   int c;
 1897:   char mb[MB_LEN_MAX];
 1898: 
 1899:   _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
 1900: 
 1901:   if (c < 0)
 1902:     return -1;
 1903: 
 1904:   _rl_callback_func = 0;
 1905:   _rl_want_redisplay = 1;
 1906: 
 1907:   return (_rl_vi_change_char (data->count, c, mb));
 1908: }
 1909: #endif
 1910: 
 1911: int
 1912: rl_vi_change_char (count, key)
 1913:      int count, key;
 1914: {
 1915:   int c;
 1916:   char mb[MB_LEN_MAX];
 1917: 
 1918:   if (vi_redoing)
 1919:     {
 1920:       c = _rl_vi_last_replacement;
 1921:       mb[0] = c;
 1922:       mb[1] = '\0';
 1923:     }
 1924: #if defined (READLINE_CALLBACKS)
 1925:   else if (RL_ISSTATE (RL_STATE_CALLBACK))
 1926:     {
 1927:       _rl_callback_data = _rl_callback_data_alloc (count);
 1928:       _rl_callback_func = _rl_vi_callback_change_char;
 1929:       return (0);
 1930:     }
 1931: #endif
 1932:   else
 1933:     _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
 1934: 
 1935:   if (c < 0)
 1936:     return -1;
 1937: 
 1938:   return (_rl_vi_change_char (count, c, mb));
 1939: }
 1940: 
 1941: int
 1942: rl_vi_subst (count, key)
 1943:      int count, key;
 1944: {
 1945:   /* If we are redoing, rl_vi_change_to will stuff the last motion char */
 1946:   if (vi_redoing == 0)
 1947:     rl_stuff_char ((key == 'S') ? 'c' : 'l');	/* `S' == `cc', `s' == `cl' */
 1948: 
 1949:   return (rl_vi_change_to (count, 'c'));
 1950: }
 1951: 
 1952: int
 1953: rl_vi_overstrike (count, key)
 1954:      int count, key;
 1955: {
 1956:   if (_rl_vi_doing_insert == 0)
 1957:     {
 1958:       _rl_vi_doing_insert = 1;
 1959:       rl_begin_undo_group ();
 1960:     }
 1961: 
 1962:   if (count > 0)
 1963:     {
 1964:       _rl_overwrite_char (count, key);
 1965:       vi_replace_count += count;
 1966:     }
 1967: 
 1968:   return (0);
 1969: }
 1970: 
 1971: int
 1972: rl_vi_overstrike_delete (count, key)
 1973:      int count, key;
 1974: {
 1975:   int i, s;
 1976: 
 1977:   for (i = 0; i < count; i++)
 1978:     {
 1979:       if (vi_replace_count == 0)
 1980: 	{
 1981: 	  rl_ding ();
 1982: 	  break;
 1983: 	}
 1984:       s = rl_point;
 1985: 
 1986:       if (rl_do_undo ())
 1987: 	vi_replace_count--;
 1988: 
 1989:       if (rl_point == s)
 1990: 	rl_backward_char (1, key);
 1991:     }
 1992: 
 1993:   if (vi_replace_count == 0 && _rl_vi_doing_insert)
 1994:     {
 1995:       rl_end_undo_group ();
 1996:       rl_do_undo ();
 1997:       _rl_vi_doing_insert = 0;
 1998:     }
 1999:   return (0);
 2000: }
 2001: 
 2002: int
 2003: rl_vi_replace (count, key)
 2004:      int count, key;
 2005: {
 2006:   int i;
 2007: 
 2008:   vi_replace_count = 0;
 2009: 
 2010:   if (vi_replace_map == 0)
 2011:     {
 2012:       vi_replace_map = rl_make_bare_keymap ();
 2013: 
 2014:       for (i = 0; i < ' '; i++)
 2015: 	if (vi_insertion_keymap[i].type == ISFUNC)
 2016: 	  vi_replace_map[i].function = vi_insertion_keymap[i].function;
 2017: 
 2018:       for (i = ' '; i < KEYMAP_SIZE; i++)
 2019: 	vi_replace_map[i].function = rl_vi_overstrike;
 2020: 
 2021:       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
 2022: 
 2023:       /* Make sure these are what we want. */
 2024:       vi_replace_map[ESC].function = rl_vi_movement_mode;
 2025:       vi_replace_map[RETURN].function = rl_newline;
 2026:       vi_replace_map[NEWLINE].function = rl_newline;
 2027: 
 2028:       /* If the normal vi insertion keymap has ^H bound to erase, do the
 2029: 	 same here.  Probably should remove the assignment to RUBOUT up
 2030: 	 there, but I don't think it will make a difference in real life. */
 2031:       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
 2032: 	  vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
 2033: 	vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
 2034: 
 2035:     }
 2036: 
 2037:   rl_vi_start_inserting (key, 1, rl_arg_sign);
 2038: 
 2039:   _rl_vi_last_key_before_insert = key;
 2040:   _rl_keymap = vi_replace_map;
 2041: 
 2042:   return (0);
 2043: }
 2044: 
 2045: #if 0
 2046: /* Try to complete the word we are standing on or the word that ends with
 2047:    the previous character.  A space matches everything.  Word delimiters are
 2048:    space and ;. */
 2049: int
 2050: rl_vi_possible_completions()
 2051: {
 2052:   int save_pos = rl_point;
 2053: 
 2054:   if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
 2055:     {
 2056:       while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
 2057: 	     rl_line_buffer[rl_point] != ';')
 2058: 	rl_point++;
 2059:     }
 2060:   else if (rl_line_buffer[rl_point - 1] == ';')
 2061:     {
 2062:       rl_ding ();
 2063:       return (0);
 2064:     }
 2065: 
 2066:   rl_possible_completions ();
 2067:   rl_point = save_pos;
 2068: 
 2069:   return (0);
 2070: }
 2071: #endif
 2072: 
 2073: /* Functions to save and restore marks. */
 2074: static int
 2075: _rl_vi_set_mark ()
 2076: {
 2077:   int ch;
 2078: 
 2079:   RL_SETSTATE(RL_STATE_MOREINPUT);
 2080:   ch = rl_read_key ();
 2081:   RL_UNSETSTATE(RL_STATE_MOREINPUT);
 2082: 
 2083:   if (ch < 0 || ch < 'a' || ch > 'z')	/* make test against 0 explicit */
 2084:     {
 2085:       rl_ding ();
 2086:       return -1;
 2087:     }
 2088:   ch -= 'a';
 2089:   vi_mark_chars[ch] = rl_point;
 2090:   return 0;
 2091: }
 2092: 
 2093: #if defined (READLINE_CALLBACKS)
 2094: static int
 2095: _rl_vi_callback_set_mark (data)
 2096:      _rl_callback_generic_arg *data;
 2097: {
 2098:   _rl_callback_func = 0;
 2099:   _rl_want_redisplay = 1;
 2100: 
 2101:   return (_rl_vi_set_mark ());
 2102: }
 2103: #endif
 2104: 
 2105: int
 2106: rl_vi_set_mark (count, key)
 2107:      int count, key;
 2108: {
 2109: #if defined (READLINE_CALLBACKS)
 2110:   if (RL_ISSTATE (RL_STATE_CALLBACK))
 2111:     {
 2112:       _rl_callback_data = 0;
 2113:       _rl_callback_func = _rl_vi_callback_set_mark;
 2114:       return (0);
 2115:     }
 2116: #endif
 2117: 
 2118:   return (_rl_vi_set_mark ());
 2119: }
 2120: 
 2121: static int
 2122: _rl_vi_goto_mark ()
 2123: {
 2124:   int ch;
 2125: 
 2126:   RL_SETSTATE(RL_STATE_MOREINPUT);
 2127:   ch = rl_read_key ();
 2128:   RL_UNSETSTATE(RL_STATE_MOREINPUT);
 2129: 
 2130:   if (ch == '`')
 2131:     {
 2132:       rl_point = rl_mark;
 2133:       return 0;
 2134:     }
 2135:   else if (ch < 0 || ch < 'a' || ch > 'z')	/* make test against 0 explicit */
 2136:     {
 2137:       rl_ding ();
 2138:       return -1;
 2139:     }
 2140: 
 2141:   ch -= 'a';
 2142:   if (vi_mark_chars[ch] == -1)
 2143:     {
 2144:       rl_ding ();
 2145:       return -1;
 2146:     }
 2147:   rl_point = vi_mark_chars[ch];
 2148:   return 0;
 2149: }
 2150: 
 2151: #if defined (READLINE_CALLBACKS)
 2152: static int
 2153: _rl_vi_callback_goto_mark (data)
 2154:      _rl_callback_generic_arg *data;
 2155: {
 2156:   _rl_callback_func = 0;
 2157:   _rl_want_redisplay = 1;
 2158: 
 2159:   return (_rl_vi_goto_mark ());
 2160: }
 2161: #endif
 2162: 
 2163: int
 2164: rl_vi_goto_mark (count, key)
 2165:      int count, key;
 2166: {
 2167: #if defined (READLINE_CALLBACKS)
 2168:   if (RL_ISSTATE (RL_STATE_CALLBACK))
 2169:     {
 2170:       _rl_callback_data = 0;
 2171:       _rl_callback_func = _rl_vi_callback_goto_mark;
 2172:       return (0);
 2173:     }
 2174: #endif
 2175: 
 2176:   return (_rl_vi_goto_mark ());
 2177: }
 2178: #endif /* VI_MODE */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>