vi_mode.c revision 136759
1125665Sache/* $FreeBSD: head/contrib/libreadline/vi_mode.c 136759 2004-10-21 20:10:14Z peter $ */ 2136759Speter 321308Sache/* vi_mode.c -- A vi emulation mode for Bash. 421308Sache Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ 521308Sache 6136759Speter/* Copyright (C) 1987-2004 Free Software Foundation, Inc. 721308Sache 821308Sache This file is part of the GNU Readline Library, a library for 921308Sache reading lines of text with interactive input and history editing. 1021308Sache 1121308Sache The GNU Readline Library is free software; you can redistribute it 1221308Sache and/or modify it under the terms of the GNU General Public License 1358310Sache as published by the Free Software Foundation; either version 2, or 1421308Sache (at your option) any later version. 1521308Sache 1621308Sache The GNU Readline Library is distributed in the hope that it will be 1721308Sache useful, but WITHOUT ANY WARRANTY; without even the implied warranty 1821308Sache of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1921308Sache GNU General Public License for more details. 2021308Sache 2121308Sache The GNU General Public License is often shipped with GNU software, and 2221308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2321308Sache have a copy of the license, write to the Free Software Foundation, 2458310Sache 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 2521308Sache#define READLINE_LIBRARY 2621308Sache 2721308Sache/* **************************************************************** */ 2821308Sache/* */ 2921308Sache/* VI Emulation Mode */ 3021308Sache/* */ 3121308Sache/* **************************************************************** */ 3221308Sache#include "rlconf.h" 3321308Sache 3421308Sache#if defined (VI_MODE) 3521308Sache 3621308Sache#if defined (HAVE_CONFIG_H) 3721308Sache# include <config.h> 3821308Sache#endif 3921308Sache 4021308Sache#include <sys/types.h> 4121308Sache 4221308Sache#if defined (HAVE_STDLIB_H) 4321308Sache# include <stdlib.h> 4421308Sache#else 4521308Sache# include "ansi_stdlib.h" 4621308Sache#endif /* HAVE_STDLIB_H */ 4721308Sache 4821308Sache#if defined (HAVE_UNISTD_H) 4921308Sache# include <unistd.h> 5021308Sache#endif 5121308Sache 5221308Sache#include <stdio.h> 5321308Sache 5421308Sache/* Some standard library routines. */ 5521308Sache#include "rldefs.h" 56119610Sache#include "rlmbutil.h" 57119610Sache 5821308Sache#include "readline.h" 5921308Sache#include "history.h" 6021308Sache 6158310Sache#include "rlprivate.h" 6258310Sache#include "xmalloc.h" 6358310Sache 6421308Sache#ifndef member 6521308Sache#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) 6621308Sache#endif 6721308Sache 68136759Speterint _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ 69136759Speter 7021308Sache/* Non-zero means enter insertion mode. */ 7121308Sachestatic int _rl_vi_doing_insert; 7221308Sache 7321308Sache/* Command keys which do movement for xxx_to commands. */ 74119610Sachestatic const char *vi_motion = " hl^$0ftFT;,%wbeWBE|"; 7521308Sache 7621308Sache/* Keymap used for vi replace characters. Created dynamically since 7721308Sache rarely used. */ 7821308Sachestatic Keymap vi_replace_map; 7921308Sache 8021308Sache/* The number of characters inserted in the last replace operation. */ 8121308Sachestatic int vi_replace_count; 8221308Sache 8321308Sache/* If non-zero, we have text inserted after a c[motion] command that put 8421308Sache us implicitly into insert mode. Some people want this text to be 8521308Sache attached to the command so that it is `redoable' with `.'. */ 8621308Sachestatic int vi_continued_command; 8721308Sachestatic char *vi_insert_buffer; 8821308Sachestatic int vi_insert_buffer_size; 8921308Sache 9021308Sachestatic int _rl_vi_last_repeat = 1; 9121308Sachestatic int _rl_vi_last_arg_sign = 1; 9221308Sachestatic int _rl_vi_last_motion; 93119610Sache#if defined (HANDLE_MULTIBYTE) 94119610Sachestatic char _rl_vi_last_search_mbchar[MB_LEN_MAX]; 95119610Sache#else 9621308Sachestatic int _rl_vi_last_search_char; 97119610Sache#endif 9821308Sachestatic int _rl_vi_last_replacement; 9921308Sache 10021308Sachestatic int _rl_vi_last_key_before_insert; 10121308Sache 10221308Sachestatic int vi_redoing; 10321308Sache 10421308Sache/* Text modification commands. These are the `redoable' commands. */ 10575406Sachestatic const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; 10621308Sache 10721308Sache/* Arrays for the saved marks. */ 108119610Sachestatic int vi_mark_chars['z' - 'a' + 1]; 10921308Sache 110119610Sachestatic void _rl_vi_stuff_insert PARAMS((int)); 111119610Sachestatic void _rl_vi_save_insert PARAMS((UNDO_LIST *)); 112119610Sachestatic int rl_digit_loop1 PARAMS((void)); 11321308Sache 11421308Sachevoid 11521308Sache_rl_vi_initialize_line () 11621308Sache{ 11721308Sache register int i; 11821308Sache 11921308Sache for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) 12021308Sache vi_mark_chars[i] = -1; 12121308Sache} 12221308Sache 12321308Sachevoid 12421308Sache_rl_vi_reset_last () 12521308Sache{ 12621308Sache _rl_vi_last_command = 'i'; 12721308Sache _rl_vi_last_repeat = 1; 12821308Sache _rl_vi_last_arg_sign = 1; 12921308Sache _rl_vi_last_motion = 0; 13021308Sache} 13121308Sache 13221308Sachevoid 13321308Sache_rl_vi_set_last (key, repeat, sign) 13421308Sache int key, repeat, sign; 13521308Sache{ 13621308Sache _rl_vi_last_command = key; 13721308Sache _rl_vi_last_repeat = repeat; 13821308Sache _rl_vi_last_arg_sign = sign; 13921308Sache} 14021308Sache 141136759Speter/* A convenience function that calls _rl_vi_set_last to save the last command 142136759Speter information and enters insertion mode. */ 143136759Spetervoid 144136759Speterrl_vi_start_inserting (key, repeat, sign) 145136759Speter int key, repeat, sign; 146136759Speter{ 147136759Speter _rl_vi_set_last (key, repeat, sign); 148136759Speter rl_vi_insertion_mode (1, key); 149136759Speter} 150136759Speter 15121308Sache/* Is the command C a VI mode text modification command? */ 15221308Sacheint 15321308Sache_rl_vi_textmod_command (c) 15421308Sache int c; 15521308Sache{ 15621308Sache return (member (c, vi_textmod)); 15721308Sache} 15821308Sache 15921308Sachestatic void 16021308Sache_rl_vi_stuff_insert (count) 16121308Sache int count; 16221308Sache{ 16321308Sache rl_begin_undo_group (); 16421308Sache while (count--) 16521308Sache rl_insert_text (vi_insert_buffer); 16621308Sache rl_end_undo_group (); 16721308Sache} 16821308Sache 16921308Sache/* Bound to `.'. Called from command mode, so we know that we have to 17021308Sache redo a text modification command. The default for _rl_vi_last_command 17121308Sache puts you back into insert mode. */ 17221308Sacheint 17321308Sacherl_vi_redo (count, c) 17421308Sache int count, c; 17521308Sache{ 176119610Sache int r; 177119610Sache 17821308Sache if (!rl_explicit_arg) 17921308Sache { 18021308Sache rl_numeric_arg = _rl_vi_last_repeat; 18121308Sache rl_arg_sign = _rl_vi_last_arg_sign; 18221308Sache } 18321308Sache 184119610Sache r = 0; 18521308Sache vi_redoing = 1; 18621308Sache /* If we're redoing an insert with `i', stuff in the inserted text 18721308Sache and do not go into insertion mode. */ 18821308Sache if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) 18921308Sache { 19021308Sache _rl_vi_stuff_insert (count); 19121308Sache /* And back up point over the last character inserted. */ 19221308Sache if (rl_point > 0) 19321308Sache rl_point--; 19421308Sache } 19521308Sache else 196119610Sache r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); 19721308Sache vi_redoing = 0; 19821308Sache 199119610Sache return (r); 20021308Sache} 20121308Sache 20221308Sache/* A placeholder for further expansion. */ 20321308Sacheint 20421308Sacherl_vi_undo (count, key) 20521308Sache int count, key; 20621308Sache{ 20721308Sache return (rl_undo_command (count, key)); 20821308Sache} 20921308Sache 21021308Sache/* Yank the nth arg from the previous line into this line at point. */ 21121308Sacheint 21221308Sacherl_vi_yank_arg (count, key) 21321308Sache int count, key; 21421308Sache{ 21521308Sache /* Readline thinks that the first word on a line is the 0th, while vi 21621308Sache thinks the first word on a line is the 1st. Compensate. */ 21721308Sache if (rl_explicit_arg) 21821308Sache rl_yank_nth_arg (count - 1, 0); 21921308Sache else 22021308Sache rl_yank_nth_arg ('$', 0); 22121308Sache 22221308Sache return (0); 22321308Sache} 22421308Sache 22521308Sache/* With an argument, move back that many history lines, else move to the 22621308Sache beginning of history. */ 22721308Sacheint 22821308Sacherl_vi_fetch_history (count, c) 22921308Sache int count, c; 23021308Sache{ 23121308Sache int wanted; 23221308Sache 23321308Sache /* Giving an argument of n means we want the nth command in the history 23421308Sache file. The command number is interpreted the same way that the bash 23521308Sache `history' command does it -- that is, giving an argument count of 450 23621308Sache to this command would get the command listed as number 450 in the 23721308Sache output of `history'. */ 23821308Sache if (rl_explicit_arg) 23921308Sache { 24021308Sache wanted = history_base + where_history () - count; 24121308Sache if (wanted <= 0) 24221308Sache rl_beginning_of_history (0, 0); 24321308Sache else 24421308Sache rl_get_previous_history (wanted, c); 24521308Sache } 24621308Sache else 24721308Sache rl_beginning_of_history (count, 0); 24821308Sache return (0); 24921308Sache} 25021308Sache 25121308Sache/* Search again for the last thing searched for. */ 25221308Sacheint 25321308Sacherl_vi_search_again (count, key) 25421308Sache int count, key; 25521308Sache{ 25621308Sache switch (key) 25721308Sache { 25821308Sache case 'n': 25921308Sache rl_noninc_reverse_search_again (count, key); 26021308Sache break; 26121308Sache 26221308Sache case 'N': 26321308Sache rl_noninc_forward_search_again (count, key); 26421308Sache break; 26521308Sache } 26621308Sache return (0); 26721308Sache} 26821308Sache 26921308Sache/* Do a vi style search. */ 27021308Sacheint 27121308Sacherl_vi_search (count, key) 27221308Sache int count, key; 27321308Sache{ 27421308Sache switch (key) 27521308Sache { 27621308Sache case '?': 277136759Speter _rl_free_saved_history_line (); 27821308Sache rl_noninc_forward_search (count, key); 27921308Sache break; 28021308Sache 28121308Sache case '/': 282136759Speter _rl_free_saved_history_line (); 28321308Sache rl_noninc_reverse_search (count, key); 28421308Sache break; 28521308Sache 28621308Sache default: 28775406Sache rl_ding (); 28821308Sache break; 28921308Sache } 29021308Sache return (0); 29121308Sache} 29221308Sache 29321308Sache/* Completion, from vi's point of view. */ 29421308Sacheint 29521308Sacherl_vi_complete (ignore, key) 29621308Sache int ignore, key; 29721308Sache{ 29821308Sache if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) 29921308Sache { 30021308Sache if (!whitespace (rl_line_buffer[rl_point + 1])) 30121308Sache rl_vi_end_word (1, 'E'); 30221308Sache rl_point++; 30321308Sache } 30421308Sache 30521308Sache if (key == '*') 30621308Sache rl_complete_internal ('*'); /* Expansion and replacement. */ 30721308Sache else if (key == '=') 30821308Sache rl_complete_internal ('?'); /* List possible completions. */ 30921308Sache else if (key == '\\') 31021308Sache rl_complete_internal (TAB); /* Standard Readline completion. */ 31121308Sache else 31221308Sache rl_complete (0, key); 31321308Sache 31421308Sache if (key == '*' || key == '\\') 315136759Speter rl_vi_start_inserting (key, 1, rl_arg_sign); 316136759Speter 31721308Sache return (0); 31821308Sache} 31921308Sache 32021308Sache/* Tilde expansion for vi mode. */ 32121308Sacheint 32221308Sacherl_vi_tilde_expand (ignore, key) 32321308Sache int ignore, key; 32421308Sache{ 32521308Sache rl_tilde_expand (0, key); 326136759Speter rl_vi_start_inserting (key, 1, rl_arg_sign); 32721308Sache return (0); 32821308Sache} 32921308Sache 33021308Sache/* Previous word in vi mode. */ 33121308Sacheint 33221308Sacherl_vi_prev_word (count, key) 33321308Sache int count, key; 33421308Sache{ 33521308Sache if (count < 0) 33621308Sache return (rl_vi_next_word (-count, key)); 33721308Sache 33821308Sache if (rl_point == 0) 33921308Sache { 34075406Sache rl_ding (); 34121308Sache return (0); 34221308Sache } 34321308Sache 34421308Sache if (_rl_uppercase_p (key)) 34547558Sache rl_vi_bWord (count, key); 34621308Sache else 34747558Sache rl_vi_bword (count, key); 34821308Sache 34921308Sache return (0); 35021308Sache} 35121308Sache 35221308Sache/* Next word in vi mode. */ 35321308Sacheint 35421308Sacherl_vi_next_word (count, key) 35521308Sache int count, key; 35621308Sache{ 35721308Sache if (count < 0) 35821308Sache return (rl_vi_prev_word (-count, key)); 35921308Sache 36021308Sache if (rl_point >= (rl_end - 1)) 36121308Sache { 36275406Sache rl_ding (); 36321308Sache return (0); 36421308Sache } 36521308Sache 36621308Sache if (_rl_uppercase_p (key)) 36747558Sache rl_vi_fWord (count, key); 36821308Sache else 36947558Sache rl_vi_fword (count, key); 37021308Sache return (0); 37121308Sache} 37221308Sache 37321308Sache/* Move to the end of the ?next? word. */ 37421308Sacheint 37521308Sacherl_vi_end_word (count, key) 37621308Sache int count, key; 37721308Sache{ 37821308Sache if (count < 0) 37921308Sache { 38075406Sache rl_ding (); 38121308Sache return -1; 38221308Sache } 38321308Sache 38421308Sache if (_rl_uppercase_p (key)) 38547558Sache rl_vi_eWord (count, key); 38621308Sache else 38747558Sache rl_vi_eword (count, key); 38821308Sache return (0); 38921308Sache} 39021308Sache 39121308Sache/* Move forward a word the way that 'W' does. */ 39221308Sacheint 39347558Sacherl_vi_fWord (count, ignore) 39447558Sache int count, ignore; 39521308Sache{ 39621308Sache while (count-- && rl_point < (rl_end - 1)) 39721308Sache { 39821308Sache /* Skip until whitespace. */ 39921308Sache while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 40021308Sache rl_point++; 40121308Sache 40221308Sache /* Now skip whitespace. */ 40321308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 40421308Sache rl_point++; 40521308Sache } 40621308Sache return (0); 40721308Sache} 40821308Sache 40921308Sacheint 41047558Sacherl_vi_bWord (count, ignore) 41147558Sache int count, ignore; 41221308Sache{ 41321308Sache while (count-- && rl_point > 0) 41421308Sache { 41521308Sache /* If we are at the start of a word, move back to whitespace so 41621308Sache we will go back to the start of the previous word. */ 41721308Sache if (!whitespace (rl_line_buffer[rl_point]) && 41821308Sache whitespace (rl_line_buffer[rl_point - 1])) 41921308Sache rl_point--; 42021308Sache 42121308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 42221308Sache rl_point--; 42321308Sache 42421308Sache if (rl_point > 0) 42521308Sache { 42621308Sache while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); 42721308Sache rl_point++; 42821308Sache } 42921308Sache } 43021308Sache return (0); 43121308Sache} 43221308Sache 43321308Sacheint 43447558Sacherl_vi_eWord (count, ignore) 43547558Sache int count, ignore; 43621308Sache{ 43721308Sache while (count-- && rl_point < (rl_end - 1)) 43821308Sache { 43921308Sache if (!whitespace (rl_line_buffer[rl_point])) 44021308Sache rl_point++; 44121308Sache 44221308Sache /* Move to the next non-whitespace character (to the start of the 44321308Sache next word). */ 444136759Speter while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 445136759Speter rl_point++; 44621308Sache 44721308Sache if (rl_point && rl_point < rl_end) 44821308Sache { 44921308Sache /* Skip whitespace. */ 45021308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 45121308Sache rl_point++; 45221308Sache 45321308Sache /* Skip until whitespace. */ 45421308Sache while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) 45521308Sache rl_point++; 45621308Sache 45721308Sache /* Move back to the last character of the word. */ 45821308Sache rl_point--; 45921308Sache } 46021308Sache } 46121308Sache return (0); 46221308Sache} 46321308Sache 46421308Sacheint 46547558Sacherl_vi_fword (count, ignore) 46647558Sache int count, ignore; 46721308Sache{ 46821308Sache while (count-- && rl_point < (rl_end - 1)) 46921308Sache { 47021308Sache /* Move to white space (really non-identifer). */ 471119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 47221308Sache { 473119610Sache while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) 47421308Sache rl_point++; 47521308Sache } 47621308Sache else /* if (!whitespace (rl_line_buffer[rl_point])) */ 47721308Sache { 478119610Sache while (!_rl_isident (rl_line_buffer[rl_point]) && 47921308Sache !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 48021308Sache rl_point++; 48121308Sache } 48221308Sache 48321308Sache /* Move past whitespace. */ 48421308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 48521308Sache rl_point++; 48621308Sache } 48721308Sache return (0); 48821308Sache} 48921308Sache 49021308Sacheint 49147558Sacherl_vi_bword (count, ignore) 49247558Sache int count, ignore; 49321308Sache{ 49421308Sache while (count-- && rl_point > 0) 49521308Sache { 49621308Sache int last_is_ident; 49721308Sache 49821308Sache /* If we are at the start of a word, move back to whitespace 49921308Sache so we will go back to the start of the previous word. */ 50021308Sache if (!whitespace (rl_line_buffer[rl_point]) && 50121308Sache whitespace (rl_line_buffer[rl_point - 1])) 50221308Sache rl_point--; 50321308Sache 50421308Sache /* If this character and the previous character are `opposite', move 50521308Sache back so we don't get messed up by the rl_point++ down there in 50621308Sache the while loop. Without this code, words like `l;' screw up the 50721308Sache function. */ 508119610Sache last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]); 509119610Sache if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || 510119610Sache (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident)) 51121308Sache rl_point--; 51221308Sache 51321308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 51421308Sache rl_point--; 51521308Sache 51621308Sache if (rl_point > 0) 51721308Sache { 518119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 519119610Sache while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); 52021308Sache else 521119610Sache while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && 52221308Sache !whitespace (rl_line_buffer[rl_point])); 52321308Sache rl_point++; 52421308Sache } 52521308Sache } 52621308Sache return (0); 52721308Sache} 52821308Sache 52921308Sacheint 53047558Sacherl_vi_eword (count, ignore) 53147558Sache int count, ignore; 53221308Sache{ 53321308Sache while (count-- && rl_point < rl_end - 1) 53421308Sache { 53521308Sache if (!whitespace (rl_line_buffer[rl_point])) 53621308Sache rl_point++; 53721308Sache 53821308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 53921308Sache rl_point++; 54021308Sache 54121308Sache if (rl_point < rl_end) 54221308Sache { 543119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 544119610Sache while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); 54521308Sache else 546119610Sache while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) 54721308Sache && !whitespace (rl_line_buffer[rl_point])); 54821308Sache } 54921308Sache rl_point--; 55021308Sache } 55121308Sache return (0); 55221308Sache} 55321308Sache 55421308Sacheint 55521308Sacherl_vi_insert_beg (count, key) 55621308Sache int count, key; 55721308Sache{ 55821308Sache rl_beg_of_line (1, key); 55921308Sache rl_vi_insertion_mode (1, key); 56021308Sache return (0); 56121308Sache} 56221308Sache 56321308Sacheint 56421308Sacherl_vi_append_mode (count, key) 56521308Sache int count, key; 56621308Sache{ 56721308Sache if (rl_point < rl_end) 568119610Sache { 569119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 570119610Sache rl_point++; 571119610Sache else 572119610Sache { 573119610Sache int point = rl_point; 574119610Sache rl_forward_char (1, key); 575119610Sache if (point == rl_point) 576119610Sache rl_point = rl_end; 577119610Sache } 578119610Sache } 57921308Sache rl_vi_insertion_mode (1, key); 58021308Sache return (0); 58121308Sache} 58221308Sache 58321308Sacheint 58421308Sacherl_vi_append_eol (count, key) 58521308Sache int count, key; 58621308Sache{ 58721308Sache rl_end_of_line (1, key); 58821308Sache rl_vi_append_mode (1, key); 58921308Sache return (0); 59021308Sache} 59121308Sache 59221308Sache/* What to do in the case of C-d. */ 59321308Sacheint 59421308Sacherl_vi_eof_maybe (count, c) 59521308Sache int count, c; 59621308Sache{ 59721308Sache return (rl_newline (1, '\n')); 59821308Sache} 59921308Sache 60021308Sache/* Insertion mode stuff. */ 60121308Sache 60221308Sache/* Switching from one mode to the other really just involves 60321308Sache switching keymaps. */ 60421308Sacheint 60521308Sacherl_vi_insertion_mode (count, key) 60621308Sache int count, key; 60721308Sache{ 60821308Sache _rl_keymap = vi_insertion_keymap; 60921308Sache _rl_vi_last_key_before_insert = key; 61021308Sache return (0); 61121308Sache} 61221308Sache 61321308Sachestatic void 61421308Sache_rl_vi_save_insert (up) 61521308Sache UNDO_LIST *up; 61621308Sache{ 61721308Sache int len, start, end; 61821308Sache 61935486Sache if (up == 0) 62035486Sache { 62135486Sache if (vi_insert_buffer_size >= 1) 62235486Sache vi_insert_buffer[0] = '\0'; 62335486Sache return; 62435486Sache } 62535486Sache 62621308Sache start = up->start; 62721308Sache end = up->end; 62821308Sache len = end - start + 1; 62921308Sache if (len >= vi_insert_buffer_size) 63021308Sache { 63121308Sache vi_insert_buffer_size += (len + 32) - (len % 32); 632119610Sache vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); 63321308Sache } 63421308Sache strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); 63521308Sache vi_insert_buffer[len-1] = '\0'; 63621308Sache} 63721308Sache 63821308Sachevoid 63921308Sache_rl_vi_done_inserting () 64021308Sache{ 64121308Sache if (_rl_vi_doing_insert) 64221308Sache { 643119610Sache /* The `C', `s', and `S' commands set this. */ 64421308Sache rl_end_undo_group (); 64521308Sache /* Now, the text between rl_undo_list->next->start and 64621308Sache rl_undo_list->next->end is what was inserted while in insert 64721308Sache mode. It gets copied to VI_INSERT_BUFFER because it depends 64821308Sache on absolute indices into the line which may change (though they 64921308Sache probably will not). */ 65021308Sache _rl_vi_doing_insert = 0; 65121308Sache _rl_vi_save_insert (rl_undo_list->next); 65221308Sache vi_continued_command = 1; 65321308Sache } 65421308Sache else 65521308Sache { 656136759Speter if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list) 65721308Sache _rl_vi_save_insert (rl_undo_list); 65821308Sache /* XXX - Other keys probably need to be checked. */ 65921308Sache else if (_rl_vi_last_key_before_insert == 'C') 66021308Sache rl_end_undo_group (); 66121308Sache while (_rl_undo_group_level > 0) 66221308Sache rl_end_undo_group (); 66321308Sache vi_continued_command = 0; 66421308Sache } 66521308Sache} 66621308Sache 66721308Sacheint 66821308Sacherl_vi_movement_mode (count, key) 66921308Sache int count, key; 67021308Sache{ 67121308Sache if (rl_point > 0) 672119610Sache rl_backward_char (1, key); 67321308Sache 67421308Sache _rl_keymap = vi_movement_keymap; 67521308Sache _rl_vi_done_inserting (); 67621308Sache return (0); 67721308Sache} 67821308Sache 67921308Sacheint 68021308Sacherl_vi_arg_digit (count, c) 68121308Sache int count, c; 68221308Sache{ 68321308Sache if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) 68421308Sache return (rl_beg_of_line (1, c)); 68521308Sache else 68621308Sache return (rl_digit_argument (count, c)); 68721308Sache} 68821308Sache 689119610Sache/* Change the case of the next COUNT characters. */ 690119610Sache#if defined (HANDLE_MULTIBYTE) 691119610Sachestatic int 692119610Sache_rl_vi_change_mbchar_case (count) 693119610Sache int count; 694119610Sache{ 695119610Sache wchar_t wc; 696125665Sache char mb[MB_LEN_MAX+1]; 697136759Speter int mblen, p; 698119610Sache mbstate_t ps; 699119610Sache 700119610Sache memset (&ps, 0, sizeof (mbstate_t)); 701119610Sache if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) 702119610Sache count--; 703119610Sache while (count-- && rl_point < rl_end) 704119610Sache { 705119610Sache mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); 706119610Sache if (iswupper (wc)) 707119610Sache wc = towlower (wc); 708119610Sache else if (iswlower (wc)) 709119610Sache wc = towupper (wc); 710119610Sache else 711119610Sache { 712119610Sache /* Just skip over chars neither upper nor lower case */ 713119610Sache rl_forward_char (1, 0); 714119610Sache continue; 715119610Sache } 716119610Sache 717119610Sache /* Vi is kind of strange here. */ 718119610Sache if (wc) 719119610Sache { 720136759Speter p = rl_point; 721136759Speter mblen = wcrtomb (mb, wc, &ps); 722125665Sache if (mblen >= 0) 723125665Sache mb[mblen] = '\0'; 724119610Sache rl_begin_undo_group (); 725136759Speter rl_vi_delete (1, 0); 726136759Speter if (rl_point < p) /* Did we retreat at EOL? */ 727136759Speter rl_point++; /* XXX - should we advance more than 1 for mbchar? */ 728119610Sache rl_insert_text (mb); 729119610Sache rl_end_undo_group (); 730119610Sache rl_vi_check (); 731119610Sache } 732119610Sache else 733119610Sache rl_forward_char (1, 0); 734119610Sache } 735119610Sache 736119610Sache return 0; 737119610Sache} 738119610Sache#endif 739119610Sache 74021308Sacheint 74121308Sacherl_vi_change_case (count, ignore) 74221308Sache int count, ignore; 74321308Sache{ 744136759Speter int c, p; 74521308Sache 74621308Sache /* Don't try this on an empty line. */ 74721308Sache if (rl_point >= rl_end) 74821308Sache return (0); 74921308Sache 750136759Speter c = 0; 751119610Sache#if defined (HANDLE_MULTIBYTE) 752119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 753119610Sache return (_rl_vi_change_mbchar_case (count)); 754119610Sache#endif 755119610Sache 75621308Sache while (count-- && rl_point < rl_end) 75721308Sache { 75821308Sache if (_rl_uppercase_p (rl_line_buffer[rl_point])) 75921308Sache c = _rl_to_lower (rl_line_buffer[rl_point]); 76021308Sache else if (_rl_lowercase_p (rl_line_buffer[rl_point])) 76121308Sache c = _rl_to_upper (rl_line_buffer[rl_point]); 76221308Sache else 76321308Sache { 76421308Sache /* Just skip over characters neither upper nor lower case. */ 765119610Sache rl_forward_char (1, c); 76621308Sache continue; 76721308Sache } 76821308Sache 76921308Sache /* Vi is kind of strange here. */ 77021308Sache if (c) 77121308Sache { 772136759Speter p = rl_point; 77321308Sache rl_begin_undo_group (); 774136759Speter rl_vi_delete (1, c); 775136759Speter if (rl_point < p) /* Did we retreat at EOL? */ 776136759Speter rl_point++; 777119610Sache _rl_insert_char (1, c); 77821308Sache rl_end_undo_group (); 77921308Sache rl_vi_check (); 78021308Sache } 78121308Sache else 782119610Sache rl_forward_char (1, c); 78321308Sache } 78421308Sache return (0); 78521308Sache} 78621308Sache 78721308Sacheint 78821308Sacherl_vi_put (count, key) 78921308Sache int count, key; 79021308Sache{ 79121308Sache if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) 792119610Sache rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); 79321308Sache 794136759Speter while (count--) 795136759Speter rl_yank (1, key); 796136759Speter 797119610Sache rl_backward_char (1, key); 79821308Sache return (0); 79921308Sache} 80021308Sache 80121308Sacheint 80221308Sacherl_vi_check () 80321308Sache{ 80421308Sache if (rl_point && rl_point == rl_end) 805119610Sache { 806119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 807119610Sache rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 808119610Sache else 809119610Sache rl_point--; 810119610Sache } 81121308Sache return (0); 81221308Sache} 81321308Sache 81421308Sacheint 81521308Sacherl_vi_column (count, key) 81621308Sache int count, key; 81721308Sache{ 81821308Sache if (count > rl_end) 81921308Sache rl_end_of_line (1, key); 82021308Sache else 82121308Sache rl_point = count - 1; 82221308Sache return (0); 82321308Sache} 82421308Sache 82521308Sacheint 82621308Sacherl_vi_domove (key, nextkey) 82721308Sache int key, *nextkey; 82821308Sache{ 82921308Sache int c, save; 83021308Sache int old_end; 83121308Sache 83221308Sache rl_mark = rl_point; 83375406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 83421308Sache c = rl_read_key (); 83575406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 83621308Sache *nextkey = c; 83721308Sache 83821308Sache if (!member (c, vi_motion)) 83921308Sache { 84021308Sache if (_rl_digit_p (c)) 84121308Sache { 84221308Sache save = rl_numeric_arg; 84321308Sache rl_numeric_arg = _rl_digit_value (c); 844136759Speter rl_explicit_arg = 1; 84521308Sache rl_digit_loop1 (); 84621308Sache rl_numeric_arg *= save; 84775406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 84821308Sache c = rl_read_key (); /* real command */ 84975406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 85021308Sache *nextkey = c; 85121308Sache } 85221308Sache else if (key == c && (key == 'd' || key == 'y' || key == 'c')) 85321308Sache { 85421308Sache rl_mark = rl_end; 85521308Sache rl_beg_of_line (1, c); 85621308Sache _rl_vi_last_motion = c; 85721308Sache return (0); 85821308Sache } 85921308Sache else 86021308Sache return (-1); 86121308Sache } 86221308Sache 86321308Sache _rl_vi_last_motion = c; 86421308Sache 86521308Sache /* Append a blank character temporarily so that the motion routines 86621308Sache work right at the end of the line. */ 86721308Sache old_end = rl_end; 86821308Sache rl_line_buffer[rl_end++] = ' '; 86921308Sache rl_line_buffer[rl_end] = '\0'; 87021308Sache 87121308Sache _rl_dispatch (c, _rl_keymap); 87221308Sache 87321308Sache /* Remove the blank that we added. */ 87421308Sache rl_end = old_end; 87521308Sache rl_line_buffer[rl_end] = '\0'; 87621308Sache if (rl_point > rl_end) 87721308Sache rl_point = rl_end; 87821308Sache 87921308Sache /* No change in position means the command failed. */ 88021308Sache if (rl_mark == rl_point) 88121308Sache return (-1); 88221308Sache 88321308Sache /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next 88421308Sache word. If we are not at the end of the line, and we are on a 88521308Sache non-whitespace character, move back one (presumably to whitespace). */ 88621308Sache if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && 88721308Sache !whitespace (rl_line_buffer[rl_point])) 88821308Sache rl_point--; 88921308Sache 89021308Sache /* If cw or cW, back up to the end of a word, so the behaviour of ce 89121308Sache or cE is the actual result. Brute-force, no subtlety. */ 89221308Sache if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) 89321308Sache { 89421308Sache /* Don't move farther back than where we started. */ 89521308Sache while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) 89621308Sache rl_point--; 89721308Sache 89821308Sache /* Posix.2 says that if cw or cW moves the cursor towards the end of 89921308Sache the line, the character under the cursor should be deleted. */ 90021308Sache if (rl_point == rl_mark) 90121308Sache rl_point++; 90221308Sache else 90321308Sache { 90421308Sache /* Move past the end of the word so that the kill doesn't 90521308Sache remove the last letter of the previous word. Only do this 90621308Sache if we are not at the end of the line. */ 90721308Sache if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) 90821308Sache rl_point++; 90921308Sache } 91021308Sache } 91121308Sache 91221308Sache if (rl_mark < rl_point) 913119610Sache SWAP (rl_point, rl_mark); 91421308Sache 91521308Sache return (0); 91621308Sache} 91721308Sache 91821308Sache/* A simplified loop for vi. Don't dispatch key at end. 91975406Sache Don't recognize minus sign? 92075406Sache Should this do rl_save_prompt/rl_restore_prompt? */ 92121308Sachestatic int 92221308Sacherl_digit_loop1 () 92321308Sache{ 92421308Sache int key, c; 92521308Sache 92675406Sache RL_SETSTATE(RL_STATE_NUMERICARG); 92721308Sache while (1) 92821308Sache { 92975406Sache if (rl_numeric_arg > 1000000) 93075406Sache { 93175406Sache rl_explicit_arg = rl_numeric_arg = 0; 93275406Sache rl_ding (); 93375406Sache rl_clear_message (); 93475406Sache RL_UNSETSTATE(RL_STATE_NUMERICARG); 93575406Sache return 1; 93675406Sache } 937119610Sache rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); 93875406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 93921308Sache key = c = rl_read_key (); 94075406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 94121308Sache 942119610Sache if (c >= 0 && _rl_keymap[c].type == ISFUNC && 94321308Sache _rl_keymap[c].function == rl_universal_argument) 94421308Sache { 94521308Sache rl_numeric_arg *= 4; 94621308Sache continue; 94721308Sache } 94821308Sache 94921308Sache c = UNMETA (c); 95021308Sache if (_rl_digit_p (c)) 95121308Sache { 95221308Sache if (rl_explicit_arg) 95321308Sache rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); 95421308Sache else 95521308Sache rl_numeric_arg = _rl_digit_value (c); 95621308Sache rl_explicit_arg = 1; 95721308Sache } 95821308Sache else 95921308Sache { 96021308Sache rl_clear_message (); 96121308Sache rl_stuff_char (key); 96221308Sache break; 96321308Sache } 96421308Sache } 96575406Sache 96675406Sache RL_UNSETSTATE(RL_STATE_NUMERICARG); 96721308Sache return (0); 96821308Sache} 96921308Sache 97021308Sacheint 97121308Sacherl_vi_delete_to (count, key) 97221308Sache int count, key; 97321308Sache{ 97421308Sache int c; 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 if (rl_vi_domove (key, &c)) 98221308Sache { 98375406Sache rl_ding (); 98421308Sache return -1; 98521308Sache } 98621308Sache 98721308Sache /* These are the motion commands that do not require adjusting the 98821308Sache mark. */ 98921308Sache if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) 99021308Sache rl_mark++; 99121308Sache 99221308Sache rl_kill_text (rl_point, rl_mark); 99321308Sache return (0); 99421308Sache} 99521308Sache 99621308Sacheint 99721308Sacherl_vi_change_to (count, key) 99821308Sache int count, key; 99921308Sache{ 100021308Sache int c, start_pos; 100121308Sache 100221308Sache if (_rl_uppercase_p (key)) 100321308Sache rl_stuff_char ('$'); 100421308Sache else if (vi_redoing) 100521308Sache rl_stuff_char (_rl_vi_last_motion); 100621308Sache 100721308Sache start_pos = rl_point; 100821308Sache 100921308Sache if (rl_vi_domove (key, &c)) 101021308Sache { 101175406Sache rl_ding (); 101221308Sache return -1; 101321308Sache } 101421308Sache 101521308Sache /* These are the motion commands that do not require adjusting the 101621308Sache mark. c[wW] are handled by special-case code in rl_vi_domove(), 101721308Sache and already leave the mark at the correct location. */ 101821308Sache if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) 101921308Sache rl_mark++; 102021308Sache 102121308Sache /* The cursor never moves with c[wW]. */ 102221308Sache if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) 102321308Sache rl_point = start_pos; 102421308Sache 102521308Sache if (vi_redoing) 102621308Sache { 102721308Sache if (vi_insert_buffer && *vi_insert_buffer) 102821308Sache rl_begin_undo_group (); 102921308Sache rl_delete_text (rl_point, rl_mark); 103021308Sache if (vi_insert_buffer && *vi_insert_buffer) 103121308Sache { 103221308Sache rl_insert_text (vi_insert_buffer); 103321308Sache rl_end_undo_group (); 103421308Sache } 103521308Sache } 103621308Sache else 103721308Sache { 103821308Sache rl_begin_undo_group (); /* to make the `u' command work */ 103921308Sache rl_kill_text (rl_point, rl_mark); 104021308Sache /* `C' does not save the text inserted for undoing or redoing. */ 104121308Sache if (_rl_uppercase_p (key) == 0) 104221308Sache _rl_vi_doing_insert = 1; 1043136759Speter rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign); 104421308Sache } 104521308Sache 104621308Sache return (0); 104721308Sache} 104821308Sache 104921308Sacheint 105021308Sacherl_vi_yank_to (count, key) 105121308Sache int count, key; 105221308Sache{ 105321308Sache int c, save = rl_point; 105421308Sache 105521308Sache if (_rl_uppercase_p (key)) 105621308Sache rl_stuff_char ('$'); 105721308Sache 105821308Sache if (rl_vi_domove (key, &c)) 105921308Sache { 106075406Sache rl_ding (); 106121308Sache return -1; 106221308Sache } 106321308Sache 106421308Sache /* These are the motion commands that do not require adjusting the 106521308Sache mark. */ 106621308Sache if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) 106721308Sache rl_mark++; 106821308Sache 106921308Sache rl_begin_undo_group (); 107021308Sache rl_kill_text (rl_point, rl_mark); 107121308Sache rl_end_undo_group (); 107221308Sache rl_do_undo (); 107321308Sache rl_point = save; 107421308Sache 107521308Sache return (0); 107621308Sache} 107721308Sache 107821308Sacheint 107921308Sacherl_vi_delete (count, key) 108021308Sache int count, key; 108121308Sache{ 108221308Sache int end; 108321308Sache 108421308Sache if (rl_end == 0) 108521308Sache { 108675406Sache rl_ding (); 108721308Sache return -1; 108821308Sache } 108921308Sache 1090119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1091119610Sache end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); 1092119610Sache else 1093119610Sache end = rl_point + count; 109421308Sache 109521308Sache if (end >= rl_end) 109621308Sache end = rl_end; 109721308Sache 109821308Sache rl_kill_text (rl_point, end); 109921308Sache 110021308Sache if (rl_point > 0 && rl_point == rl_end) 1101119610Sache rl_backward_char (1, key); 110221308Sache return (0); 110321308Sache} 110421308Sache 110521308Sacheint 110621308Sacherl_vi_back_to_indent (count, key) 110721308Sache int count, key; 110821308Sache{ 110921308Sache rl_beg_of_line (1, key); 111021308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 111121308Sache rl_point++; 111221308Sache return (0); 111321308Sache} 111421308Sache 111521308Sacheint 111621308Sacherl_vi_first_print (count, key) 111721308Sache int count, key; 111821308Sache{ 111921308Sache return (rl_vi_back_to_indent (1, key)); 112021308Sache} 112121308Sache 112221308Sacheint 112321308Sacherl_vi_char_search (count, key) 112421308Sache int count, key; 112521308Sache{ 1126119610Sache#if defined (HANDLE_MULTIBYTE) 1127119610Sache static char *target; 1128119610Sache static int mb_len; 1129119610Sache#else 113021308Sache static char target; 1131119610Sache#endif 113221308Sache static int orig_dir, dir; 113321308Sache 113421308Sache if (key == ';' || key == ',') 113521308Sache dir = key == ';' ? orig_dir : -orig_dir; 113621308Sache else 113721308Sache { 113821308Sache if (vi_redoing) 1139119610Sache#if defined (HANDLE_MULTIBYTE) 1140119610Sache target = _rl_vi_last_search_mbchar; 1141119610Sache#else 114221308Sache target = _rl_vi_last_search_char; 1143119610Sache#endif 114421308Sache else 114575406Sache { 1146119610Sache#if defined (HANDLE_MULTIBYTE) 1147119610Sache mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1148119610Sache target = _rl_vi_last_search_mbchar; 1149119610Sache#else 115075406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 115175406Sache _rl_vi_last_search_char = target = rl_read_key (); 115275406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 1153119610Sache#endif 115475406Sache } 115521308Sache 115621308Sache switch (key) 115721308Sache { 115821308Sache case 't': 115921308Sache orig_dir = dir = FTO; 116021308Sache break; 116121308Sache 116221308Sache case 'T': 116321308Sache orig_dir = dir = BTO; 116421308Sache break; 116521308Sache 116621308Sache case 'f': 116721308Sache orig_dir = dir = FFIND; 116821308Sache break; 116921308Sache 117021308Sache case 'F': 117121308Sache orig_dir = dir = BFIND; 117221308Sache break; 117321308Sache } 117421308Sache } 117521308Sache 1176119610Sache#if defined (HANDLE_MULTIBYTE) 1177119610Sache return (_rl_char_search_internal (count, dir, target, mb_len)); 1178119610Sache#else 117921308Sache return (_rl_char_search_internal (count, dir, target)); 1180119610Sache#endif 118121308Sache} 118221308Sache 118321308Sache/* Match brackets */ 118421308Sacheint 118521308Sacherl_vi_match (ignore, key) 118621308Sache int ignore, key; 118721308Sache{ 1188119610Sache int count = 1, brack, pos, tmp, pre; 118921308Sache 119021308Sache pos = rl_point; 119121308Sache if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 119221308Sache { 1193119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1194119610Sache { 1195119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1196119610Sache { 1197119610Sache pre = rl_point; 1198119610Sache rl_forward_char (1, key); 1199119610Sache if (pre == rl_point) 1200119610Sache break; 1201119610Sache } 1202119610Sache } 1203119610Sache else 1204119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && 1205119610Sache rl_point < rl_end - 1) 1206119610Sache rl_forward_char (1, key); 120721308Sache 120821308Sache if (brack <= 0) 120921308Sache { 121021308Sache rl_point = pos; 121175406Sache rl_ding (); 121221308Sache return -1; 121321308Sache } 121421308Sache } 121521308Sache 121621308Sache pos = rl_point; 121721308Sache 121821308Sache if (brack < 0) 121921308Sache { 122021308Sache while (count) 122121308Sache { 1222119610Sache tmp = pos; 1223119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1224119610Sache pos--; 1225119610Sache else 122621308Sache { 1227119610Sache pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); 1228119610Sache if (tmp == pos) 1229119610Sache pos--; 1230119610Sache } 1231119610Sache if (pos >= 0) 1232119610Sache { 123321308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 123421308Sache if (b == -brack) 123521308Sache count--; 123621308Sache else if (b == brack) 123721308Sache count++; 123821308Sache } 123921308Sache else 124021308Sache { 124175406Sache rl_ding (); 124221308Sache return -1; 124321308Sache } 124421308Sache } 124521308Sache } 124621308Sache else 124721308Sache { /* brack > 0 */ 124821308Sache while (count) 124921308Sache { 1250119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1251119610Sache pos++; 1252119610Sache else 1253119610Sache pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); 1254119610Sache 1255119610Sache if (pos < rl_end) 125621308Sache { 125721308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 125821308Sache if (b == -brack) 125921308Sache count--; 126021308Sache else if (b == brack) 126121308Sache count++; 126221308Sache } 126321308Sache else 126421308Sache { 126575406Sache rl_ding (); 126621308Sache return -1; 126721308Sache } 126821308Sache } 126921308Sache } 127021308Sache rl_point = pos; 127121308Sache return (0); 127221308Sache} 127321308Sache 127421308Sacheint 127521308Sacherl_vi_bracktype (c) 127621308Sache int c; 127721308Sache{ 127821308Sache switch (c) 127921308Sache { 128021308Sache case '(': return 1; 128121308Sache case ')': return -1; 128221308Sache case '[': return 2; 128321308Sache case ']': return -2; 128421308Sache case '{': return 3; 128521308Sache case '}': return -3; 128621308Sache default: return 0; 128721308Sache } 128821308Sache} 128921308Sache 1290119610Sache/* XXX - think about reading an entire mbchar with _rl_read_mbchar and 1291119610Sache inserting it in one bunch instead of the loop below (like in 1292136759Speter rl_vi_char_search or _rl_vi_change_mbchar_case). Set c to mbchar[0] 1293119610Sache for test against 033 or ^C. Make sure that _rl_read_mbchar does 1294119610Sache this right. */ 129521308Sacheint 129621308Sacherl_vi_change_char (count, key) 129721308Sache int count, key; 129821308Sache{ 1299136759Speter int c, p; 130021308Sache 130121308Sache if (vi_redoing) 130221308Sache c = _rl_vi_last_replacement; 130321308Sache else 130475406Sache { 130575406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 130675406Sache _rl_vi_last_replacement = c = rl_read_key (); 130775406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 130875406Sache } 130921308Sache 131021308Sache if (c == '\033' || c == CTRL ('C')) 131121308Sache return -1; 131221308Sache 1313136759Speter rl_begin_undo_group (); 131421308Sache while (count-- && rl_point < rl_end) 131521308Sache { 1316136759Speter p = rl_point; 1317136759Speter rl_vi_delete (1, c); 1318119610Sache#if defined (HANDLE_MULTIBYTE) 1319119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1320136759Speter { 1321136759Speter if (rl_point < p) /* Did we retreat at EOL? */ 1322136759Speter rl_point++; 1323136759Speter while (_rl_insert_char (1, c)) 1324136759Speter { 1325136759Speter RL_SETSTATE (RL_STATE_MOREINPUT); 1326136759Speter c = rl_read_key (); 1327136759Speter RL_UNSETSTATE (RL_STATE_MOREINPUT); 1328136759Speter } 1329136759Speter } 1330119610Sache else 1331119610Sache#endif 1332136759Speter { 1333136759Speter if (rl_point < p) /* Did we retreat at EOL? */ 1334136759Speter rl_point++; 1335136759Speter _rl_insert_char (1, c); 1336136759Speter } 1337136759Speter } 1338136759Speter rl_end_undo_group (); 133921308Sache 134021308Sache return (0); 134121308Sache} 134221308Sache 134321308Sacheint 134421308Sacherl_vi_subst (count, key) 134521308Sache int count, key; 134621308Sache{ 1347119610Sache /* If we are redoing, rl_vi_change_to will stuff the last motion char */ 1348119610Sache if (vi_redoing == 0) 1349136759Speter rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */ 135021308Sache 1351119610Sache return (rl_vi_change_to (count, 'c')); 135221308Sache} 135321308Sache 135421308Sacheint 135521308Sacherl_vi_overstrike (count, key) 135621308Sache int count, key; 135721308Sache{ 135821308Sache if (_rl_vi_doing_insert == 0) 135921308Sache { 136021308Sache _rl_vi_doing_insert = 1; 136121308Sache rl_begin_undo_group (); 136221308Sache } 136321308Sache 1364119610Sache if (count > 0) 136521308Sache { 1366119610Sache _rl_overwrite_char (count, key); 1367119610Sache vi_replace_count += count; 1368119610Sache } 136921308Sache 137021308Sache return (0); 137121308Sache} 137221308Sache 137321308Sacheint 137421308Sacherl_vi_overstrike_delete (count, key) 137521308Sache int count, key; 137621308Sache{ 137721308Sache int i, s; 137821308Sache 137921308Sache for (i = 0; i < count; i++) 138021308Sache { 138121308Sache if (vi_replace_count == 0) 138221308Sache { 138375406Sache rl_ding (); 138421308Sache break; 138521308Sache } 138621308Sache s = rl_point; 138721308Sache 138821308Sache if (rl_do_undo ()) 138921308Sache vi_replace_count--; 139021308Sache 139121308Sache if (rl_point == s) 1392119610Sache rl_backward_char (1, key); 139321308Sache } 139421308Sache 139521308Sache if (vi_replace_count == 0 && _rl_vi_doing_insert) 139621308Sache { 139721308Sache rl_end_undo_group (); 139821308Sache rl_do_undo (); 139921308Sache _rl_vi_doing_insert = 0; 140021308Sache } 140121308Sache return (0); 140221308Sache} 140321308Sache 140421308Sacheint 140521308Sacherl_vi_replace (count, key) 140621308Sache int count, key; 140721308Sache{ 140821308Sache int i; 140921308Sache 141021308Sache vi_replace_count = 0; 141121308Sache 141221308Sache if (!vi_replace_map) 141321308Sache { 141421308Sache vi_replace_map = rl_make_bare_keymap (); 141521308Sache 141621308Sache for (i = ' '; i < KEYMAP_SIZE; i++) 141721308Sache vi_replace_map[i].function = rl_vi_overstrike; 141821308Sache 141921308Sache vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; 142021308Sache vi_replace_map[ESC].function = rl_vi_movement_mode; 142121308Sache vi_replace_map[RETURN].function = rl_newline; 142221308Sache vi_replace_map[NEWLINE].function = rl_newline; 142321308Sache 142421308Sache /* If the normal vi insertion keymap has ^H bound to erase, do the 142521308Sache same here. Probably should remove the assignment to RUBOUT up 142621308Sache there, but I don't think it will make a difference in real life. */ 142721308Sache if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && 142821308Sache vi_insertion_keymap[CTRL ('H')].function == rl_rubout) 142921308Sache vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; 143021308Sache 143121308Sache } 143221308Sache _rl_keymap = vi_replace_map; 143321308Sache return (0); 143421308Sache} 143521308Sache 143621308Sache#if 0 143721308Sache/* Try to complete the word we are standing on or the word that ends with 143821308Sache the previous character. A space matches everything. Word delimiters are 143921308Sache space and ;. */ 144021308Sacheint 144121308Sacherl_vi_possible_completions() 144221308Sache{ 144321308Sache int save_pos = rl_point; 144421308Sache 144521308Sache if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') 144621308Sache { 144721308Sache while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && 144821308Sache rl_line_buffer[rl_point] != ';') 144921308Sache rl_point++; 145021308Sache } 145121308Sache else if (rl_line_buffer[rl_point - 1] == ';') 145221308Sache { 145375406Sache rl_ding (); 145421308Sache return (0); 145521308Sache } 145621308Sache 145721308Sache rl_possible_completions (); 145821308Sache rl_point = save_pos; 145921308Sache 146021308Sache return (0); 146121308Sache} 146221308Sache#endif 146321308Sache 146421308Sache/* Functions to save and restore marks. */ 146521308Sacheint 146621308Sacherl_vi_set_mark (count, key) 146721308Sache int count, key; 146821308Sache{ 146921308Sache int ch; 147021308Sache 147175406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 147221308Sache ch = rl_read_key (); 147375406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 147475406Sache 1475119610Sache if (ch < 'a' || ch > 'z') 147621308Sache { 147775406Sache rl_ding (); 147821308Sache return -1; 147921308Sache } 148021308Sache ch -= 'a'; 148121308Sache vi_mark_chars[ch] = rl_point; 148221308Sache return 0; 148321308Sache} 148421308Sache 148521308Sacheint 148621308Sacherl_vi_goto_mark (count, key) 148721308Sache int count, key; 148821308Sache{ 148921308Sache int ch; 149021308Sache 149175406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 149221308Sache ch = rl_read_key (); 149375406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 149475406Sache 149521308Sache if (ch == '`') 149621308Sache { 149721308Sache rl_point = rl_mark; 149821308Sache return 0; 149921308Sache } 1500119610Sache else if (ch < 'a' || ch > 'z') 150121308Sache { 150275406Sache rl_ding (); 150321308Sache return -1; 150421308Sache } 150521308Sache 150621308Sache ch -= 'a'; 150721308Sache if (vi_mark_chars[ch] == -1) 150821308Sache { 150975406Sache rl_ding (); 151021308Sache return -1; 151121308Sache } 151221308Sache rl_point = vi_mark_chars[ch]; 151321308Sache return 0; 151421308Sache} 151521308Sache 151621308Sache#endif /* VI_MODE */ 1517