File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / vi_mode.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 01:01:01 2021 UTC (3 years, 3 months ago) by misho
Branches: readline, MAIN
CVS tags: v8_2p0, v8_1p0, HEAD
readline 8.1

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

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