vi_mode.c revision 125665
1125665Sache/* $FreeBSD: head/contrib/libreadline/vi_mode.c 125665 2004-02-10 20:17:58Z ache $ */ 221308Sache/* vi_mode.c -- A vi emulation mode for Bash. 321308Sache Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ 421308Sache 521308Sache/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. 621308Sache 721308Sache This file is part of the GNU Readline Library, a library for 821308Sache reading lines of text with interactive input and history editing. 921308Sache 1021308Sache The GNU Readline Library is free software; you can redistribute it 1121308Sache and/or modify it under the terms of the GNU General Public License 1258310Sache as published by the Free Software Foundation; either version 2, or 1321308Sache (at your option) any later version. 1421308Sache 1521308Sache The GNU Readline Library is distributed in the hope that it will be 1621308Sache useful, but WITHOUT ANY WARRANTY; without even the implied warranty 1721308Sache of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1821308Sache GNU General Public License for more details. 1921308Sache 2021308Sache The GNU General Public License is often shipped with GNU software, and 2121308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2221308Sache have a copy of the license, write to the Free Software Foundation, 2358310Sache 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 2421308Sache#define READLINE_LIBRARY 2521308Sache 2621308Sache/* **************************************************************** */ 2721308Sache/* */ 2821308Sache/* VI Emulation Mode */ 2921308Sache/* */ 3021308Sache/* **************************************************************** */ 3121308Sache#include "rlconf.h" 3221308Sache 3321308Sache#if defined (VI_MODE) 3421308Sache 3521308Sache#if defined (HAVE_CONFIG_H) 3621308Sache# include <config.h> 3721308Sache#endif 3821308Sache 3921308Sache#include <sys/types.h> 4021308Sache 4121308Sache#if defined (HAVE_STDLIB_H) 4221308Sache# include <stdlib.h> 4321308Sache#else 4421308Sache# include "ansi_stdlib.h" 4521308Sache#endif /* HAVE_STDLIB_H */ 4621308Sache 4721308Sache#if defined (HAVE_UNISTD_H) 4821308Sache# include <unistd.h> 4921308Sache#endif 5021308Sache 5121308Sache#include <stdio.h> 5221308Sache 5321308Sache/* Some standard library routines. */ 5421308Sache#include "rldefs.h" 55119610Sache#include "rlmbutil.h" 56119610Sache 5721308Sache#include "readline.h" 5821308Sache#include "history.h" 5921308Sache 6058310Sache#include "rlprivate.h" 6158310Sache#include "xmalloc.h" 6258310Sache 6321308Sache#ifndef member 6421308Sache#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) 6521308Sache#endif 6621308Sache 6721308Sache/* Non-zero means enter insertion mode. */ 6821308Sachestatic int _rl_vi_doing_insert; 6921308Sache 7021308Sache/* Command keys which do movement for xxx_to commands. */ 71119610Sachestatic const char *vi_motion = " hl^$0ftFT;,%wbeWBE|"; 7221308Sache 7321308Sache/* Keymap used for vi replace characters. Created dynamically since 7421308Sache rarely used. */ 7521308Sachestatic Keymap vi_replace_map; 7621308Sache 7721308Sache/* The number of characters inserted in the last replace operation. */ 7821308Sachestatic int vi_replace_count; 7921308Sache 8021308Sache/* If non-zero, we have text inserted after a c[motion] command that put 8121308Sache us implicitly into insert mode. Some people want this text to be 8221308Sache attached to the command so that it is `redoable' with `.'. */ 8321308Sachestatic int vi_continued_command; 8421308Sachestatic char *vi_insert_buffer; 8521308Sachestatic int vi_insert_buffer_size; 8621308Sache 8721308Sachestatic int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ 8821308Sachestatic int _rl_vi_last_repeat = 1; 8921308Sachestatic int _rl_vi_last_arg_sign = 1; 9021308Sachestatic int _rl_vi_last_motion; 91119610Sache#if defined (HANDLE_MULTIBYTE) 92119610Sachestatic char _rl_vi_last_search_mbchar[MB_LEN_MAX]; 93119610Sache#else 9421308Sachestatic int _rl_vi_last_search_char; 95119610Sache#endif 9621308Sachestatic int _rl_vi_last_replacement; 9721308Sache 9821308Sachestatic int _rl_vi_last_key_before_insert; 9921308Sache 10021308Sachestatic int vi_redoing; 10121308Sache 10221308Sache/* Text modification commands. These are the `redoable' commands. */ 10375406Sachestatic const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; 10421308Sache 10521308Sache/* Arrays for the saved marks. */ 106119610Sachestatic int vi_mark_chars['z' - 'a' + 1]; 10721308Sache 108119610Sachestatic void _rl_vi_stuff_insert PARAMS((int)); 109119610Sachestatic void _rl_vi_save_insert PARAMS((UNDO_LIST *)); 110119610Sachestatic int rl_digit_loop1 PARAMS((void)); 11121308Sache 11221308Sachevoid 11321308Sache_rl_vi_initialize_line () 11421308Sache{ 11521308Sache register int i; 11621308Sache 11721308Sache for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) 11821308Sache vi_mark_chars[i] = -1; 11921308Sache} 12021308Sache 12121308Sachevoid 12221308Sache_rl_vi_reset_last () 12321308Sache{ 12421308Sache _rl_vi_last_command = 'i'; 12521308Sache _rl_vi_last_repeat = 1; 12621308Sache _rl_vi_last_arg_sign = 1; 12721308Sache _rl_vi_last_motion = 0; 12821308Sache} 12921308Sache 13021308Sachevoid 13121308Sache_rl_vi_set_last (key, repeat, sign) 13221308Sache int key, repeat, sign; 13321308Sache{ 13421308Sache _rl_vi_last_command = key; 13521308Sache _rl_vi_last_repeat = repeat; 13621308Sache _rl_vi_last_arg_sign = sign; 13721308Sache} 13821308Sache 13921308Sache/* Is the command C a VI mode text modification command? */ 14021308Sacheint 14121308Sache_rl_vi_textmod_command (c) 14221308Sache int c; 14321308Sache{ 14421308Sache return (member (c, vi_textmod)); 14521308Sache} 14621308Sache 14721308Sachestatic void 14821308Sache_rl_vi_stuff_insert (count) 14921308Sache int count; 15021308Sache{ 15121308Sache rl_begin_undo_group (); 15221308Sache while (count--) 15321308Sache rl_insert_text (vi_insert_buffer); 15421308Sache rl_end_undo_group (); 15521308Sache} 15621308Sache 15721308Sache/* Bound to `.'. Called from command mode, so we know that we have to 15821308Sache redo a text modification command. The default for _rl_vi_last_command 15921308Sache puts you back into insert mode. */ 16021308Sacheint 16121308Sacherl_vi_redo (count, c) 16221308Sache int count, c; 16321308Sache{ 164119610Sache int r; 165119610Sache 16621308Sache if (!rl_explicit_arg) 16721308Sache { 16821308Sache rl_numeric_arg = _rl_vi_last_repeat; 16921308Sache rl_arg_sign = _rl_vi_last_arg_sign; 17021308Sache } 17121308Sache 172119610Sache r = 0; 17321308Sache vi_redoing = 1; 17421308Sache /* If we're redoing an insert with `i', stuff in the inserted text 17521308Sache and do not go into insertion mode. */ 17621308Sache if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) 17721308Sache { 17821308Sache _rl_vi_stuff_insert (count); 17921308Sache /* And back up point over the last character inserted. */ 18021308Sache if (rl_point > 0) 18121308Sache rl_point--; 18221308Sache } 18321308Sache else 184119610Sache r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); 18521308Sache vi_redoing = 0; 18621308Sache 187119610Sache return (r); 18821308Sache} 18921308Sache 19021308Sache/* A placeholder for further expansion. */ 19121308Sacheint 19221308Sacherl_vi_undo (count, key) 19321308Sache int count, key; 19421308Sache{ 19521308Sache return (rl_undo_command (count, key)); 19621308Sache} 19721308Sache 19821308Sache/* Yank the nth arg from the previous line into this line at point. */ 19921308Sacheint 20021308Sacherl_vi_yank_arg (count, key) 20121308Sache int count, key; 20221308Sache{ 20321308Sache /* Readline thinks that the first word on a line is the 0th, while vi 20421308Sache thinks the first word on a line is the 1st. Compensate. */ 20521308Sache if (rl_explicit_arg) 20621308Sache rl_yank_nth_arg (count - 1, 0); 20721308Sache else 20821308Sache rl_yank_nth_arg ('$', 0); 20921308Sache 21021308Sache return (0); 21121308Sache} 21221308Sache 21321308Sache/* With an argument, move back that many history lines, else move to the 21421308Sache beginning of history. */ 21521308Sacheint 21621308Sacherl_vi_fetch_history (count, c) 21721308Sache int count, c; 21821308Sache{ 21921308Sache int wanted; 22021308Sache 22121308Sache /* Giving an argument of n means we want the nth command in the history 22221308Sache file. The command number is interpreted the same way that the bash 22321308Sache `history' command does it -- that is, giving an argument count of 450 22421308Sache to this command would get the command listed as number 450 in the 22521308Sache output of `history'. */ 22621308Sache if (rl_explicit_arg) 22721308Sache { 22821308Sache wanted = history_base + where_history () - count; 22921308Sache if (wanted <= 0) 23021308Sache rl_beginning_of_history (0, 0); 23121308Sache else 23221308Sache rl_get_previous_history (wanted, c); 23321308Sache } 23421308Sache else 23521308Sache rl_beginning_of_history (count, 0); 23621308Sache return (0); 23721308Sache} 23821308Sache 23921308Sache/* Search again for the last thing searched for. */ 24021308Sacheint 24121308Sacherl_vi_search_again (count, key) 24221308Sache int count, key; 24321308Sache{ 24421308Sache switch (key) 24521308Sache { 24621308Sache case 'n': 24721308Sache rl_noninc_reverse_search_again (count, key); 24821308Sache break; 24921308Sache 25021308Sache case 'N': 25121308Sache rl_noninc_forward_search_again (count, key); 25221308Sache break; 25321308Sache } 25421308Sache return (0); 25521308Sache} 25621308Sache 25721308Sache/* Do a vi style search. */ 25821308Sacheint 25921308Sacherl_vi_search (count, key) 26021308Sache int count, key; 26121308Sache{ 26221308Sache switch (key) 26321308Sache { 26421308Sache case '?': 26521308Sache rl_noninc_forward_search (count, key); 26621308Sache break; 26721308Sache 26821308Sache case '/': 26921308Sache rl_noninc_reverse_search (count, key); 27021308Sache break; 27121308Sache 27221308Sache default: 27375406Sache rl_ding (); 27421308Sache break; 27521308Sache } 27621308Sache return (0); 27721308Sache} 27821308Sache 27921308Sache/* Completion, from vi's point of view. */ 28021308Sacheint 28121308Sacherl_vi_complete (ignore, key) 28221308Sache int ignore, key; 28321308Sache{ 28421308Sache if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) 28521308Sache { 28621308Sache if (!whitespace (rl_line_buffer[rl_point + 1])) 28721308Sache rl_vi_end_word (1, 'E'); 28821308Sache rl_point++; 28921308Sache } 29021308Sache 29121308Sache if (key == '*') 29221308Sache rl_complete_internal ('*'); /* Expansion and replacement. */ 29321308Sache else if (key == '=') 29421308Sache rl_complete_internal ('?'); /* List possible completions. */ 29521308Sache else if (key == '\\') 29621308Sache rl_complete_internal (TAB); /* Standard Readline completion. */ 29721308Sache else 29821308Sache rl_complete (0, key); 29921308Sache 30021308Sache if (key == '*' || key == '\\') 30121308Sache { 30221308Sache _rl_vi_set_last (key, 1, rl_arg_sign); 30321308Sache rl_vi_insertion_mode (1, key); 30421308Sache } 30521308Sache return (0); 30621308Sache} 30721308Sache 30821308Sache/* Tilde expansion for vi mode. */ 30921308Sacheint 31021308Sacherl_vi_tilde_expand (ignore, key) 31121308Sache int ignore, key; 31221308Sache{ 31321308Sache rl_tilde_expand (0, key); 31421308Sache _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */ 31521308Sache rl_vi_insertion_mode (1, key); 31621308Sache return (0); 31721308Sache} 31821308Sache 31921308Sache/* Previous word in vi mode. */ 32021308Sacheint 32121308Sacherl_vi_prev_word (count, key) 32221308Sache int count, key; 32321308Sache{ 32421308Sache if (count < 0) 32521308Sache return (rl_vi_next_word (-count, key)); 32621308Sache 32721308Sache if (rl_point == 0) 32821308Sache { 32975406Sache rl_ding (); 33021308Sache return (0); 33121308Sache } 33221308Sache 33321308Sache if (_rl_uppercase_p (key)) 33447558Sache rl_vi_bWord (count, key); 33521308Sache else 33647558Sache rl_vi_bword (count, key); 33721308Sache 33821308Sache return (0); 33921308Sache} 34021308Sache 34121308Sache/* Next word in vi mode. */ 34221308Sacheint 34321308Sacherl_vi_next_word (count, key) 34421308Sache int count, key; 34521308Sache{ 34621308Sache if (count < 0) 34721308Sache return (rl_vi_prev_word (-count, key)); 34821308Sache 34921308Sache if (rl_point >= (rl_end - 1)) 35021308Sache { 35175406Sache rl_ding (); 35221308Sache return (0); 35321308Sache } 35421308Sache 35521308Sache if (_rl_uppercase_p (key)) 35647558Sache rl_vi_fWord (count, key); 35721308Sache else 35847558Sache rl_vi_fword (count, key); 35921308Sache return (0); 36021308Sache} 36121308Sache 36221308Sache/* Move to the end of the ?next? word. */ 36321308Sacheint 36421308Sacherl_vi_end_word (count, key) 36521308Sache int count, key; 36621308Sache{ 36721308Sache if (count < 0) 36821308Sache { 36975406Sache rl_ding (); 37021308Sache return -1; 37121308Sache } 37221308Sache 37321308Sache if (_rl_uppercase_p (key)) 37447558Sache rl_vi_eWord (count, key); 37521308Sache else 37647558Sache rl_vi_eword (count, key); 37721308Sache return (0); 37821308Sache} 37921308Sache 38021308Sache/* Move forward a word the way that 'W' does. */ 38121308Sacheint 38247558Sacherl_vi_fWord (count, ignore) 38347558Sache int count, ignore; 38421308Sache{ 38521308Sache while (count-- && rl_point < (rl_end - 1)) 38621308Sache { 38721308Sache /* Skip until whitespace. */ 38821308Sache while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 38921308Sache rl_point++; 39021308Sache 39121308Sache /* Now skip whitespace. */ 39221308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 39321308Sache rl_point++; 39421308Sache } 39521308Sache return (0); 39621308Sache} 39721308Sache 39821308Sacheint 39947558Sacherl_vi_bWord (count, ignore) 40047558Sache int count, ignore; 40121308Sache{ 40221308Sache while (count-- && rl_point > 0) 40321308Sache { 40421308Sache /* If we are at the start of a word, move back to whitespace so 40521308Sache we will go back to the start of the previous word. */ 40621308Sache if (!whitespace (rl_line_buffer[rl_point]) && 40721308Sache whitespace (rl_line_buffer[rl_point - 1])) 40821308Sache rl_point--; 40921308Sache 41021308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 41121308Sache rl_point--; 41221308Sache 41321308Sache if (rl_point > 0) 41421308Sache { 41521308Sache while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); 41621308Sache rl_point++; 41721308Sache } 41821308Sache } 41921308Sache return (0); 42021308Sache} 42121308Sache 42221308Sacheint 42347558Sacherl_vi_eWord (count, ignore) 42447558Sache int count, ignore; 42521308Sache{ 42621308Sache while (count-- && rl_point < (rl_end - 1)) 42721308Sache { 42821308Sache if (!whitespace (rl_line_buffer[rl_point])) 42921308Sache rl_point++; 43021308Sache 43121308Sache /* Move to the next non-whitespace character (to the start of the 43221308Sache next word). */ 43321308Sache while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point])); 43421308Sache 43521308Sache if (rl_point && rl_point < rl_end) 43621308Sache { 43721308Sache /* Skip whitespace. */ 43821308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 43921308Sache rl_point++; 44021308Sache 44121308Sache /* Skip until whitespace. */ 44221308Sache while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) 44321308Sache rl_point++; 44421308Sache 44521308Sache /* Move back to the last character of the word. */ 44621308Sache rl_point--; 44721308Sache } 44821308Sache } 44921308Sache return (0); 45021308Sache} 45121308Sache 45221308Sacheint 45347558Sacherl_vi_fword (count, ignore) 45447558Sache int count, ignore; 45521308Sache{ 45621308Sache while (count-- && rl_point < (rl_end - 1)) 45721308Sache { 45821308Sache /* Move to white space (really non-identifer). */ 459119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 46021308Sache { 461119610Sache while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) 46221308Sache rl_point++; 46321308Sache } 46421308Sache else /* if (!whitespace (rl_line_buffer[rl_point])) */ 46521308Sache { 466119610Sache while (!_rl_isident (rl_line_buffer[rl_point]) && 46721308Sache !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 46821308Sache rl_point++; 46921308Sache } 47021308Sache 47121308Sache /* Move past whitespace. */ 47221308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 47321308Sache rl_point++; 47421308Sache } 47521308Sache return (0); 47621308Sache} 47721308Sache 47821308Sacheint 47947558Sacherl_vi_bword (count, ignore) 48047558Sache int count, ignore; 48121308Sache{ 48221308Sache while (count-- && rl_point > 0) 48321308Sache { 48421308Sache int last_is_ident; 48521308Sache 48621308Sache /* If we are at the start of a word, move back to whitespace 48721308Sache so we will go back to the start of the previous word. */ 48821308Sache if (!whitespace (rl_line_buffer[rl_point]) && 48921308Sache whitespace (rl_line_buffer[rl_point - 1])) 49021308Sache rl_point--; 49121308Sache 49221308Sache /* If this character and the previous character are `opposite', move 49321308Sache back so we don't get messed up by the rl_point++ down there in 49421308Sache the while loop. Without this code, words like `l;' screw up the 49521308Sache function. */ 496119610Sache last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]); 497119610Sache if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || 498119610Sache (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident)) 49921308Sache rl_point--; 50021308Sache 50121308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 50221308Sache rl_point--; 50321308Sache 50421308Sache if (rl_point > 0) 50521308Sache { 506119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 507119610Sache while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); 50821308Sache else 509119610Sache while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && 51021308Sache !whitespace (rl_line_buffer[rl_point])); 51121308Sache rl_point++; 51221308Sache } 51321308Sache } 51421308Sache return (0); 51521308Sache} 51621308Sache 51721308Sacheint 51847558Sacherl_vi_eword (count, ignore) 51947558Sache int count, ignore; 52021308Sache{ 52121308Sache while (count-- && rl_point < rl_end - 1) 52221308Sache { 52321308Sache if (!whitespace (rl_line_buffer[rl_point])) 52421308Sache rl_point++; 52521308Sache 52621308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 52721308Sache rl_point++; 52821308Sache 52921308Sache if (rl_point < rl_end) 53021308Sache { 531119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 532119610Sache while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); 53321308Sache else 534119610Sache while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) 53521308Sache && !whitespace (rl_line_buffer[rl_point])); 53621308Sache } 53721308Sache rl_point--; 53821308Sache } 53921308Sache return (0); 54021308Sache} 54121308Sache 54221308Sacheint 54321308Sacherl_vi_insert_beg (count, key) 54421308Sache int count, key; 54521308Sache{ 54621308Sache rl_beg_of_line (1, key); 54721308Sache rl_vi_insertion_mode (1, key); 54821308Sache return (0); 54921308Sache} 55021308Sache 55121308Sacheint 55221308Sacherl_vi_append_mode (count, key) 55321308Sache int count, key; 55421308Sache{ 55521308Sache if (rl_point < rl_end) 556119610Sache { 557119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 558119610Sache rl_point++; 559119610Sache else 560119610Sache { 561119610Sache int point = rl_point; 562119610Sache rl_forward_char (1, key); 563119610Sache if (point == rl_point) 564119610Sache rl_point = rl_end; 565119610Sache } 566119610Sache } 56721308Sache rl_vi_insertion_mode (1, key); 56821308Sache return (0); 56921308Sache} 57021308Sache 57121308Sacheint 57221308Sacherl_vi_append_eol (count, key) 57321308Sache int count, key; 57421308Sache{ 57521308Sache rl_end_of_line (1, key); 57621308Sache rl_vi_append_mode (1, key); 57721308Sache return (0); 57821308Sache} 57921308Sache 58021308Sache/* What to do in the case of C-d. */ 58121308Sacheint 58221308Sacherl_vi_eof_maybe (count, c) 58321308Sache int count, c; 58421308Sache{ 58521308Sache return (rl_newline (1, '\n')); 58621308Sache} 58721308Sache 58821308Sache/* Insertion mode stuff. */ 58921308Sache 59021308Sache/* Switching from one mode to the other really just involves 59121308Sache switching keymaps. */ 59221308Sacheint 59321308Sacherl_vi_insertion_mode (count, key) 59421308Sache int count, key; 59521308Sache{ 59621308Sache _rl_keymap = vi_insertion_keymap; 59721308Sache _rl_vi_last_key_before_insert = key; 59821308Sache return (0); 59921308Sache} 60021308Sache 60121308Sachestatic void 60221308Sache_rl_vi_save_insert (up) 60321308Sache UNDO_LIST *up; 60421308Sache{ 60521308Sache int len, start, end; 60621308Sache 60735486Sache if (up == 0) 60835486Sache { 60935486Sache if (vi_insert_buffer_size >= 1) 61035486Sache vi_insert_buffer[0] = '\0'; 61135486Sache return; 61235486Sache } 61335486Sache 61421308Sache start = up->start; 61521308Sache end = up->end; 61621308Sache len = end - start + 1; 61721308Sache if (len >= vi_insert_buffer_size) 61821308Sache { 61921308Sache vi_insert_buffer_size += (len + 32) - (len % 32); 620119610Sache vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); 62121308Sache } 62221308Sache strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); 62321308Sache vi_insert_buffer[len-1] = '\0'; 62421308Sache} 62521308Sache 62621308Sachevoid 62721308Sache_rl_vi_done_inserting () 62821308Sache{ 62921308Sache if (_rl_vi_doing_insert) 63021308Sache { 631119610Sache /* The `C', `s', and `S' commands set this. */ 63221308Sache rl_end_undo_group (); 63321308Sache /* Now, the text between rl_undo_list->next->start and 63421308Sache rl_undo_list->next->end is what was inserted while in insert 63521308Sache mode. It gets copied to VI_INSERT_BUFFER because it depends 63621308Sache on absolute indices into the line which may change (though they 63721308Sache probably will not). */ 63821308Sache _rl_vi_doing_insert = 0; 63921308Sache _rl_vi_save_insert (rl_undo_list->next); 64021308Sache vi_continued_command = 1; 64121308Sache } 64221308Sache else 64321308Sache { 64421308Sache if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list) 64521308Sache _rl_vi_save_insert (rl_undo_list); 64621308Sache /* XXX - Other keys probably need to be checked. */ 64721308Sache else if (_rl_vi_last_key_before_insert == 'C') 64821308Sache rl_end_undo_group (); 64921308Sache while (_rl_undo_group_level > 0) 65021308Sache rl_end_undo_group (); 65121308Sache vi_continued_command = 0; 65221308Sache } 65321308Sache} 65421308Sache 65521308Sacheint 65621308Sacherl_vi_movement_mode (count, key) 65721308Sache int count, key; 65821308Sache{ 65921308Sache if (rl_point > 0) 660119610Sache rl_backward_char (1, key); 66121308Sache 66221308Sache _rl_keymap = vi_movement_keymap; 66321308Sache _rl_vi_done_inserting (); 66421308Sache return (0); 66521308Sache} 66621308Sache 66721308Sacheint 66821308Sacherl_vi_arg_digit (count, c) 66921308Sache int count, c; 67021308Sache{ 67121308Sache if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) 67221308Sache return (rl_beg_of_line (1, c)); 67321308Sache else 67421308Sache return (rl_digit_argument (count, c)); 67521308Sache} 67621308Sache 677119610Sache/* Change the case of the next COUNT characters. */ 678119610Sache#if defined (HANDLE_MULTIBYTE) 679119610Sachestatic int 680119610Sache_rl_vi_change_mbchar_case (count) 681119610Sache int count; 682119610Sache{ 683119610Sache wchar_t wc; 684125665Sache char mb[MB_LEN_MAX+1]; 685125665Sache int mblen; 686119610Sache mbstate_t ps; 687119610Sache 688119610Sache memset (&ps, 0, sizeof (mbstate_t)); 689119610Sache if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) 690119610Sache count--; 691119610Sache while (count-- && rl_point < rl_end) 692119610Sache { 693119610Sache mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); 694119610Sache if (iswupper (wc)) 695119610Sache wc = towlower (wc); 696119610Sache else if (iswlower (wc)) 697119610Sache wc = towupper (wc); 698119610Sache else 699119610Sache { 700119610Sache /* Just skip over chars neither upper nor lower case */ 701119610Sache rl_forward_char (1, 0); 702119610Sache continue; 703119610Sache } 704119610Sache 705119610Sache /* Vi is kind of strange here. */ 706119610Sache if (wc) 707119610Sache { 708125665Sache mblen = wctomb (mb, wc); 709125665Sache if (mblen >= 0) 710125665Sache mb[mblen] = '\0'; 711119610Sache rl_begin_undo_group (); 712119610Sache rl_delete (1, 0); 713119610Sache rl_insert_text (mb); 714119610Sache rl_end_undo_group (); 715119610Sache rl_vi_check (); 716119610Sache } 717119610Sache else 718119610Sache rl_forward_char (1, 0); 719119610Sache } 720119610Sache 721119610Sache return 0; 722119610Sache} 723119610Sache#endif 724119610Sache 72521308Sacheint 72621308Sacherl_vi_change_case (count, ignore) 72721308Sache int count, ignore; 72821308Sache{ 72921308Sache char c = 0; 73021308Sache 73121308Sache /* Don't try this on an empty line. */ 73221308Sache if (rl_point >= rl_end) 73321308Sache return (0); 73421308Sache 735119610Sache#if defined (HANDLE_MULTIBYTE) 736119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 737119610Sache return (_rl_vi_change_mbchar_case (count)); 738119610Sache#endif 739119610Sache 74021308Sache while (count-- && rl_point < rl_end) 74121308Sache { 74221308Sache if (_rl_uppercase_p (rl_line_buffer[rl_point])) 74321308Sache c = _rl_to_lower (rl_line_buffer[rl_point]); 74421308Sache else if (_rl_lowercase_p (rl_line_buffer[rl_point])) 74521308Sache c = _rl_to_upper (rl_line_buffer[rl_point]); 74621308Sache else 74721308Sache { 74821308Sache /* Just skip over characters neither upper nor lower case. */ 749119610Sache rl_forward_char (1, c); 75021308Sache continue; 75121308Sache } 75221308Sache 75321308Sache /* Vi is kind of strange here. */ 75421308Sache if (c) 75521308Sache { 75621308Sache rl_begin_undo_group (); 75721308Sache rl_delete (1, c); 758119610Sache _rl_insert_char (1, c); 75921308Sache rl_end_undo_group (); 76021308Sache rl_vi_check (); 76121308Sache } 76221308Sache else 763119610Sache rl_forward_char (1, c); 76421308Sache } 76521308Sache return (0); 76621308Sache} 76721308Sache 76821308Sacheint 76921308Sacherl_vi_put (count, key) 77021308Sache int count, key; 77121308Sache{ 77221308Sache if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) 773119610Sache rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); 77421308Sache 77547558Sache rl_yank (1, key); 776119610Sache rl_backward_char (1, key); 77721308Sache return (0); 77821308Sache} 77921308Sache 78021308Sacheint 78121308Sacherl_vi_check () 78221308Sache{ 78321308Sache if (rl_point && rl_point == rl_end) 784119610Sache { 785119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 786119610Sache rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 787119610Sache else 788119610Sache rl_point--; 789119610Sache } 79021308Sache return (0); 79121308Sache} 79221308Sache 79321308Sacheint 79421308Sacherl_vi_column (count, key) 79521308Sache int count, key; 79621308Sache{ 79721308Sache if (count > rl_end) 79821308Sache rl_end_of_line (1, key); 79921308Sache else 80021308Sache rl_point = count - 1; 80121308Sache return (0); 80221308Sache} 80321308Sache 80421308Sacheint 80521308Sacherl_vi_domove (key, nextkey) 80621308Sache int key, *nextkey; 80721308Sache{ 80821308Sache int c, save; 80921308Sache int old_end; 81021308Sache 81121308Sache rl_mark = rl_point; 81275406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 81321308Sache c = rl_read_key (); 81475406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 81521308Sache *nextkey = c; 81621308Sache 81721308Sache if (!member (c, vi_motion)) 81821308Sache { 81921308Sache if (_rl_digit_p (c)) 82021308Sache { 82121308Sache save = rl_numeric_arg; 82221308Sache rl_numeric_arg = _rl_digit_value (c); 82321308Sache rl_digit_loop1 (); 82421308Sache rl_numeric_arg *= save; 82575406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 82621308Sache c = rl_read_key (); /* real command */ 82775406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 82821308Sache *nextkey = c; 82921308Sache } 83021308Sache else if (key == c && (key == 'd' || key == 'y' || key == 'c')) 83121308Sache { 83221308Sache rl_mark = rl_end; 83321308Sache rl_beg_of_line (1, c); 83421308Sache _rl_vi_last_motion = c; 83521308Sache return (0); 83621308Sache } 83721308Sache else 83821308Sache return (-1); 83921308Sache } 84021308Sache 84121308Sache _rl_vi_last_motion = c; 84221308Sache 84321308Sache /* Append a blank character temporarily so that the motion routines 84421308Sache work right at the end of the line. */ 84521308Sache old_end = rl_end; 84621308Sache rl_line_buffer[rl_end++] = ' '; 84721308Sache rl_line_buffer[rl_end] = '\0'; 84821308Sache 84921308Sache _rl_dispatch (c, _rl_keymap); 85021308Sache 85121308Sache /* Remove the blank that we added. */ 85221308Sache rl_end = old_end; 85321308Sache rl_line_buffer[rl_end] = '\0'; 85421308Sache if (rl_point > rl_end) 85521308Sache rl_point = rl_end; 85621308Sache 85721308Sache /* No change in position means the command failed. */ 85821308Sache if (rl_mark == rl_point) 85921308Sache return (-1); 86021308Sache 86121308Sache /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next 86221308Sache word. If we are not at the end of the line, and we are on a 86321308Sache non-whitespace character, move back one (presumably to whitespace). */ 86421308Sache if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && 86521308Sache !whitespace (rl_line_buffer[rl_point])) 86621308Sache rl_point--; 86721308Sache 86821308Sache /* If cw or cW, back up to the end of a word, so the behaviour of ce 86921308Sache or cE is the actual result. Brute-force, no subtlety. */ 87021308Sache if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) 87121308Sache { 87221308Sache /* Don't move farther back than where we started. */ 87321308Sache while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) 87421308Sache rl_point--; 87521308Sache 87621308Sache /* Posix.2 says that if cw or cW moves the cursor towards the end of 87721308Sache the line, the character under the cursor should be deleted. */ 87821308Sache if (rl_point == rl_mark) 87921308Sache rl_point++; 88021308Sache else 88121308Sache { 88221308Sache /* Move past the end of the word so that the kill doesn't 88321308Sache remove the last letter of the previous word. Only do this 88421308Sache if we are not at the end of the line. */ 88521308Sache if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) 88621308Sache rl_point++; 88721308Sache } 88821308Sache } 88921308Sache 89021308Sache if (rl_mark < rl_point) 891119610Sache SWAP (rl_point, rl_mark); 89221308Sache 89321308Sache return (0); 89421308Sache} 89521308Sache 89621308Sache/* A simplified loop for vi. Don't dispatch key at end. 89775406Sache Don't recognize minus sign? 89875406Sache Should this do rl_save_prompt/rl_restore_prompt? */ 89921308Sachestatic int 90021308Sacherl_digit_loop1 () 90121308Sache{ 90221308Sache int key, c; 90321308Sache 90475406Sache RL_SETSTATE(RL_STATE_NUMERICARG); 90521308Sache while (1) 90621308Sache { 90775406Sache if (rl_numeric_arg > 1000000) 90875406Sache { 90975406Sache rl_explicit_arg = rl_numeric_arg = 0; 91075406Sache rl_ding (); 91175406Sache rl_clear_message (); 91275406Sache RL_UNSETSTATE(RL_STATE_NUMERICARG); 91375406Sache return 1; 91475406Sache } 915119610Sache rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); 91675406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 91721308Sache key = c = rl_read_key (); 91875406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 91921308Sache 920119610Sache if (c >= 0 && _rl_keymap[c].type == ISFUNC && 92121308Sache _rl_keymap[c].function == rl_universal_argument) 92221308Sache { 92321308Sache rl_numeric_arg *= 4; 92421308Sache continue; 92521308Sache } 92621308Sache 92721308Sache c = UNMETA (c); 92821308Sache if (_rl_digit_p (c)) 92921308Sache { 93021308Sache if (rl_explicit_arg) 93121308Sache rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); 93221308Sache else 93321308Sache rl_numeric_arg = _rl_digit_value (c); 93421308Sache rl_explicit_arg = 1; 93521308Sache } 93621308Sache else 93721308Sache { 93821308Sache rl_clear_message (); 93921308Sache rl_stuff_char (key); 94021308Sache break; 94121308Sache } 94221308Sache } 94375406Sache 94475406Sache RL_UNSETSTATE(RL_STATE_NUMERICARG); 94521308Sache return (0); 94621308Sache} 94721308Sache 94821308Sacheint 94921308Sacherl_vi_delete_to (count, key) 95021308Sache int count, key; 95121308Sache{ 95221308Sache int c; 95321308Sache 95421308Sache if (_rl_uppercase_p (key)) 95521308Sache rl_stuff_char ('$'); 95621308Sache else if (vi_redoing) 95721308Sache rl_stuff_char (_rl_vi_last_motion); 95821308Sache 95921308Sache if (rl_vi_domove (key, &c)) 96021308Sache { 96175406Sache rl_ding (); 96221308Sache return -1; 96321308Sache } 96421308Sache 96521308Sache /* These are the motion commands that do not require adjusting the 96621308Sache mark. */ 96721308Sache if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) 96821308Sache rl_mark++; 96921308Sache 97021308Sache rl_kill_text (rl_point, rl_mark); 97121308Sache return (0); 97221308Sache} 97321308Sache 97421308Sacheint 97521308Sacherl_vi_change_to (count, key) 97621308Sache int count, key; 97721308Sache{ 97821308Sache int c, start_pos; 97921308Sache 98021308Sache if (_rl_uppercase_p (key)) 98121308Sache rl_stuff_char ('$'); 98221308Sache else if (vi_redoing) 98321308Sache rl_stuff_char (_rl_vi_last_motion); 98421308Sache 98521308Sache start_pos = rl_point; 98621308Sache 98721308Sache if (rl_vi_domove (key, &c)) 98821308Sache { 98975406Sache rl_ding (); 99021308Sache return -1; 99121308Sache } 99221308Sache 99321308Sache /* These are the motion commands that do not require adjusting the 99421308Sache mark. c[wW] are handled by special-case code in rl_vi_domove(), 99521308Sache and already leave the mark at the correct location. */ 99621308Sache if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) 99721308Sache rl_mark++; 99821308Sache 99921308Sache /* The cursor never moves with c[wW]. */ 100021308Sache if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) 100121308Sache rl_point = start_pos; 100221308Sache 100321308Sache if (vi_redoing) 100421308Sache { 100521308Sache if (vi_insert_buffer && *vi_insert_buffer) 100621308Sache rl_begin_undo_group (); 100721308Sache rl_delete_text (rl_point, rl_mark); 100821308Sache if (vi_insert_buffer && *vi_insert_buffer) 100921308Sache { 101021308Sache rl_insert_text (vi_insert_buffer); 101121308Sache rl_end_undo_group (); 101221308Sache } 101321308Sache } 101421308Sache else 101521308Sache { 101621308Sache rl_begin_undo_group (); /* to make the `u' command work */ 101721308Sache rl_kill_text (rl_point, rl_mark); 101821308Sache /* `C' does not save the text inserted for undoing or redoing. */ 101921308Sache if (_rl_uppercase_p (key) == 0) 102021308Sache _rl_vi_doing_insert = 1; 102121308Sache _rl_vi_set_last (key, count, rl_arg_sign); 102221308Sache rl_vi_insertion_mode (1, key); 102321308Sache } 102421308Sache 102521308Sache return (0); 102621308Sache} 102721308Sache 102821308Sacheint 102921308Sacherl_vi_yank_to (count, key) 103021308Sache int count, key; 103121308Sache{ 103221308Sache int c, save = rl_point; 103321308Sache 103421308Sache if (_rl_uppercase_p (key)) 103521308Sache rl_stuff_char ('$'); 103621308Sache 103721308Sache if (rl_vi_domove (key, &c)) 103821308Sache { 103975406Sache rl_ding (); 104021308Sache return -1; 104121308Sache } 104221308Sache 104321308Sache /* These are the motion commands that do not require adjusting the 104421308Sache mark. */ 104521308Sache if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) 104621308Sache rl_mark++; 104721308Sache 104821308Sache rl_begin_undo_group (); 104921308Sache rl_kill_text (rl_point, rl_mark); 105021308Sache rl_end_undo_group (); 105121308Sache rl_do_undo (); 105221308Sache rl_point = save; 105321308Sache 105421308Sache return (0); 105521308Sache} 105621308Sache 105721308Sacheint 105821308Sacherl_vi_delete (count, key) 105921308Sache int count, key; 106021308Sache{ 106121308Sache int end; 106221308Sache 106321308Sache if (rl_end == 0) 106421308Sache { 106575406Sache rl_ding (); 106621308Sache return -1; 106721308Sache } 106821308Sache 1069119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1070119610Sache end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); 1071119610Sache else 1072119610Sache end = rl_point + count; 107321308Sache 107421308Sache if (end >= rl_end) 107521308Sache end = rl_end; 107621308Sache 107721308Sache rl_kill_text (rl_point, end); 107821308Sache 107921308Sache if (rl_point > 0 && rl_point == rl_end) 1080119610Sache rl_backward_char (1, key); 108121308Sache return (0); 108221308Sache} 108321308Sache 108421308Sacheint 108521308Sacherl_vi_back_to_indent (count, key) 108621308Sache int count, key; 108721308Sache{ 108821308Sache rl_beg_of_line (1, key); 108921308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 109021308Sache rl_point++; 109121308Sache return (0); 109221308Sache} 109321308Sache 109421308Sacheint 109521308Sacherl_vi_first_print (count, key) 109621308Sache int count, key; 109721308Sache{ 109821308Sache return (rl_vi_back_to_indent (1, key)); 109921308Sache} 110021308Sache 110121308Sacheint 110221308Sacherl_vi_char_search (count, key) 110321308Sache int count, key; 110421308Sache{ 1105119610Sache#if defined (HANDLE_MULTIBYTE) 1106119610Sache static char *target; 1107119610Sache static int mb_len; 1108119610Sache#else 110921308Sache static char target; 1110119610Sache#endif 111121308Sache static int orig_dir, dir; 111221308Sache 111321308Sache if (key == ';' || key == ',') 111421308Sache dir = key == ';' ? orig_dir : -orig_dir; 111521308Sache else 111621308Sache { 111721308Sache if (vi_redoing) 1118119610Sache#if defined (HANDLE_MULTIBYTE) 1119119610Sache target = _rl_vi_last_search_mbchar; 1120119610Sache#else 112121308Sache target = _rl_vi_last_search_char; 1122119610Sache#endif 112321308Sache else 112475406Sache { 1125119610Sache#if defined (HANDLE_MULTIBYTE) 1126119610Sache mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1127119610Sache target = _rl_vi_last_search_mbchar; 1128119610Sache#else 112975406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 113075406Sache _rl_vi_last_search_char = target = rl_read_key (); 113175406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 1132119610Sache#endif 113375406Sache } 113421308Sache 113521308Sache switch (key) 113621308Sache { 113721308Sache case 't': 113821308Sache orig_dir = dir = FTO; 113921308Sache break; 114021308Sache 114121308Sache case 'T': 114221308Sache orig_dir = dir = BTO; 114321308Sache break; 114421308Sache 114521308Sache case 'f': 114621308Sache orig_dir = dir = FFIND; 114721308Sache break; 114821308Sache 114921308Sache case 'F': 115021308Sache orig_dir = dir = BFIND; 115121308Sache break; 115221308Sache } 115321308Sache } 115421308Sache 1155119610Sache#if defined (HANDLE_MULTIBYTE) 1156119610Sache return (_rl_char_search_internal (count, dir, target, mb_len)); 1157119610Sache#else 115821308Sache return (_rl_char_search_internal (count, dir, target)); 1159119610Sache#endif 116021308Sache} 116121308Sache 116221308Sache/* Match brackets */ 116321308Sacheint 116421308Sacherl_vi_match (ignore, key) 116521308Sache int ignore, key; 116621308Sache{ 1167119610Sache int count = 1, brack, pos, tmp, pre; 116821308Sache 116921308Sache pos = rl_point; 117021308Sache if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 117121308Sache { 1172119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1173119610Sache { 1174119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1175119610Sache { 1176119610Sache pre = rl_point; 1177119610Sache rl_forward_char (1, key); 1178119610Sache if (pre == rl_point) 1179119610Sache break; 1180119610Sache } 1181119610Sache } 1182119610Sache else 1183119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && 1184119610Sache rl_point < rl_end - 1) 1185119610Sache rl_forward_char (1, key); 118621308Sache 118721308Sache if (brack <= 0) 118821308Sache { 118921308Sache rl_point = pos; 119075406Sache rl_ding (); 119121308Sache return -1; 119221308Sache } 119321308Sache } 119421308Sache 119521308Sache pos = rl_point; 119621308Sache 119721308Sache if (brack < 0) 119821308Sache { 119921308Sache while (count) 120021308Sache { 1201119610Sache tmp = pos; 1202119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1203119610Sache pos--; 1204119610Sache else 120521308Sache { 1206119610Sache pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); 1207119610Sache if (tmp == pos) 1208119610Sache pos--; 1209119610Sache } 1210119610Sache if (pos >= 0) 1211119610Sache { 121221308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 121321308Sache if (b == -brack) 121421308Sache count--; 121521308Sache else if (b == brack) 121621308Sache count++; 121721308Sache } 121821308Sache else 121921308Sache { 122075406Sache rl_ding (); 122121308Sache return -1; 122221308Sache } 122321308Sache } 122421308Sache } 122521308Sache else 122621308Sache { /* brack > 0 */ 122721308Sache while (count) 122821308Sache { 1229119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1230119610Sache pos++; 1231119610Sache else 1232119610Sache pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); 1233119610Sache 1234119610Sache if (pos < rl_end) 123521308Sache { 123621308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 123721308Sache if (b == -brack) 123821308Sache count--; 123921308Sache else if (b == brack) 124021308Sache count++; 124121308Sache } 124221308Sache else 124321308Sache { 124475406Sache rl_ding (); 124521308Sache return -1; 124621308Sache } 124721308Sache } 124821308Sache } 124921308Sache rl_point = pos; 125021308Sache return (0); 125121308Sache} 125221308Sache 125321308Sacheint 125421308Sacherl_vi_bracktype (c) 125521308Sache int c; 125621308Sache{ 125721308Sache switch (c) 125821308Sache { 125921308Sache case '(': return 1; 126021308Sache case ')': return -1; 126121308Sache case '[': return 2; 126221308Sache case ']': return -2; 126321308Sache case '{': return 3; 126421308Sache case '}': return -3; 126521308Sache default: return 0; 126621308Sache } 126721308Sache} 126821308Sache 1269119610Sache/* XXX - think about reading an entire mbchar with _rl_read_mbchar and 1270119610Sache inserting it in one bunch instead of the loop below (like in 1271119610Sache rl_vi_char_search or _rl_vi_change_mbchar_case. Set c to mbchar[0] 1272119610Sache for test against 033 or ^C. Make sure that _rl_read_mbchar does 1273119610Sache this right. */ 127421308Sacheint 127521308Sacherl_vi_change_char (count, key) 127621308Sache int count, key; 127721308Sache{ 127821308Sache int c; 127921308Sache 128021308Sache if (vi_redoing) 128121308Sache c = _rl_vi_last_replacement; 128221308Sache else 128375406Sache { 128475406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 128575406Sache _rl_vi_last_replacement = c = rl_read_key (); 128675406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 128775406Sache } 128821308Sache 128921308Sache if (c == '\033' || c == CTRL ('C')) 129021308Sache return -1; 129121308Sache 129221308Sache while (count-- && rl_point < rl_end) 129321308Sache { 129421308Sache rl_begin_undo_group (); 129521308Sache 129621308Sache rl_delete (1, c); 1297119610Sache#if defined (HANDLE_MULTIBYTE) 1298119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1299119610Sache while (_rl_insert_char (1, c)) 1300119610Sache { 1301119610Sache RL_SETSTATE (RL_STATE_MOREINPUT); 1302119610Sache c = rl_read_key (); 1303119610Sache RL_UNSETSTATE (RL_STATE_MOREINPUT); 1304119610Sache } 1305119610Sache else 1306119610Sache#endif 1307119610Sache _rl_insert_char (1, c); 130821308Sache if (count == 0) 1309119610Sache rl_backward_char (1, c); 131021308Sache 131121308Sache rl_end_undo_group (); 131221308Sache } 131321308Sache return (0); 131421308Sache} 131521308Sache 131621308Sacheint 131721308Sacherl_vi_subst (count, key) 131821308Sache int count, key; 131921308Sache{ 1320119610Sache /* If we are redoing, rl_vi_change_to will stuff the last motion char */ 1321119610Sache if (vi_redoing == 0) 1322119610Sache rl_stuff_char ((key == 'S') ? 'c' : ' '); /* `S' == `cc', `s' == `c ' */ 132321308Sache 1324119610Sache return (rl_vi_change_to (count, 'c')); 132521308Sache} 132621308Sache 132721308Sacheint 132821308Sacherl_vi_overstrike (count, key) 132921308Sache int count, key; 133021308Sache{ 133121308Sache if (_rl_vi_doing_insert == 0) 133221308Sache { 133321308Sache _rl_vi_doing_insert = 1; 133421308Sache rl_begin_undo_group (); 133521308Sache } 133621308Sache 1337119610Sache if (count > 0) 133821308Sache { 1339119610Sache _rl_overwrite_char (count, key); 1340119610Sache vi_replace_count += count; 1341119610Sache } 134221308Sache 134321308Sache return (0); 134421308Sache} 134521308Sache 134621308Sacheint 134721308Sacherl_vi_overstrike_delete (count, key) 134821308Sache int count, key; 134921308Sache{ 135021308Sache int i, s; 135121308Sache 135221308Sache for (i = 0; i < count; i++) 135321308Sache { 135421308Sache if (vi_replace_count == 0) 135521308Sache { 135675406Sache rl_ding (); 135721308Sache break; 135821308Sache } 135921308Sache s = rl_point; 136021308Sache 136121308Sache if (rl_do_undo ()) 136221308Sache vi_replace_count--; 136321308Sache 136421308Sache if (rl_point == s) 1365119610Sache rl_backward_char (1, key); 136621308Sache } 136721308Sache 136821308Sache if (vi_replace_count == 0 && _rl_vi_doing_insert) 136921308Sache { 137021308Sache rl_end_undo_group (); 137121308Sache rl_do_undo (); 137221308Sache _rl_vi_doing_insert = 0; 137321308Sache } 137421308Sache return (0); 137521308Sache} 137621308Sache 137721308Sacheint 137821308Sacherl_vi_replace (count, key) 137921308Sache int count, key; 138021308Sache{ 138121308Sache int i; 138221308Sache 138321308Sache vi_replace_count = 0; 138421308Sache 138521308Sache if (!vi_replace_map) 138621308Sache { 138721308Sache vi_replace_map = rl_make_bare_keymap (); 138821308Sache 138921308Sache for (i = ' '; i < KEYMAP_SIZE; i++) 139021308Sache vi_replace_map[i].function = rl_vi_overstrike; 139121308Sache 139221308Sache vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; 139321308Sache vi_replace_map[ESC].function = rl_vi_movement_mode; 139421308Sache vi_replace_map[RETURN].function = rl_newline; 139521308Sache vi_replace_map[NEWLINE].function = rl_newline; 139621308Sache 139721308Sache /* If the normal vi insertion keymap has ^H bound to erase, do the 139821308Sache same here. Probably should remove the assignment to RUBOUT up 139921308Sache there, but I don't think it will make a difference in real life. */ 140021308Sache if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && 140121308Sache vi_insertion_keymap[CTRL ('H')].function == rl_rubout) 140221308Sache vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; 140321308Sache 140421308Sache } 140521308Sache _rl_keymap = vi_replace_map; 140621308Sache return (0); 140721308Sache} 140821308Sache 140921308Sache#if 0 141021308Sache/* Try to complete the word we are standing on or the word that ends with 141121308Sache the previous character. A space matches everything. Word delimiters are 141221308Sache space and ;. */ 141321308Sacheint 141421308Sacherl_vi_possible_completions() 141521308Sache{ 141621308Sache int save_pos = rl_point; 141721308Sache 141821308Sache if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') 141921308Sache { 142021308Sache while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && 142121308Sache rl_line_buffer[rl_point] != ';') 142221308Sache rl_point++; 142321308Sache } 142421308Sache else if (rl_line_buffer[rl_point - 1] == ';') 142521308Sache { 142675406Sache rl_ding (); 142721308Sache return (0); 142821308Sache } 142921308Sache 143021308Sache rl_possible_completions (); 143121308Sache rl_point = save_pos; 143221308Sache 143321308Sache return (0); 143421308Sache} 143521308Sache#endif 143621308Sache 143721308Sache/* Functions to save and restore marks. */ 143821308Sacheint 143921308Sacherl_vi_set_mark (count, key) 144021308Sache int count, key; 144121308Sache{ 144221308Sache int ch; 144321308Sache 144475406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 144521308Sache ch = rl_read_key (); 144675406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 144775406Sache 1448119610Sache if (ch < 'a' || ch > 'z') 144921308Sache { 145075406Sache rl_ding (); 145121308Sache return -1; 145221308Sache } 145321308Sache ch -= 'a'; 145421308Sache vi_mark_chars[ch] = rl_point; 145521308Sache return 0; 145621308Sache} 145721308Sache 145821308Sacheint 145921308Sacherl_vi_goto_mark (count, key) 146021308Sache int count, key; 146121308Sache{ 146221308Sache int ch; 146321308Sache 146475406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 146521308Sache ch = rl_read_key (); 146675406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 146775406Sache 146821308Sache if (ch == '`') 146921308Sache { 147021308Sache rl_point = rl_mark; 147121308Sache return 0; 147221308Sache } 1473119610Sache else if (ch < 'a' || ch > 'z') 147421308Sache { 147575406Sache rl_ding (); 147621308Sache return -1; 147721308Sache } 147821308Sache 147921308Sache ch -= 'a'; 148021308Sache if (vi_mark_chars[ch] == -1) 148121308Sache { 148275406Sache rl_ding (); 148321308Sache return -1; 148421308Sache } 148521308Sache rl_point = vi_mark_chars[ch]; 148621308Sache return 0; 148721308Sache} 148821308Sache 148921308Sache#endif /* VI_MODE */ 1490