vi_mode.c revision 119610
121308Sache/* vi_mode.c -- A vi emulation mode for Bash. 221308Sache Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ 321308Sache 421308Sache/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. 521308Sache 621308Sache This file is part of the GNU Readline Library, a library for 721308Sache reading lines of text with interactive input and history editing. 821308Sache 921308Sache The GNU Readline Library is free software; you can redistribute it 1021308Sache and/or modify it under the terms of the GNU General Public License 1158310Sache as published by the Free Software Foundation; either version 2, or 1221308Sache (at your option) any later version. 1321308Sache 1421308Sache The GNU Readline Library is distributed in the hope that it will be 1521308Sache useful, but WITHOUT ANY WARRANTY; without even the implied warranty 1621308Sache of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1721308Sache GNU General Public License for more details. 1821308Sache 1921308Sache The GNU General Public License is often shipped with GNU software, and 2021308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2121308Sache have a copy of the license, write to the Free Software Foundation, 2258310Sache 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 2321308Sache#define READLINE_LIBRARY 2421308Sache 2521308Sache/* **************************************************************** */ 2621308Sache/* */ 2721308Sache/* VI Emulation Mode */ 2821308Sache/* */ 2921308Sache/* **************************************************************** */ 3021308Sache#include "rlconf.h" 3121308Sache 3221308Sache#if defined (VI_MODE) 3321308Sache 3421308Sache#if defined (HAVE_CONFIG_H) 3521308Sache# include <config.h> 3621308Sache#endif 3721308Sache 3821308Sache#include <sys/types.h> 3921308Sache 4021308Sache#if defined (HAVE_STDLIB_H) 4121308Sache# include <stdlib.h> 4221308Sache#else 4321308Sache# include "ansi_stdlib.h" 4421308Sache#endif /* HAVE_STDLIB_H */ 4521308Sache 4621308Sache#if defined (HAVE_UNISTD_H) 4721308Sache# include <unistd.h> 4821308Sache#endif 4921308Sache 5021308Sache#include <stdio.h> 5121308Sache 5221308Sache/* Some standard library routines. */ 5321308Sache#include "rldefs.h" 54119610Sache#include "rlmbutil.h" 55119610Sache 5621308Sache#include "readline.h" 5721308Sache#include "history.h" 5821308Sache 5958310Sache#include "rlprivate.h" 6058310Sache#include "xmalloc.h" 6158310Sache 6221308Sache#ifndef member 6321308Sache#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) 6421308Sache#endif 6521308Sache 6621308Sache/* Non-zero means enter insertion mode. */ 6721308Sachestatic int _rl_vi_doing_insert; 6821308Sache 6921308Sache/* Command keys which do movement for xxx_to commands. */ 70119610Sachestatic const char *vi_motion = " hl^$0ftFT;,%wbeWBE|"; 7121308Sache 7221308Sache/* Keymap used for vi replace characters. Created dynamically since 7321308Sache rarely used. */ 7421308Sachestatic Keymap vi_replace_map; 7521308Sache 7621308Sache/* The number of characters inserted in the last replace operation. */ 7721308Sachestatic int vi_replace_count; 7821308Sache 7921308Sache/* If non-zero, we have text inserted after a c[motion] command that put 8021308Sache us implicitly into insert mode. Some people want this text to be 8121308Sache attached to the command so that it is `redoable' with `.'. */ 8221308Sachestatic int vi_continued_command; 8321308Sachestatic char *vi_insert_buffer; 8421308Sachestatic int vi_insert_buffer_size; 8521308Sache 8621308Sachestatic int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ 8721308Sachestatic int _rl_vi_last_repeat = 1; 8821308Sachestatic int _rl_vi_last_arg_sign = 1; 8921308Sachestatic int _rl_vi_last_motion; 90119610Sache#if defined (HANDLE_MULTIBYTE) 91119610Sachestatic char _rl_vi_last_search_mbchar[MB_LEN_MAX]; 92119610Sache#else 9321308Sachestatic int _rl_vi_last_search_char; 94119610Sache#endif 9521308Sachestatic int _rl_vi_last_replacement; 9621308Sache 9721308Sachestatic int _rl_vi_last_key_before_insert; 9821308Sache 9921308Sachestatic int vi_redoing; 10021308Sache 10121308Sache/* Text modification commands. These are the `redoable' commands. */ 10275406Sachestatic const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; 10321308Sache 10421308Sache/* Arrays for the saved marks. */ 105119610Sachestatic int vi_mark_chars['z' - 'a' + 1]; 10621308Sache 107119610Sachestatic void _rl_vi_stuff_insert PARAMS((int)); 108119610Sachestatic void _rl_vi_save_insert PARAMS((UNDO_LIST *)); 109119610Sachestatic int rl_digit_loop1 PARAMS((void)); 11021308Sache 11121308Sachevoid 11221308Sache_rl_vi_initialize_line () 11321308Sache{ 11421308Sache register int i; 11521308Sache 11621308Sache for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) 11721308Sache vi_mark_chars[i] = -1; 11821308Sache} 11921308Sache 12021308Sachevoid 12121308Sache_rl_vi_reset_last () 12221308Sache{ 12321308Sache _rl_vi_last_command = 'i'; 12421308Sache _rl_vi_last_repeat = 1; 12521308Sache _rl_vi_last_arg_sign = 1; 12621308Sache _rl_vi_last_motion = 0; 12721308Sache} 12821308Sache 12921308Sachevoid 13021308Sache_rl_vi_set_last (key, repeat, sign) 13121308Sache int key, repeat, sign; 13221308Sache{ 13321308Sache _rl_vi_last_command = key; 13421308Sache _rl_vi_last_repeat = repeat; 13521308Sache _rl_vi_last_arg_sign = sign; 13621308Sache} 13721308Sache 13821308Sache/* Is the command C a VI mode text modification command? */ 13921308Sacheint 14021308Sache_rl_vi_textmod_command (c) 14121308Sache int c; 14221308Sache{ 14321308Sache return (member (c, vi_textmod)); 14421308Sache} 14521308Sache 14621308Sachestatic void 14721308Sache_rl_vi_stuff_insert (count) 14821308Sache int count; 14921308Sache{ 15021308Sache rl_begin_undo_group (); 15121308Sache while (count--) 15221308Sache rl_insert_text (vi_insert_buffer); 15321308Sache rl_end_undo_group (); 15421308Sache} 15521308Sache 15621308Sache/* Bound to `.'. Called from command mode, so we know that we have to 15721308Sache redo a text modification command. The default for _rl_vi_last_command 15821308Sache puts you back into insert mode. */ 15921308Sacheint 16021308Sacherl_vi_redo (count, c) 16121308Sache int count, c; 16221308Sache{ 163119610Sache int r; 164119610Sache 16521308Sache if (!rl_explicit_arg) 16621308Sache { 16721308Sache rl_numeric_arg = _rl_vi_last_repeat; 16821308Sache rl_arg_sign = _rl_vi_last_arg_sign; 16921308Sache } 17021308Sache 171119610Sache r = 0; 17221308Sache vi_redoing = 1; 17321308Sache /* If we're redoing an insert with `i', stuff in the inserted text 17421308Sache and do not go into insertion mode. */ 17521308Sache if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) 17621308Sache { 17721308Sache _rl_vi_stuff_insert (count); 17821308Sache /* And back up point over the last character inserted. */ 17921308Sache if (rl_point > 0) 18021308Sache rl_point--; 18121308Sache } 18221308Sache else 183119610Sache r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); 18421308Sache vi_redoing = 0; 18521308Sache 186119610Sache return (r); 18721308Sache} 18821308Sache 18921308Sache/* A placeholder for further expansion. */ 19021308Sacheint 19121308Sacherl_vi_undo (count, key) 19221308Sache int count, key; 19321308Sache{ 19421308Sache return (rl_undo_command (count, key)); 19521308Sache} 19621308Sache 19721308Sache/* Yank the nth arg from the previous line into this line at point. */ 19821308Sacheint 19921308Sacherl_vi_yank_arg (count, key) 20021308Sache int count, key; 20121308Sache{ 20221308Sache /* Readline thinks that the first word on a line is the 0th, while vi 20321308Sache thinks the first word on a line is the 1st. Compensate. */ 20421308Sache if (rl_explicit_arg) 20521308Sache rl_yank_nth_arg (count - 1, 0); 20621308Sache else 20721308Sache rl_yank_nth_arg ('$', 0); 20821308Sache 20921308Sache return (0); 21021308Sache} 21121308Sache 21221308Sache/* With an argument, move back that many history lines, else move to the 21321308Sache beginning of history. */ 21421308Sacheint 21521308Sacherl_vi_fetch_history (count, c) 21621308Sache int count, c; 21721308Sache{ 21821308Sache int wanted; 21921308Sache 22021308Sache /* Giving an argument of n means we want the nth command in the history 22121308Sache file. The command number is interpreted the same way that the bash 22221308Sache `history' command does it -- that is, giving an argument count of 450 22321308Sache to this command would get the command listed as number 450 in the 22421308Sache output of `history'. */ 22521308Sache if (rl_explicit_arg) 22621308Sache { 22721308Sache wanted = history_base + where_history () - count; 22821308Sache if (wanted <= 0) 22921308Sache rl_beginning_of_history (0, 0); 23021308Sache else 23121308Sache rl_get_previous_history (wanted, c); 23221308Sache } 23321308Sache else 23421308Sache rl_beginning_of_history (count, 0); 23521308Sache return (0); 23621308Sache} 23721308Sache 23821308Sache/* Search again for the last thing searched for. */ 23921308Sacheint 24021308Sacherl_vi_search_again (count, key) 24121308Sache int count, key; 24221308Sache{ 24321308Sache switch (key) 24421308Sache { 24521308Sache case 'n': 24621308Sache rl_noninc_reverse_search_again (count, key); 24721308Sache break; 24821308Sache 24921308Sache case 'N': 25021308Sache rl_noninc_forward_search_again (count, key); 25121308Sache break; 25221308Sache } 25321308Sache return (0); 25421308Sache} 25521308Sache 25621308Sache/* Do a vi style search. */ 25721308Sacheint 25821308Sacherl_vi_search (count, key) 25921308Sache int count, key; 26021308Sache{ 26121308Sache switch (key) 26221308Sache { 26321308Sache case '?': 26421308Sache rl_noninc_forward_search (count, key); 26521308Sache break; 26621308Sache 26721308Sache case '/': 26821308Sache rl_noninc_reverse_search (count, key); 26921308Sache break; 27021308Sache 27121308Sache default: 27275406Sache rl_ding (); 27321308Sache break; 27421308Sache } 27521308Sache return (0); 27621308Sache} 27721308Sache 27821308Sache/* Completion, from vi's point of view. */ 27921308Sacheint 28021308Sacherl_vi_complete (ignore, key) 28121308Sache int ignore, key; 28221308Sache{ 28321308Sache if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) 28421308Sache { 28521308Sache if (!whitespace (rl_line_buffer[rl_point + 1])) 28621308Sache rl_vi_end_word (1, 'E'); 28721308Sache rl_point++; 28821308Sache } 28921308Sache 29021308Sache if (key == '*') 29121308Sache rl_complete_internal ('*'); /* Expansion and replacement. */ 29221308Sache else if (key == '=') 29321308Sache rl_complete_internal ('?'); /* List possible completions. */ 29421308Sache else if (key == '\\') 29521308Sache rl_complete_internal (TAB); /* Standard Readline completion. */ 29621308Sache else 29721308Sache rl_complete (0, key); 29821308Sache 29921308Sache if (key == '*' || key == '\\') 30021308Sache { 30121308Sache _rl_vi_set_last (key, 1, rl_arg_sign); 30221308Sache rl_vi_insertion_mode (1, key); 30321308Sache } 30421308Sache return (0); 30521308Sache} 30621308Sache 30721308Sache/* Tilde expansion for vi mode. */ 30821308Sacheint 30921308Sacherl_vi_tilde_expand (ignore, key) 31021308Sache int ignore, key; 31121308Sache{ 31221308Sache rl_tilde_expand (0, key); 31321308Sache _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */ 31421308Sache rl_vi_insertion_mode (1, key); 31521308Sache return (0); 31621308Sache} 31721308Sache 31821308Sache/* Previous word in vi mode. */ 31921308Sacheint 32021308Sacherl_vi_prev_word (count, key) 32121308Sache int count, key; 32221308Sache{ 32321308Sache if (count < 0) 32421308Sache return (rl_vi_next_word (-count, key)); 32521308Sache 32621308Sache if (rl_point == 0) 32721308Sache { 32875406Sache rl_ding (); 32921308Sache return (0); 33021308Sache } 33121308Sache 33221308Sache if (_rl_uppercase_p (key)) 33347558Sache rl_vi_bWord (count, key); 33421308Sache else 33547558Sache rl_vi_bword (count, key); 33621308Sache 33721308Sache return (0); 33821308Sache} 33921308Sache 34021308Sache/* Next word in vi mode. */ 34121308Sacheint 34221308Sacherl_vi_next_word (count, key) 34321308Sache int count, key; 34421308Sache{ 34521308Sache if (count < 0) 34621308Sache return (rl_vi_prev_word (-count, key)); 34721308Sache 34821308Sache if (rl_point >= (rl_end - 1)) 34921308Sache { 35075406Sache rl_ding (); 35121308Sache return (0); 35221308Sache } 35321308Sache 35421308Sache if (_rl_uppercase_p (key)) 35547558Sache rl_vi_fWord (count, key); 35621308Sache else 35747558Sache rl_vi_fword (count, key); 35821308Sache return (0); 35921308Sache} 36021308Sache 36121308Sache/* Move to the end of the ?next? word. */ 36221308Sacheint 36321308Sacherl_vi_end_word (count, key) 36421308Sache int count, key; 36521308Sache{ 36621308Sache if (count < 0) 36721308Sache { 36875406Sache rl_ding (); 36921308Sache return -1; 37021308Sache } 37121308Sache 37221308Sache if (_rl_uppercase_p (key)) 37347558Sache rl_vi_eWord (count, key); 37421308Sache else 37547558Sache rl_vi_eword (count, key); 37621308Sache return (0); 37721308Sache} 37821308Sache 37921308Sache/* Move forward a word the way that 'W' does. */ 38021308Sacheint 38147558Sacherl_vi_fWord (count, ignore) 38247558Sache int count, ignore; 38321308Sache{ 38421308Sache while (count-- && rl_point < (rl_end - 1)) 38521308Sache { 38621308Sache /* Skip until whitespace. */ 38721308Sache while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 38821308Sache rl_point++; 38921308Sache 39021308Sache /* Now skip whitespace. */ 39121308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 39221308Sache rl_point++; 39321308Sache } 39421308Sache return (0); 39521308Sache} 39621308Sache 39721308Sacheint 39847558Sacherl_vi_bWord (count, ignore) 39947558Sache int count, ignore; 40021308Sache{ 40121308Sache while (count-- && rl_point > 0) 40221308Sache { 40321308Sache /* If we are at the start of a word, move back to whitespace so 40421308Sache we will go back to the start of the previous word. */ 40521308Sache if (!whitespace (rl_line_buffer[rl_point]) && 40621308Sache whitespace (rl_line_buffer[rl_point - 1])) 40721308Sache rl_point--; 40821308Sache 40921308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 41021308Sache rl_point--; 41121308Sache 41221308Sache if (rl_point > 0) 41321308Sache { 41421308Sache while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); 41521308Sache rl_point++; 41621308Sache } 41721308Sache } 41821308Sache return (0); 41921308Sache} 42021308Sache 42121308Sacheint 42247558Sacherl_vi_eWord (count, ignore) 42347558Sache int count, ignore; 42421308Sache{ 42521308Sache while (count-- && rl_point < (rl_end - 1)) 42621308Sache { 42721308Sache if (!whitespace (rl_line_buffer[rl_point])) 42821308Sache rl_point++; 42921308Sache 43021308Sache /* Move to the next non-whitespace character (to the start of the 43121308Sache next word). */ 43221308Sache while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point])); 43321308Sache 43421308Sache if (rl_point && rl_point < rl_end) 43521308Sache { 43621308Sache /* Skip whitespace. */ 43721308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 43821308Sache rl_point++; 43921308Sache 44021308Sache /* Skip until whitespace. */ 44121308Sache while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) 44221308Sache rl_point++; 44321308Sache 44421308Sache /* Move back to the last character of the word. */ 44521308Sache rl_point--; 44621308Sache } 44721308Sache } 44821308Sache return (0); 44921308Sache} 45021308Sache 45121308Sacheint 45247558Sacherl_vi_fword (count, ignore) 45347558Sache int count, ignore; 45421308Sache{ 45521308Sache while (count-- && rl_point < (rl_end - 1)) 45621308Sache { 45721308Sache /* Move to white space (really non-identifer). */ 458119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 45921308Sache { 460119610Sache while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) 46121308Sache rl_point++; 46221308Sache } 46321308Sache else /* if (!whitespace (rl_line_buffer[rl_point])) */ 46421308Sache { 465119610Sache while (!_rl_isident (rl_line_buffer[rl_point]) && 46621308Sache !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 46721308Sache rl_point++; 46821308Sache } 46921308Sache 47021308Sache /* Move past whitespace. */ 47121308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 47221308Sache rl_point++; 47321308Sache } 47421308Sache return (0); 47521308Sache} 47621308Sache 47721308Sacheint 47847558Sacherl_vi_bword (count, ignore) 47947558Sache int count, ignore; 48021308Sache{ 48121308Sache while (count-- && rl_point > 0) 48221308Sache { 48321308Sache int last_is_ident; 48421308Sache 48521308Sache /* If we are at the start of a word, move back to whitespace 48621308Sache so we will go back to the start of the previous word. */ 48721308Sache if (!whitespace (rl_line_buffer[rl_point]) && 48821308Sache whitespace (rl_line_buffer[rl_point - 1])) 48921308Sache rl_point--; 49021308Sache 49121308Sache /* If this character and the previous character are `opposite', move 49221308Sache back so we don't get messed up by the rl_point++ down there in 49321308Sache the while loop. Without this code, words like `l;' screw up the 49421308Sache function. */ 495119610Sache last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]); 496119610Sache if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || 497119610Sache (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident)) 49821308Sache rl_point--; 49921308Sache 50021308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 50121308Sache rl_point--; 50221308Sache 50321308Sache if (rl_point > 0) 50421308Sache { 505119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 506119610Sache while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); 50721308Sache else 508119610Sache while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && 50921308Sache !whitespace (rl_line_buffer[rl_point])); 51021308Sache rl_point++; 51121308Sache } 51221308Sache } 51321308Sache return (0); 51421308Sache} 51521308Sache 51621308Sacheint 51747558Sacherl_vi_eword (count, ignore) 51847558Sache int count, ignore; 51921308Sache{ 52021308Sache while (count-- && rl_point < rl_end - 1) 52121308Sache { 52221308Sache if (!whitespace (rl_line_buffer[rl_point])) 52321308Sache rl_point++; 52421308Sache 52521308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 52621308Sache rl_point++; 52721308Sache 52821308Sache if (rl_point < rl_end) 52921308Sache { 530119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 531119610Sache while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); 53221308Sache else 533119610Sache while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) 53421308Sache && !whitespace (rl_line_buffer[rl_point])); 53521308Sache } 53621308Sache rl_point--; 53721308Sache } 53821308Sache return (0); 53921308Sache} 54021308Sache 54121308Sacheint 54221308Sacherl_vi_insert_beg (count, key) 54321308Sache int count, key; 54421308Sache{ 54521308Sache rl_beg_of_line (1, key); 54621308Sache rl_vi_insertion_mode (1, key); 54721308Sache return (0); 54821308Sache} 54921308Sache 55021308Sacheint 55121308Sacherl_vi_append_mode (count, key) 55221308Sache int count, key; 55321308Sache{ 55421308Sache if (rl_point < rl_end) 555119610Sache { 556119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 557119610Sache rl_point++; 558119610Sache else 559119610Sache { 560119610Sache int point = rl_point; 561119610Sache rl_forward_char (1, key); 562119610Sache if (point == rl_point) 563119610Sache rl_point = rl_end; 564119610Sache } 565119610Sache } 56621308Sache rl_vi_insertion_mode (1, key); 56721308Sache return (0); 56821308Sache} 56921308Sache 57021308Sacheint 57121308Sacherl_vi_append_eol (count, key) 57221308Sache int count, key; 57321308Sache{ 57421308Sache rl_end_of_line (1, key); 57521308Sache rl_vi_append_mode (1, key); 57621308Sache return (0); 57721308Sache} 57821308Sache 57921308Sache/* What to do in the case of C-d. */ 58021308Sacheint 58121308Sacherl_vi_eof_maybe (count, c) 58221308Sache int count, c; 58321308Sache{ 58421308Sache return (rl_newline (1, '\n')); 58521308Sache} 58621308Sache 58721308Sache/* Insertion mode stuff. */ 58821308Sache 58921308Sache/* Switching from one mode to the other really just involves 59021308Sache switching keymaps. */ 59121308Sacheint 59221308Sacherl_vi_insertion_mode (count, key) 59321308Sache int count, key; 59421308Sache{ 59521308Sache _rl_keymap = vi_insertion_keymap; 59621308Sache _rl_vi_last_key_before_insert = key; 59721308Sache return (0); 59821308Sache} 59921308Sache 60021308Sachestatic void 60121308Sache_rl_vi_save_insert (up) 60221308Sache UNDO_LIST *up; 60321308Sache{ 60421308Sache int len, start, end; 60521308Sache 60635486Sache if (up == 0) 60735486Sache { 60835486Sache if (vi_insert_buffer_size >= 1) 60935486Sache vi_insert_buffer[0] = '\0'; 61035486Sache return; 61135486Sache } 61235486Sache 61321308Sache start = up->start; 61421308Sache end = up->end; 61521308Sache len = end - start + 1; 61621308Sache if (len >= vi_insert_buffer_size) 61721308Sache { 61821308Sache vi_insert_buffer_size += (len + 32) - (len % 32); 619119610Sache vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); 62021308Sache } 62121308Sache strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); 62221308Sache vi_insert_buffer[len-1] = '\0'; 62321308Sache} 62421308Sache 62521308Sachevoid 62621308Sache_rl_vi_done_inserting () 62721308Sache{ 62821308Sache if (_rl_vi_doing_insert) 62921308Sache { 630119610Sache /* The `C', `s', and `S' commands set this. */ 63121308Sache rl_end_undo_group (); 63221308Sache /* Now, the text between rl_undo_list->next->start and 63321308Sache rl_undo_list->next->end is what was inserted while in insert 63421308Sache mode. It gets copied to VI_INSERT_BUFFER because it depends 63521308Sache on absolute indices into the line which may change (though they 63621308Sache probably will not). */ 63721308Sache _rl_vi_doing_insert = 0; 63821308Sache _rl_vi_save_insert (rl_undo_list->next); 63921308Sache vi_continued_command = 1; 64021308Sache } 64121308Sache else 64221308Sache { 64321308Sache if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list) 64421308Sache _rl_vi_save_insert (rl_undo_list); 64521308Sache /* XXX - Other keys probably need to be checked. */ 64621308Sache else if (_rl_vi_last_key_before_insert == 'C') 64721308Sache rl_end_undo_group (); 64821308Sache while (_rl_undo_group_level > 0) 64921308Sache rl_end_undo_group (); 65021308Sache vi_continued_command = 0; 65121308Sache } 65221308Sache} 65321308Sache 65421308Sacheint 65521308Sacherl_vi_movement_mode (count, key) 65621308Sache int count, key; 65721308Sache{ 65821308Sache if (rl_point > 0) 659119610Sache rl_backward_char (1, key); 66021308Sache 66121308Sache _rl_keymap = vi_movement_keymap; 66221308Sache _rl_vi_done_inserting (); 66321308Sache return (0); 66421308Sache} 66521308Sache 66621308Sacheint 66721308Sacherl_vi_arg_digit (count, c) 66821308Sache int count, c; 66921308Sache{ 67021308Sache if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) 67121308Sache return (rl_beg_of_line (1, c)); 67221308Sache else 67321308Sache return (rl_digit_argument (count, c)); 67421308Sache} 67521308Sache 676119610Sache/* Change the case of the next COUNT characters. */ 677119610Sache#if defined (HANDLE_MULTIBYTE) 678119610Sachestatic int 679119610Sache_rl_vi_change_mbchar_case (count) 680119610Sache int count; 681119610Sache{ 682119610Sache wchar_t wc; 683119610Sache char mb[MB_LEN_MAX]; 684119610Sache mbstate_t ps; 685119610Sache 686119610Sache memset (&ps, 0, sizeof (mbstate_t)); 687119610Sache if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) 688119610Sache count--; 689119610Sache while (count-- && rl_point < rl_end) 690119610Sache { 691119610Sache mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); 692119610Sache if (iswupper (wc)) 693119610Sache wc = towlower (wc); 694119610Sache else if (iswlower (wc)) 695119610Sache wc = towupper (wc); 696119610Sache else 697119610Sache { 698119610Sache /* Just skip over chars neither upper nor lower case */ 699119610Sache rl_forward_char (1, 0); 700119610Sache continue; 701119610Sache } 702119610Sache 703119610Sache /* Vi is kind of strange here. */ 704119610Sache if (wc) 705119610Sache { 706119610Sache wctomb (mb, wc); 707119610Sache rl_begin_undo_group (); 708119610Sache rl_delete (1, 0); 709119610Sache rl_insert_text (mb); 710119610Sache rl_end_undo_group (); 711119610Sache rl_vi_check (); 712119610Sache } 713119610Sache else 714119610Sache rl_forward_char (1, 0); 715119610Sache } 716119610Sache 717119610Sache return 0; 718119610Sache} 719119610Sache#endif 720119610Sache 72121308Sacheint 72221308Sacherl_vi_change_case (count, ignore) 72321308Sache int count, ignore; 72421308Sache{ 72521308Sache char c = 0; 72621308Sache 72721308Sache /* Don't try this on an empty line. */ 72821308Sache if (rl_point >= rl_end) 72921308Sache return (0); 73021308Sache 731119610Sache#if defined (HANDLE_MULTIBYTE) 732119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 733119610Sache return (_rl_vi_change_mbchar_case (count)); 734119610Sache#endif 735119610Sache 73621308Sache while (count-- && rl_point < rl_end) 73721308Sache { 73821308Sache if (_rl_uppercase_p (rl_line_buffer[rl_point])) 73921308Sache c = _rl_to_lower (rl_line_buffer[rl_point]); 74021308Sache else if (_rl_lowercase_p (rl_line_buffer[rl_point])) 74121308Sache c = _rl_to_upper (rl_line_buffer[rl_point]); 74221308Sache else 74321308Sache { 74421308Sache /* Just skip over characters neither upper nor lower case. */ 745119610Sache rl_forward_char (1, c); 74621308Sache continue; 74721308Sache } 74821308Sache 74921308Sache /* Vi is kind of strange here. */ 75021308Sache if (c) 75121308Sache { 75221308Sache rl_begin_undo_group (); 75321308Sache rl_delete (1, c); 754119610Sache _rl_insert_char (1, c); 75521308Sache rl_end_undo_group (); 75621308Sache rl_vi_check (); 75721308Sache } 75821308Sache else 759119610Sache rl_forward_char (1, c); 76021308Sache } 76121308Sache return (0); 76221308Sache} 76321308Sache 76421308Sacheint 76521308Sacherl_vi_put (count, key) 76621308Sache int count, key; 76721308Sache{ 76821308Sache if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) 769119610Sache rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); 77021308Sache 77147558Sache rl_yank (1, key); 772119610Sache rl_backward_char (1, key); 77321308Sache return (0); 77421308Sache} 77521308Sache 77621308Sacheint 77721308Sacherl_vi_check () 77821308Sache{ 77921308Sache if (rl_point && rl_point == rl_end) 780119610Sache { 781119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 782119610Sache rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 783119610Sache else 784119610Sache rl_point--; 785119610Sache } 78621308Sache return (0); 78721308Sache} 78821308Sache 78921308Sacheint 79021308Sacherl_vi_column (count, key) 79121308Sache int count, key; 79221308Sache{ 79321308Sache if (count > rl_end) 79421308Sache rl_end_of_line (1, key); 79521308Sache else 79621308Sache rl_point = count - 1; 79721308Sache return (0); 79821308Sache} 79921308Sache 80021308Sacheint 80121308Sacherl_vi_domove (key, nextkey) 80221308Sache int key, *nextkey; 80321308Sache{ 80421308Sache int c, save; 80521308Sache int old_end; 80621308Sache 80721308Sache rl_mark = rl_point; 80875406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 80921308Sache c = rl_read_key (); 81075406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 81121308Sache *nextkey = c; 81221308Sache 81321308Sache if (!member (c, vi_motion)) 81421308Sache { 81521308Sache if (_rl_digit_p (c)) 81621308Sache { 81721308Sache save = rl_numeric_arg; 81821308Sache rl_numeric_arg = _rl_digit_value (c); 81921308Sache rl_digit_loop1 (); 82021308Sache rl_numeric_arg *= save; 82175406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 82221308Sache c = rl_read_key (); /* real command */ 82375406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 82421308Sache *nextkey = c; 82521308Sache } 82621308Sache else if (key == c && (key == 'd' || key == 'y' || key == 'c')) 82721308Sache { 82821308Sache rl_mark = rl_end; 82921308Sache rl_beg_of_line (1, c); 83021308Sache _rl_vi_last_motion = c; 83121308Sache return (0); 83221308Sache } 83321308Sache else 83421308Sache return (-1); 83521308Sache } 83621308Sache 83721308Sache _rl_vi_last_motion = c; 83821308Sache 83921308Sache /* Append a blank character temporarily so that the motion routines 84021308Sache work right at the end of the line. */ 84121308Sache old_end = rl_end; 84221308Sache rl_line_buffer[rl_end++] = ' '; 84321308Sache rl_line_buffer[rl_end] = '\0'; 84421308Sache 84521308Sache _rl_dispatch (c, _rl_keymap); 84621308Sache 84721308Sache /* Remove the blank that we added. */ 84821308Sache rl_end = old_end; 84921308Sache rl_line_buffer[rl_end] = '\0'; 85021308Sache if (rl_point > rl_end) 85121308Sache rl_point = rl_end; 85221308Sache 85321308Sache /* No change in position means the command failed. */ 85421308Sache if (rl_mark == rl_point) 85521308Sache return (-1); 85621308Sache 85721308Sache /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next 85821308Sache word. If we are not at the end of the line, and we are on a 85921308Sache non-whitespace character, move back one (presumably to whitespace). */ 86021308Sache if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && 86121308Sache !whitespace (rl_line_buffer[rl_point])) 86221308Sache rl_point--; 86321308Sache 86421308Sache /* If cw or cW, back up to the end of a word, so the behaviour of ce 86521308Sache or cE is the actual result. Brute-force, no subtlety. */ 86621308Sache if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) 86721308Sache { 86821308Sache /* Don't move farther back than where we started. */ 86921308Sache while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) 87021308Sache rl_point--; 87121308Sache 87221308Sache /* Posix.2 says that if cw or cW moves the cursor towards the end of 87321308Sache the line, the character under the cursor should be deleted. */ 87421308Sache if (rl_point == rl_mark) 87521308Sache rl_point++; 87621308Sache else 87721308Sache { 87821308Sache /* Move past the end of the word so that the kill doesn't 87921308Sache remove the last letter of the previous word. Only do this 88021308Sache if we are not at the end of the line. */ 88121308Sache if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) 88221308Sache rl_point++; 88321308Sache } 88421308Sache } 88521308Sache 88621308Sache if (rl_mark < rl_point) 887119610Sache SWAP (rl_point, rl_mark); 88821308Sache 88921308Sache return (0); 89021308Sache} 89121308Sache 89221308Sache/* A simplified loop for vi. Don't dispatch key at end. 89375406Sache Don't recognize minus sign? 89475406Sache Should this do rl_save_prompt/rl_restore_prompt? */ 89521308Sachestatic int 89621308Sacherl_digit_loop1 () 89721308Sache{ 89821308Sache int key, c; 89921308Sache 90075406Sache RL_SETSTATE(RL_STATE_NUMERICARG); 90121308Sache while (1) 90221308Sache { 90375406Sache if (rl_numeric_arg > 1000000) 90475406Sache { 90575406Sache rl_explicit_arg = rl_numeric_arg = 0; 90675406Sache rl_ding (); 90775406Sache rl_clear_message (); 90875406Sache RL_UNSETSTATE(RL_STATE_NUMERICARG); 90975406Sache return 1; 91075406Sache } 911119610Sache rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); 91275406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 91321308Sache key = c = rl_read_key (); 91475406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 91521308Sache 916119610Sache if (c >= 0 && _rl_keymap[c].type == ISFUNC && 91721308Sache _rl_keymap[c].function == rl_universal_argument) 91821308Sache { 91921308Sache rl_numeric_arg *= 4; 92021308Sache continue; 92121308Sache } 92221308Sache 92321308Sache c = UNMETA (c); 92421308Sache if (_rl_digit_p (c)) 92521308Sache { 92621308Sache if (rl_explicit_arg) 92721308Sache rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); 92821308Sache else 92921308Sache rl_numeric_arg = _rl_digit_value (c); 93021308Sache rl_explicit_arg = 1; 93121308Sache } 93221308Sache else 93321308Sache { 93421308Sache rl_clear_message (); 93521308Sache rl_stuff_char (key); 93621308Sache break; 93721308Sache } 93821308Sache } 93975406Sache 94075406Sache RL_UNSETSTATE(RL_STATE_NUMERICARG); 94121308Sache return (0); 94221308Sache} 94321308Sache 94421308Sacheint 94521308Sacherl_vi_delete_to (count, key) 94621308Sache int count, key; 94721308Sache{ 94821308Sache int c; 94921308Sache 95021308Sache if (_rl_uppercase_p (key)) 95121308Sache rl_stuff_char ('$'); 95221308Sache else if (vi_redoing) 95321308Sache rl_stuff_char (_rl_vi_last_motion); 95421308Sache 95521308Sache if (rl_vi_domove (key, &c)) 95621308Sache { 95775406Sache rl_ding (); 95821308Sache return -1; 95921308Sache } 96021308Sache 96121308Sache /* These are the motion commands that do not require adjusting the 96221308Sache mark. */ 96321308Sache if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) 96421308Sache rl_mark++; 96521308Sache 96621308Sache rl_kill_text (rl_point, rl_mark); 96721308Sache return (0); 96821308Sache} 96921308Sache 97021308Sacheint 97121308Sacherl_vi_change_to (count, key) 97221308Sache int count, key; 97321308Sache{ 97421308Sache int c, start_pos; 97521308Sache 97621308Sache if (_rl_uppercase_p (key)) 97721308Sache rl_stuff_char ('$'); 97821308Sache else if (vi_redoing) 97921308Sache rl_stuff_char (_rl_vi_last_motion); 98021308Sache 98121308Sache start_pos = rl_point; 98221308Sache 98321308Sache if (rl_vi_domove (key, &c)) 98421308Sache { 98575406Sache rl_ding (); 98621308Sache return -1; 98721308Sache } 98821308Sache 98921308Sache /* These are the motion commands that do not require adjusting the 99021308Sache mark. c[wW] are handled by special-case code in rl_vi_domove(), 99121308Sache and already leave the mark at the correct location. */ 99221308Sache if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) 99321308Sache rl_mark++; 99421308Sache 99521308Sache /* The cursor never moves with c[wW]. */ 99621308Sache if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) 99721308Sache rl_point = start_pos; 99821308Sache 99921308Sache if (vi_redoing) 100021308Sache { 100121308Sache if (vi_insert_buffer && *vi_insert_buffer) 100221308Sache rl_begin_undo_group (); 100321308Sache rl_delete_text (rl_point, rl_mark); 100421308Sache if (vi_insert_buffer && *vi_insert_buffer) 100521308Sache { 100621308Sache rl_insert_text (vi_insert_buffer); 100721308Sache rl_end_undo_group (); 100821308Sache } 100921308Sache } 101021308Sache else 101121308Sache { 101221308Sache rl_begin_undo_group (); /* to make the `u' command work */ 101321308Sache rl_kill_text (rl_point, rl_mark); 101421308Sache /* `C' does not save the text inserted for undoing or redoing. */ 101521308Sache if (_rl_uppercase_p (key) == 0) 101621308Sache _rl_vi_doing_insert = 1; 101721308Sache _rl_vi_set_last (key, count, rl_arg_sign); 101821308Sache rl_vi_insertion_mode (1, key); 101921308Sache } 102021308Sache 102121308Sache return (0); 102221308Sache} 102321308Sache 102421308Sacheint 102521308Sacherl_vi_yank_to (count, key) 102621308Sache int count, key; 102721308Sache{ 102821308Sache int c, save = rl_point; 102921308Sache 103021308Sache if (_rl_uppercase_p (key)) 103121308Sache rl_stuff_char ('$'); 103221308Sache 103321308Sache if (rl_vi_domove (key, &c)) 103421308Sache { 103575406Sache rl_ding (); 103621308Sache return -1; 103721308Sache } 103821308Sache 103921308Sache /* These are the motion commands that do not require adjusting the 104021308Sache mark. */ 104121308Sache if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) 104221308Sache rl_mark++; 104321308Sache 104421308Sache rl_begin_undo_group (); 104521308Sache rl_kill_text (rl_point, rl_mark); 104621308Sache rl_end_undo_group (); 104721308Sache rl_do_undo (); 104821308Sache rl_point = save; 104921308Sache 105021308Sache return (0); 105121308Sache} 105221308Sache 105321308Sacheint 105421308Sacherl_vi_delete (count, key) 105521308Sache int count, key; 105621308Sache{ 105721308Sache int end; 105821308Sache 105921308Sache if (rl_end == 0) 106021308Sache { 106175406Sache rl_ding (); 106221308Sache return -1; 106321308Sache } 106421308Sache 1065119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1066119610Sache end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); 1067119610Sache else 1068119610Sache end = rl_point + count; 106921308Sache 107021308Sache if (end >= rl_end) 107121308Sache end = rl_end; 107221308Sache 107321308Sache rl_kill_text (rl_point, end); 107421308Sache 107521308Sache if (rl_point > 0 && rl_point == rl_end) 1076119610Sache rl_backward_char (1, key); 107721308Sache return (0); 107821308Sache} 107921308Sache 108021308Sacheint 108121308Sacherl_vi_back_to_indent (count, key) 108221308Sache int count, key; 108321308Sache{ 108421308Sache rl_beg_of_line (1, key); 108521308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 108621308Sache rl_point++; 108721308Sache return (0); 108821308Sache} 108921308Sache 109021308Sacheint 109121308Sacherl_vi_first_print (count, key) 109221308Sache int count, key; 109321308Sache{ 109421308Sache return (rl_vi_back_to_indent (1, key)); 109521308Sache} 109621308Sache 109721308Sacheint 109821308Sacherl_vi_char_search (count, key) 109921308Sache int count, key; 110021308Sache{ 1101119610Sache#if defined (HANDLE_MULTIBYTE) 1102119610Sache static char *target; 1103119610Sache static int mb_len; 1104119610Sache#else 110521308Sache static char target; 1106119610Sache#endif 110721308Sache static int orig_dir, dir; 110821308Sache 110921308Sache if (key == ';' || key == ',') 111021308Sache dir = key == ';' ? orig_dir : -orig_dir; 111121308Sache else 111221308Sache { 111321308Sache if (vi_redoing) 1114119610Sache#if defined (HANDLE_MULTIBYTE) 1115119610Sache target = _rl_vi_last_search_mbchar; 1116119610Sache#else 111721308Sache target = _rl_vi_last_search_char; 1118119610Sache#endif 111921308Sache else 112075406Sache { 1121119610Sache#if defined (HANDLE_MULTIBYTE) 1122119610Sache mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1123119610Sache target = _rl_vi_last_search_mbchar; 1124119610Sache#else 112575406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 112675406Sache _rl_vi_last_search_char = target = rl_read_key (); 112775406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 1128119610Sache#endif 112975406Sache } 113021308Sache 113121308Sache switch (key) 113221308Sache { 113321308Sache case 't': 113421308Sache orig_dir = dir = FTO; 113521308Sache break; 113621308Sache 113721308Sache case 'T': 113821308Sache orig_dir = dir = BTO; 113921308Sache break; 114021308Sache 114121308Sache case 'f': 114221308Sache orig_dir = dir = FFIND; 114321308Sache break; 114421308Sache 114521308Sache case 'F': 114621308Sache orig_dir = dir = BFIND; 114721308Sache break; 114821308Sache } 114921308Sache } 115021308Sache 1151119610Sache#if defined (HANDLE_MULTIBYTE) 1152119610Sache return (_rl_char_search_internal (count, dir, target, mb_len)); 1153119610Sache#else 115421308Sache return (_rl_char_search_internal (count, dir, target)); 1155119610Sache#endif 115621308Sache} 115721308Sache 115821308Sache/* Match brackets */ 115921308Sacheint 116021308Sacherl_vi_match (ignore, key) 116121308Sache int ignore, key; 116221308Sache{ 1163119610Sache int count = 1, brack, pos, tmp, pre; 116421308Sache 116521308Sache pos = rl_point; 116621308Sache if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 116721308Sache { 1168119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1169119610Sache { 1170119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1171119610Sache { 1172119610Sache pre = rl_point; 1173119610Sache rl_forward_char (1, key); 1174119610Sache if (pre == rl_point) 1175119610Sache break; 1176119610Sache } 1177119610Sache } 1178119610Sache else 1179119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && 1180119610Sache rl_point < rl_end - 1) 1181119610Sache rl_forward_char (1, key); 118221308Sache 118321308Sache if (brack <= 0) 118421308Sache { 118521308Sache rl_point = pos; 118675406Sache rl_ding (); 118721308Sache return -1; 118821308Sache } 118921308Sache } 119021308Sache 119121308Sache pos = rl_point; 119221308Sache 119321308Sache if (brack < 0) 119421308Sache { 119521308Sache while (count) 119621308Sache { 1197119610Sache tmp = pos; 1198119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1199119610Sache pos--; 1200119610Sache else 120121308Sache { 1202119610Sache pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); 1203119610Sache if (tmp == pos) 1204119610Sache pos--; 1205119610Sache } 1206119610Sache if (pos >= 0) 1207119610Sache { 120821308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 120921308Sache if (b == -brack) 121021308Sache count--; 121121308Sache else if (b == brack) 121221308Sache count++; 121321308Sache } 121421308Sache else 121521308Sache { 121675406Sache rl_ding (); 121721308Sache return -1; 121821308Sache } 121921308Sache } 122021308Sache } 122121308Sache else 122221308Sache { /* brack > 0 */ 122321308Sache while (count) 122421308Sache { 1225119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1226119610Sache pos++; 1227119610Sache else 1228119610Sache pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); 1229119610Sache 1230119610Sache if (pos < rl_end) 123121308Sache { 123221308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 123321308Sache if (b == -brack) 123421308Sache count--; 123521308Sache else if (b == brack) 123621308Sache count++; 123721308Sache } 123821308Sache else 123921308Sache { 124075406Sache rl_ding (); 124121308Sache return -1; 124221308Sache } 124321308Sache } 124421308Sache } 124521308Sache rl_point = pos; 124621308Sache return (0); 124721308Sache} 124821308Sache 124921308Sacheint 125021308Sacherl_vi_bracktype (c) 125121308Sache int c; 125221308Sache{ 125321308Sache switch (c) 125421308Sache { 125521308Sache case '(': return 1; 125621308Sache case ')': return -1; 125721308Sache case '[': return 2; 125821308Sache case ']': return -2; 125921308Sache case '{': return 3; 126021308Sache case '}': return -3; 126121308Sache default: return 0; 126221308Sache } 126321308Sache} 126421308Sache 1265119610Sache/* XXX - think about reading an entire mbchar with _rl_read_mbchar and 1266119610Sache inserting it in one bunch instead of the loop below (like in 1267119610Sache rl_vi_char_search or _rl_vi_change_mbchar_case. Set c to mbchar[0] 1268119610Sache for test against 033 or ^C. Make sure that _rl_read_mbchar does 1269119610Sache this right. */ 127021308Sacheint 127121308Sacherl_vi_change_char (count, key) 127221308Sache int count, key; 127321308Sache{ 127421308Sache int c; 127521308Sache 127621308Sache if (vi_redoing) 127721308Sache c = _rl_vi_last_replacement; 127821308Sache else 127975406Sache { 128075406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 128175406Sache _rl_vi_last_replacement = c = rl_read_key (); 128275406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 128375406Sache } 128421308Sache 128521308Sache if (c == '\033' || c == CTRL ('C')) 128621308Sache return -1; 128721308Sache 128821308Sache while (count-- && rl_point < rl_end) 128921308Sache { 129021308Sache rl_begin_undo_group (); 129121308Sache 129221308Sache rl_delete (1, c); 1293119610Sache#if defined (HANDLE_MULTIBYTE) 1294119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1295119610Sache while (_rl_insert_char (1, c)) 1296119610Sache { 1297119610Sache RL_SETSTATE (RL_STATE_MOREINPUT); 1298119610Sache c = rl_read_key (); 1299119610Sache RL_UNSETSTATE (RL_STATE_MOREINPUT); 1300119610Sache } 1301119610Sache else 1302119610Sache#endif 1303119610Sache _rl_insert_char (1, c); 130421308Sache if (count == 0) 1305119610Sache rl_backward_char (1, c); 130621308Sache 130721308Sache rl_end_undo_group (); 130821308Sache } 130921308Sache return (0); 131021308Sache} 131121308Sache 131221308Sacheint 131321308Sacherl_vi_subst (count, key) 131421308Sache int count, key; 131521308Sache{ 1316119610Sache /* If we are redoing, rl_vi_change_to will stuff the last motion char */ 1317119610Sache if (vi_redoing == 0) 1318119610Sache rl_stuff_char ((key == 'S') ? 'c' : ' '); /* `S' == `cc', `s' == `c ' */ 131921308Sache 1320119610Sache return (rl_vi_change_to (count, 'c')); 132121308Sache} 132221308Sache 132321308Sacheint 132421308Sacherl_vi_overstrike (count, key) 132521308Sache int count, key; 132621308Sache{ 132721308Sache if (_rl_vi_doing_insert == 0) 132821308Sache { 132921308Sache _rl_vi_doing_insert = 1; 133021308Sache rl_begin_undo_group (); 133121308Sache } 133221308Sache 1333119610Sache if (count > 0) 133421308Sache { 1335119610Sache _rl_overwrite_char (count, key); 1336119610Sache vi_replace_count += count; 1337119610Sache } 133821308Sache 133921308Sache return (0); 134021308Sache} 134121308Sache 134221308Sacheint 134321308Sacherl_vi_overstrike_delete (count, key) 134421308Sache int count, key; 134521308Sache{ 134621308Sache int i, s; 134721308Sache 134821308Sache for (i = 0; i < count; i++) 134921308Sache { 135021308Sache if (vi_replace_count == 0) 135121308Sache { 135275406Sache rl_ding (); 135321308Sache break; 135421308Sache } 135521308Sache s = rl_point; 135621308Sache 135721308Sache if (rl_do_undo ()) 135821308Sache vi_replace_count--; 135921308Sache 136021308Sache if (rl_point == s) 1361119610Sache rl_backward_char (1, key); 136221308Sache } 136321308Sache 136421308Sache if (vi_replace_count == 0 && _rl_vi_doing_insert) 136521308Sache { 136621308Sache rl_end_undo_group (); 136721308Sache rl_do_undo (); 136821308Sache _rl_vi_doing_insert = 0; 136921308Sache } 137021308Sache return (0); 137121308Sache} 137221308Sache 137321308Sacheint 137421308Sacherl_vi_replace (count, key) 137521308Sache int count, key; 137621308Sache{ 137721308Sache int i; 137821308Sache 137921308Sache vi_replace_count = 0; 138021308Sache 138121308Sache if (!vi_replace_map) 138221308Sache { 138321308Sache vi_replace_map = rl_make_bare_keymap (); 138421308Sache 138521308Sache for (i = ' '; i < KEYMAP_SIZE; i++) 138621308Sache vi_replace_map[i].function = rl_vi_overstrike; 138721308Sache 138821308Sache vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; 138921308Sache vi_replace_map[ESC].function = rl_vi_movement_mode; 139021308Sache vi_replace_map[RETURN].function = rl_newline; 139121308Sache vi_replace_map[NEWLINE].function = rl_newline; 139221308Sache 139321308Sache /* If the normal vi insertion keymap has ^H bound to erase, do the 139421308Sache same here. Probably should remove the assignment to RUBOUT up 139521308Sache there, but I don't think it will make a difference in real life. */ 139621308Sache if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && 139721308Sache vi_insertion_keymap[CTRL ('H')].function == rl_rubout) 139821308Sache vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; 139921308Sache 140021308Sache } 140121308Sache _rl_keymap = vi_replace_map; 140221308Sache return (0); 140321308Sache} 140421308Sache 140521308Sache#if 0 140621308Sache/* Try to complete the word we are standing on or the word that ends with 140721308Sache the previous character. A space matches everything. Word delimiters are 140821308Sache space and ;. */ 140921308Sacheint 141021308Sacherl_vi_possible_completions() 141121308Sache{ 141221308Sache int save_pos = rl_point; 141321308Sache 141421308Sache if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') 141521308Sache { 141621308Sache while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && 141721308Sache rl_line_buffer[rl_point] != ';') 141821308Sache rl_point++; 141921308Sache } 142021308Sache else if (rl_line_buffer[rl_point - 1] == ';') 142121308Sache { 142275406Sache rl_ding (); 142321308Sache return (0); 142421308Sache } 142521308Sache 142621308Sache rl_possible_completions (); 142721308Sache rl_point = save_pos; 142821308Sache 142921308Sache return (0); 143021308Sache} 143121308Sache#endif 143221308Sache 143321308Sache/* Functions to save and restore marks. */ 143421308Sacheint 143521308Sacherl_vi_set_mark (count, key) 143621308Sache int count, key; 143721308Sache{ 143821308Sache int ch; 143921308Sache 144075406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 144121308Sache ch = rl_read_key (); 144275406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 144375406Sache 1444119610Sache if (ch < 'a' || ch > 'z') 144521308Sache { 144675406Sache rl_ding (); 144721308Sache return -1; 144821308Sache } 144921308Sache ch -= 'a'; 145021308Sache vi_mark_chars[ch] = rl_point; 145121308Sache return 0; 145221308Sache} 145321308Sache 145421308Sacheint 145521308Sacherl_vi_goto_mark (count, key) 145621308Sache int count, key; 145721308Sache{ 145821308Sache int ch; 145921308Sache 146075406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 146121308Sache ch = rl_read_key (); 146275406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 146375406Sache 146421308Sache if (ch == '`') 146521308Sache { 146621308Sache rl_point = rl_mark; 146721308Sache return 0; 146821308Sache } 1469119610Sache else if (ch < 'a' || ch > 'z') 147021308Sache { 147175406Sache rl_ding (); 147221308Sache return -1; 147321308Sache } 147421308Sache 147521308Sache ch -= 'a'; 147621308Sache if (vi_mark_chars[ch] == -1) 147721308Sache { 147875406Sache rl_ding (); 147921308Sache return -1; 148021308Sache } 148121308Sache rl_point = vi_mark_chars[ch]; 148221308Sache return 0; 148321308Sache} 148421308Sache 148521308Sache#endif /* VI_MODE */ 1486