1125665Sache/* $FreeBSD$ */ 221308Sache/* vi_mode.c -- A vi emulation mode for Bash. 321308Sache Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ 421308Sache 5157188Sache/* Copyright (C) 1987-2005 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 67136759Speterint _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ 68136759Speter 6921308Sache/* Non-zero means enter insertion mode. */ 7021308Sachestatic int _rl_vi_doing_insert; 7121308Sache 7221308Sache/* Command keys which do movement for xxx_to commands. */ 73119610Sachestatic const char *vi_motion = " hl^$0ftFT;,%wbeWBE|"; 7421308Sache 7521308Sache/* Keymap used for vi replace characters. Created dynamically since 7621308Sache rarely used. */ 7721308Sachestatic Keymap vi_replace_map; 7821308Sache 7921308Sache/* The number of characters inserted in the last replace operation. */ 8021308Sachestatic int vi_replace_count; 8121308Sache 8221308Sache/* If non-zero, we have text inserted after a c[motion] command that put 8321308Sache us implicitly into insert mode. Some people want this text to be 8421308Sache attached to the command so that it is `redoable' with `.'. */ 8521308Sachestatic int vi_continued_command; 8621308Sachestatic char *vi_insert_buffer; 8721308Sachestatic int vi_insert_buffer_size; 8821308Sache 8921308Sachestatic int _rl_vi_last_repeat = 1; 9021308Sachestatic int _rl_vi_last_arg_sign = 1; 9121308Sachestatic int _rl_vi_last_motion; 92119610Sache#if defined (HANDLE_MULTIBYTE) 93119610Sachestatic char _rl_vi_last_search_mbchar[MB_LEN_MAX]; 94157188Sachestatic int _rl_vi_last_search_mblen; 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 *)); 112157188Sache 113165675Sachestatic void _rl_vi_backup PARAMS((void)); 114165675Sache 115157188Sachestatic int _rl_vi_arg_dispatch PARAMS((int)); 116119610Sachestatic int rl_digit_loop1 PARAMS((void)); 11721308Sache 118157188Sachestatic int _rl_vi_set_mark PARAMS((void)); 119157188Sachestatic int _rl_vi_goto_mark PARAMS((void)); 120157188Sache 121165675Sachestatic void _rl_vi_append_forward PARAMS((int)); 122165675Sache 123157188Sachestatic int _rl_vi_callback_getchar PARAMS((char *, int)); 124157188Sache 125157188Sache#if defined (READLINE_CALLBACKS) 126157188Sachestatic int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *)); 127157188Sachestatic int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *)); 128157188Sachestatic int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *)); 129157188Sachestatic int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *)); 130157188Sache#endif 131157188Sache 13221308Sachevoid 13321308Sache_rl_vi_initialize_line () 13421308Sache{ 13521308Sache register int i; 13621308Sache 13721308Sache for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) 13821308Sache vi_mark_chars[i] = -1; 139157188Sache 140157188Sache RL_UNSETSTATE(RL_STATE_VICMDONCE); 14121308Sache} 14221308Sache 14321308Sachevoid 14421308Sache_rl_vi_reset_last () 14521308Sache{ 14621308Sache _rl_vi_last_command = 'i'; 14721308Sache _rl_vi_last_repeat = 1; 14821308Sache _rl_vi_last_arg_sign = 1; 14921308Sache _rl_vi_last_motion = 0; 15021308Sache} 15121308Sache 15221308Sachevoid 15321308Sache_rl_vi_set_last (key, repeat, sign) 15421308Sache int key, repeat, sign; 15521308Sache{ 15621308Sache _rl_vi_last_command = key; 15721308Sache _rl_vi_last_repeat = repeat; 15821308Sache _rl_vi_last_arg_sign = sign; 15921308Sache} 16021308Sache 161136759Speter/* A convenience function that calls _rl_vi_set_last to save the last command 162136759Speter information and enters insertion mode. */ 163136759Spetervoid 164136759Speterrl_vi_start_inserting (key, repeat, sign) 165136759Speter int key, repeat, sign; 166136759Speter{ 167136759Speter _rl_vi_set_last (key, repeat, sign); 168136759Speter rl_vi_insertion_mode (1, key); 169136759Speter} 170136759Speter 17121308Sache/* Is the command C a VI mode text modification command? */ 17221308Sacheint 17321308Sache_rl_vi_textmod_command (c) 17421308Sache int c; 17521308Sache{ 17621308Sache return (member (c, vi_textmod)); 17721308Sache} 17821308Sache 17921308Sachestatic void 18021308Sache_rl_vi_stuff_insert (count) 18121308Sache int count; 18221308Sache{ 18321308Sache rl_begin_undo_group (); 18421308Sache while (count--) 18521308Sache rl_insert_text (vi_insert_buffer); 18621308Sache rl_end_undo_group (); 18721308Sache} 18821308Sache 18921308Sache/* Bound to `.'. Called from command mode, so we know that we have to 19021308Sache redo a text modification command. The default for _rl_vi_last_command 19121308Sache puts you back into insert mode. */ 19221308Sacheint 19321308Sacherl_vi_redo (count, c) 19421308Sache int count, c; 19521308Sache{ 196119610Sache int r; 197119610Sache 19821308Sache if (!rl_explicit_arg) 19921308Sache { 20021308Sache rl_numeric_arg = _rl_vi_last_repeat; 20121308Sache rl_arg_sign = _rl_vi_last_arg_sign; 20221308Sache } 20321308Sache 204119610Sache r = 0; 20521308Sache vi_redoing = 1; 20621308Sache /* If we're redoing an insert with `i', stuff in the inserted text 20721308Sache and do not go into insertion mode. */ 20821308Sache if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) 20921308Sache { 21021308Sache _rl_vi_stuff_insert (count); 21121308Sache /* And back up point over the last character inserted. */ 21221308Sache if (rl_point > 0) 213165675Sache _rl_vi_backup (); 21421308Sache } 215165675Sache /* Ditto for redoing an insert with `a', but move forward a character first 216165675Sache like the `a' command does. */ 217165675Sache else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer) 218165675Sache { 219165675Sache _rl_vi_append_forward ('a'); 220165675Sache _rl_vi_stuff_insert (count); 221165675Sache if (rl_point > 0) 222165675Sache _rl_vi_backup (); 223165675Sache } 22421308Sache else 225119610Sache r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); 22621308Sache vi_redoing = 0; 22721308Sache 228119610Sache return (r); 22921308Sache} 23021308Sache 23121308Sache/* A placeholder for further expansion. */ 23221308Sacheint 23321308Sacherl_vi_undo (count, key) 23421308Sache int count, key; 23521308Sache{ 23621308Sache return (rl_undo_command (count, key)); 23721308Sache} 23821308Sache 23921308Sache/* Yank the nth arg from the previous line into this line at point. */ 24021308Sacheint 24121308Sacherl_vi_yank_arg (count, key) 24221308Sache int count, key; 24321308Sache{ 24421308Sache /* Readline thinks that the first word on a line is the 0th, while vi 24521308Sache thinks the first word on a line is the 1st. Compensate. */ 24621308Sache if (rl_explicit_arg) 24721308Sache rl_yank_nth_arg (count - 1, 0); 24821308Sache else 24921308Sache rl_yank_nth_arg ('$', 0); 25021308Sache 25121308Sache return (0); 25221308Sache} 25321308Sache 25421308Sache/* With an argument, move back that many history lines, else move to the 25521308Sache beginning of history. */ 25621308Sacheint 25721308Sacherl_vi_fetch_history (count, c) 25821308Sache int count, c; 25921308Sache{ 26021308Sache int wanted; 26121308Sache 26221308Sache /* Giving an argument of n means we want the nth command in the history 26321308Sache file. The command number is interpreted the same way that the bash 26421308Sache `history' command does it -- that is, giving an argument count of 450 26521308Sache to this command would get the command listed as number 450 in the 26621308Sache output of `history'. */ 26721308Sache if (rl_explicit_arg) 26821308Sache { 26921308Sache wanted = history_base + where_history () - count; 27021308Sache if (wanted <= 0) 27121308Sache rl_beginning_of_history (0, 0); 27221308Sache else 27321308Sache rl_get_previous_history (wanted, c); 27421308Sache } 27521308Sache else 27621308Sache rl_beginning_of_history (count, 0); 27721308Sache return (0); 27821308Sache} 27921308Sache 28021308Sache/* Search again for the last thing searched for. */ 28121308Sacheint 28221308Sacherl_vi_search_again (count, key) 28321308Sache int count, key; 28421308Sache{ 28521308Sache switch (key) 28621308Sache { 28721308Sache case 'n': 28821308Sache rl_noninc_reverse_search_again (count, key); 28921308Sache break; 29021308Sache 29121308Sache case 'N': 29221308Sache rl_noninc_forward_search_again (count, key); 29321308Sache break; 29421308Sache } 29521308Sache return (0); 29621308Sache} 29721308Sache 29821308Sache/* Do a vi style search. */ 29921308Sacheint 30021308Sacherl_vi_search (count, key) 30121308Sache int count, key; 30221308Sache{ 30321308Sache switch (key) 30421308Sache { 30521308Sache case '?': 306136759Speter _rl_free_saved_history_line (); 30721308Sache rl_noninc_forward_search (count, key); 30821308Sache break; 30921308Sache 31021308Sache case '/': 311136759Speter _rl_free_saved_history_line (); 31221308Sache rl_noninc_reverse_search (count, key); 31321308Sache break; 31421308Sache 31521308Sache default: 31675406Sache rl_ding (); 31721308Sache break; 31821308Sache } 31921308Sache return (0); 32021308Sache} 32121308Sache 32221308Sache/* Completion, from vi's point of view. */ 32321308Sacheint 32421308Sacherl_vi_complete (ignore, key) 32521308Sache int ignore, key; 32621308Sache{ 32721308Sache if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) 32821308Sache { 32921308Sache if (!whitespace (rl_line_buffer[rl_point + 1])) 33021308Sache rl_vi_end_word (1, 'E'); 33121308Sache rl_point++; 33221308Sache } 33321308Sache 33421308Sache if (key == '*') 33521308Sache rl_complete_internal ('*'); /* Expansion and replacement. */ 33621308Sache else if (key == '=') 33721308Sache rl_complete_internal ('?'); /* List possible completions. */ 33821308Sache else if (key == '\\') 33921308Sache rl_complete_internal (TAB); /* Standard Readline completion. */ 34021308Sache else 34121308Sache rl_complete (0, key); 34221308Sache 34321308Sache if (key == '*' || key == '\\') 344136759Speter rl_vi_start_inserting (key, 1, rl_arg_sign); 345136759Speter 34621308Sache return (0); 34721308Sache} 34821308Sache 34921308Sache/* Tilde expansion for vi mode. */ 35021308Sacheint 35121308Sacherl_vi_tilde_expand (ignore, key) 35221308Sache int ignore, key; 35321308Sache{ 35421308Sache rl_tilde_expand (0, key); 355136759Speter rl_vi_start_inserting (key, 1, rl_arg_sign); 35621308Sache return (0); 35721308Sache} 35821308Sache 35921308Sache/* Previous word in vi mode. */ 36021308Sacheint 36121308Sacherl_vi_prev_word (count, key) 36221308Sache int count, key; 36321308Sache{ 36421308Sache if (count < 0) 36521308Sache return (rl_vi_next_word (-count, key)); 36621308Sache 36721308Sache if (rl_point == 0) 36821308Sache { 36975406Sache rl_ding (); 37021308Sache return (0); 37121308Sache } 37221308Sache 37321308Sache if (_rl_uppercase_p (key)) 37447558Sache rl_vi_bWord (count, key); 37521308Sache else 37647558Sache rl_vi_bword (count, key); 37721308Sache 37821308Sache return (0); 37921308Sache} 38021308Sache 38121308Sache/* Next word in vi mode. */ 38221308Sacheint 38321308Sacherl_vi_next_word (count, key) 38421308Sache int count, key; 38521308Sache{ 38621308Sache if (count < 0) 38721308Sache return (rl_vi_prev_word (-count, key)); 38821308Sache 38921308Sache if (rl_point >= (rl_end - 1)) 39021308Sache { 39175406Sache rl_ding (); 39221308Sache return (0); 39321308Sache } 39421308Sache 39521308Sache if (_rl_uppercase_p (key)) 39647558Sache rl_vi_fWord (count, key); 39721308Sache else 39847558Sache rl_vi_fword (count, key); 39921308Sache return (0); 40021308Sache} 40121308Sache 40221308Sache/* Move to the end of the ?next? word. */ 40321308Sacheint 40421308Sacherl_vi_end_word (count, key) 40521308Sache int count, key; 40621308Sache{ 40721308Sache if (count < 0) 40821308Sache { 40975406Sache rl_ding (); 41021308Sache return -1; 41121308Sache } 41221308Sache 41321308Sache if (_rl_uppercase_p (key)) 41447558Sache rl_vi_eWord (count, key); 41521308Sache else 41647558Sache rl_vi_eword (count, key); 41721308Sache return (0); 41821308Sache} 41921308Sache 42021308Sache/* Move forward a word the way that 'W' does. */ 42121308Sacheint 42247558Sacherl_vi_fWord (count, ignore) 42347558Sache int count, ignore; 42421308Sache{ 42521308Sache while (count-- && rl_point < (rl_end - 1)) 42621308Sache { 42721308Sache /* Skip until whitespace. */ 42821308Sache while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 42921308Sache rl_point++; 43021308Sache 43121308Sache /* Now skip whitespace. */ 43221308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 43321308Sache rl_point++; 43421308Sache } 43521308Sache return (0); 43621308Sache} 43721308Sache 43821308Sacheint 43947558Sacherl_vi_bWord (count, ignore) 44047558Sache int count, ignore; 44121308Sache{ 44221308Sache while (count-- && rl_point > 0) 44321308Sache { 44421308Sache /* If we are at the start of a word, move back to whitespace so 44521308Sache we will go back to the start of the previous word. */ 44621308Sache if (!whitespace (rl_line_buffer[rl_point]) && 44721308Sache whitespace (rl_line_buffer[rl_point - 1])) 44821308Sache rl_point--; 44921308Sache 45021308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 45121308Sache rl_point--; 45221308Sache 45321308Sache if (rl_point > 0) 45421308Sache { 45521308Sache while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); 45621308Sache rl_point++; 45721308Sache } 45821308Sache } 45921308Sache return (0); 46021308Sache} 46121308Sache 46221308Sacheint 46347558Sacherl_vi_eWord (count, ignore) 46447558Sache int count, ignore; 46521308Sache{ 46621308Sache while (count-- && rl_point < (rl_end - 1)) 46721308Sache { 46821308Sache if (!whitespace (rl_line_buffer[rl_point])) 46921308Sache rl_point++; 47021308Sache 47121308Sache /* Move to the next non-whitespace character (to the start of the 47221308Sache next word). */ 473136759Speter while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 474136759Speter rl_point++; 47521308Sache 47621308Sache if (rl_point && rl_point < rl_end) 47721308Sache { 47821308Sache /* Skip whitespace. */ 47921308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 48021308Sache rl_point++; 48121308Sache 48221308Sache /* Skip until whitespace. */ 48321308Sache while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) 48421308Sache rl_point++; 48521308Sache 48621308Sache /* Move back to the last character of the word. */ 48721308Sache rl_point--; 48821308Sache } 48921308Sache } 49021308Sache return (0); 49121308Sache} 49221308Sache 49321308Sacheint 49447558Sacherl_vi_fword (count, ignore) 49547558Sache int count, ignore; 49621308Sache{ 49721308Sache while (count-- && rl_point < (rl_end - 1)) 49821308Sache { 49921308Sache /* Move to white space (really non-identifer). */ 500119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 50121308Sache { 502119610Sache while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) 50321308Sache rl_point++; 50421308Sache } 50521308Sache else /* if (!whitespace (rl_line_buffer[rl_point])) */ 50621308Sache { 507119610Sache while (!_rl_isident (rl_line_buffer[rl_point]) && 50821308Sache !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 50921308Sache rl_point++; 51021308Sache } 51121308Sache 51221308Sache /* Move past whitespace. */ 51321308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 51421308Sache rl_point++; 51521308Sache } 51621308Sache return (0); 51721308Sache} 51821308Sache 51921308Sacheint 52047558Sacherl_vi_bword (count, ignore) 52147558Sache int count, ignore; 52221308Sache{ 52321308Sache while (count-- && rl_point > 0) 52421308Sache { 52521308Sache int last_is_ident; 52621308Sache 52721308Sache /* If we are at the start of a word, move back to whitespace 52821308Sache so we will go back to the start of the previous word. */ 52921308Sache if (!whitespace (rl_line_buffer[rl_point]) && 53021308Sache whitespace (rl_line_buffer[rl_point - 1])) 53121308Sache rl_point--; 53221308Sache 53321308Sache /* If this character and the previous character are `opposite', move 53421308Sache back so we don't get messed up by the rl_point++ down there in 53521308Sache the while loop. Without this code, words like `l;' screw up the 53621308Sache function. */ 537119610Sache last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]); 538119610Sache if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || 539119610Sache (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident)) 54021308Sache rl_point--; 54121308Sache 54221308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 54321308Sache rl_point--; 54421308Sache 54521308Sache if (rl_point > 0) 54621308Sache { 547119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 548119610Sache while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); 54921308Sache else 550119610Sache while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && 55121308Sache !whitespace (rl_line_buffer[rl_point])); 55221308Sache rl_point++; 55321308Sache } 55421308Sache } 55521308Sache return (0); 55621308Sache} 55721308Sache 55821308Sacheint 55947558Sacherl_vi_eword (count, ignore) 56047558Sache int count, ignore; 56121308Sache{ 56221308Sache while (count-- && rl_point < rl_end - 1) 56321308Sache { 56421308Sache if (!whitespace (rl_line_buffer[rl_point])) 56521308Sache rl_point++; 56621308Sache 56721308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 56821308Sache rl_point++; 56921308Sache 57021308Sache if (rl_point < rl_end) 57121308Sache { 572119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 573119610Sache while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); 57421308Sache else 575119610Sache while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) 57621308Sache && !whitespace (rl_line_buffer[rl_point])); 57721308Sache } 57821308Sache rl_point--; 57921308Sache } 58021308Sache return (0); 58121308Sache} 58221308Sache 58321308Sacheint 58421308Sacherl_vi_insert_beg (count, key) 58521308Sache int count, key; 58621308Sache{ 58721308Sache rl_beg_of_line (1, key); 58821308Sache rl_vi_insertion_mode (1, key); 58921308Sache return (0); 59021308Sache} 59121308Sache 592165675Sachestatic void 593165675Sache_rl_vi_append_forward (key) 594165675Sache int key; 59521308Sache{ 596165675Sache int point; 597165675Sache 59821308Sache if (rl_point < rl_end) 599119610Sache { 600119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 601119610Sache rl_point++; 602119610Sache else 603119610Sache { 604165675Sache point = rl_point; 605119610Sache rl_forward_char (1, key); 606119610Sache if (point == rl_point) 607119610Sache rl_point = rl_end; 608119610Sache } 609119610Sache } 610165675Sache} 611165675Sache 612165675Sacheint 613165675Sacherl_vi_append_mode (count, key) 614165675Sache int count, key; 615165675Sache{ 616165675Sache _rl_vi_append_forward (key); 617165675Sache rl_vi_start_inserting (key, 1, rl_arg_sign); 61821308Sache return (0); 61921308Sache} 62021308Sache 62121308Sacheint 62221308Sacherl_vi_append_eol (count, key) 62321308Sache int count, key; 62421308Sache{ 62521308Sache rl_end_of_line (1, key); 62621308Sache rl_vi_append_mode (1, key); 62721308Sache return (0); 62821308Sache} 62921308Sache 63021308Sache/* What to do in the case of C-d. */ 63121308Sacheint 63221308Sacherl_vi_eof_maybe (count, c) 63321308Sache int count, c; 63421308Sache{ 63521308Sache return (rl_newline (1, '\n')); 63621308Sache} 63721308Sache 63821308Sache/* Insertion mode stuff. */ 63921308Sache 64021308Sache/* Switching from one mode to the other really just involves 64121308Sache switching keymaps. */ 64221308Sacheint 64321308Sacherl_vi_insertion_mode (count, key) 64421308Sache int count, key; 64521308Sache{ 64621308Sache _rl_keymap = vi_insertion_keymap; 64721308Sache _rl_vi_last_key_before_insert = key; 64821308Sache return (0); 64921308Sache} 65021308Sache 65121308Sachestatic void 65221308Sache_rl_vi_save_insert (up) 65321308Sache UNDO_LIST *up; 65421308Sache{ 65521308Sache int len, start, end; 65621308Sache 657165675Sache if (up == 0 || up->what != UNDO_INSERT) 65835486Sache { 65935486Sache if (vi_insert_buffer_size >= 1) 66035486Sache vi_insert_buffer[0] = '\0'; 66135486Sache return; 66235486Sache } 66335486Sache 66421308Sache start = up->start; 66521308Sache end = up->end; 66621308Sache len = end - start + 1; 66721308Sache if (len >= vi_insert_buffer_size) 66821308Sache { 66921308Sache vi_insert_buffer_size += (len + 32) - (len % 32); 670119610Sache vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); 67121308Sache } 67221308Sache strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); 67321308Sache vi_insert_buffer[len-1] = '\0'; 67421308Sache} 67521308Sache 67621308Sachevoid 67721308Sache_rl_vi_done_inserting () 67821308Sache{ 67921308Sache if (_rl_vi_doing_insert) 68021308Sache { 681119610Sache /* The `C', `s', and `S' commands set this. */ 68221308Sache rl_end_undo_group (); 68321308Sache /* Now, the text between rl_undo_list->next->start and 68421308Sache rl_undo_list->next->end is what was inserted while in insert 68521308Sache mode. It gets copied to VI_INSERT_BUFFER because it depends 68621308Sache on absolute indices into the line which may change (though they 68721308Sache probably will not). */ 68821308Sache _rl_vi_doing_insert = 0; 68921308Sache _rl_vi_save_insert (rl_undo_list->next); 69021308Sache vi_continued_command = 1; 69121308Sache } 69221308Sache else 69321308Sache { 694136759Speter if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list) 69521308Sache _rl_vi_save_insert (rl_undo_list); 69621308Sache /* XXX - Other keys probably need to be checked. */ 69721308Sache else if (_rl_vi_last_key_before_insert == 'C') 69821308Sache rl_end_undo_group (); 69921308Sache while (_rl_undo_group_level > 0) 70021308Sache rl_end_undo_group (); 70121308Sache vi_continued_command = 0; 70221308Sache } 70321308Sache} 70421308Sache 70521308Sacheint 70621308Sacherl_vi_movement_mode (count, key) 70721308Sache int count, key; 70821308Sache{ 70921308Sache if (rl_point > 0) 710119610Sache rl_backward_char (1, key); 71121308Sache 71221308Sache _rl_keymap = vi_movement_keymap; 71321308Sache _rl_vi_done_inserting (); 714157188Sache 715157188Sache /* This is how POSIX.2 says `U' should behave -- everything up until the 716157188Sache first time you go into command mode should not be undone. */ 717157188Sache if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0) 718157188Sache rl_free_undo_list (); 719157188Sache 720157188Sache RL_SETSTATE (RL_STATE_VICMDONCE); 72121308Sache return (0); 72221308Sache} 72321308Sache 72421308Sacheint 72521308Sacherl_vi_arg_digit (count, c) 72621308Sache int count, c; 72721308Sache{ 72821308Sache if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) 72921308Sache return (rl_beg_of_line (1, c)); 73021308Sache else 73121308Sache return (rl_digit_argument (count, c)); 73221308Sache} 73321308Sache 734119610Sache/* Change the case of the next COUNT characters. */ 735119610Sache#if defined (HANDLE_MULTIBYTE) 736119610Sachestatic int 737119610Sache_rl_vi_change_mbchar_case (count) 738119610Sache int count; 739119610Sache{ 740119610Sache wchar_t wc; 741125665Sache char mb[MB_LEN_MAX+1]; 742165675Sache int mlen, p; 743119610Sache mbstate_t ps; 744119610Sache 745119610Sache memset (&ps, 0, sizeof (mbstate_t)); 746119610Sache if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) 747119610Sache count--; 748119610Sache while (count-- && rl_point < rl_end) 749119610Sache { 750119610Sache mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); 751119610Sache if (iswupper (wc)) 752119610Sache wc = towlower (wc); 753119610Sache else if (iswlower (wc)) 754119610Sache wc = towupper (wc); 755119610Sache else 756119610Sache { 757119610Sache /* Just skip over chars neither upper nor lower case */ 758119610Sache rl_forward_char (1, 0); 759119610Sache continue; 760119610Sache } 761119610Sache 762119610Sache /* Vi is kind of strange here. */ 763119610Sache if (wc) 764119610Sache { 765136759Speter p = rl_point; 766165675Sache mlen = wcrtomb (mb, wc, &ps); 767165675Sache if (mlen >= 0) 768165675Sache mb[mlen] = '\0'; 769119610Sache rl_begin_undo_group (); 770136759Speter rl_vi_delete (1, 0); 771136759Speter if (rl_point < p) /* Did we retreat at EOL? */ 772136759Speter rl_point++; /* XXX - should we advance more than 1 for mbchar? */ 773119610Sache rl_insert_text (mb); 774119610Sache rl_end_undo_group (); 775119610Sache rl_vi_check (); 776119610Sache } 777119610Sache else 778119610Sache rl_forward_char (1, 0); 779119610Sache } 780119610Sache 781119610Sache return 0; 782119610Sache} 783119610Sache#endif 784119610Sache 78521308Sacheint 78621308Sacherl_vi_change_case (count, ignore) 78721308Sache int count, ignore; 78821308Sache{ 789136759Speter int c, p; 79021308Sache 79121308Sache /* Don't try this on an empty line. */ 79221308Sache if (rl_point >= rl_end) 79321308Sache return (0); 79421308Sache 795136759Speter c = 0; 796119610Sache#if defined (HANDLE_MULTIBYTE) 797119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 798119610Sache return (_rl_vi_change_mbchar_case (count)); 799119610Sache#endif 800119610Sache 80121308Sache while (count-- && rl_point < rl_end) 80221308Sache { 80321308Sache if (_rl_uppercase_p (rl_line_buffer[rl_point])) 80421308Sache c = _rl_to_lower (rl_line_buffer[rl_point]); 80521308Sache else if (_rl_lowercase_p (rl_line_buffer[rl_point])) 80621308Sache c = _rl_to_upper (rl_line_buffer[rl_point]); 80721308Sache else 80821308Sache { 80921308Sache /* Just skip over characters neither upper nor lower case. */ 810119610Sache rl_forward_char (1, c); 81121308Sache continue; 81221308Sache } 81321308Sache 81421308Sache /* Vi is kind of strange here. */ 81521308Sache if (c) 81621308Sache { 817136759Speter p = rl_point; 81821308Sache rl_begin_undo_group (); 819136759Speter rl_vi_delete (1, c); 820136759Speter if (rl_point < p) /* Did we retreat at EOL? */ 821136759Speter rl_point++; 822119610Sache _rl_insert_char (1, c); 82321308Sache rl_end_undo_group (); 82421308Sache rl_vi_check (); 82521308Sache } 82621308Sache else 827119610Sache rl_forward_char (1, c); 82821308Sache } 82921308Sache return (0); 83021308Sache} 83121308Sache 83221308Sacheint 83321308Sacherl_vi_put (count, key) 83421308Sache int count, key; 83521308Sache{ 83621308Sache if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) 837119610Sache rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); 83821308Sache 839136759Speter while (count--) 840136759Speter rl_yank (1, key); 841136759Speter 842119610Sache rl_backward_char (1, key); 84321308Sache return (0); 84421308Sache} 84521308Sache 846165675Sachestatic void 847165675Sache_rl_vi_backup () 848165675Sache{ 849165675Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 850165675Sache rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 851165675Sache else 852165675Sache rl_point--; 853165675Sache} 854165675Sache 85521308Sacheint 85621308Sacherl_vi_check () 85721308Sache{ 85821308Sache if (rl_point && rl_point == rl_end) 859119610Sache { 860119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 861119610Sache rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 862119610Sache else 863119610Sache rl_point--; 864119610Sache } 86521308Sache return (0); 86621308Sache} 86721308Sache 86821308Sacheint 86921308Sacherl_vi_column (count, key) 87021308Sache int count, key; 87121308Sache{ 87221308Sache if (count > rl_end) 87321308Sache rl_end_of_line (1, key); 87421308Sache else 87521308Sache rl_point = count - 1; 87621308Sache return (0); 87721308Sache} 87821308Sache 87921308Sacheint 88021308Sacherl_vi_domove (key, nextkey) 88121308Sache int key, *nextkey; 88221308Sache{ 88321308Sache int c, save; 88421308Sache int old_end; 88521308Sache 88621308Sache rl_mark = rl_point; 88775406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 88821308Sache c = rl_read_key (); 88975406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 890173406Sache 891173406Sache if (c < 0) 892173406Sache { 893173406Sache *nextkey = 0; 894173406Sache return -1; 895173406Sache } 896173406Sache 89721308Sache *nextkey = c; 89821308Sache 89921308Sache if (!member (c, vi_motion)) 90021308Sache { 90121308Sache if (_rl_digit_p (c)) 90221308Sache { 90321308Sache save = rl_numeric_arg; 90421308Sache rl_numeric_arg = _rl_digit_value (c); 905136759Speter rl_explicit_arg = 1; 906157188Sache RL_SETSTATE (RL_STATE_NUMERICARG|RL_STATE_VIMOTION); 90721308Sache rl_digit_loop1 (); 908157188Sache RL_UNSETSTATE (RL_STATE_VIMOTION); 90921308Sache rl_numeric_arg *= save; 91075406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 91121308Sache c = rl_read_key (); /* real command */ 91275406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 913173406Sache if (c < 0) 914173406Sache { 915173406Sache *nextkey = 0; 916173406Sache return -1; 917173406Sache } 91821308Sache *nextkey = c; 91921308Sache } 92021308Sache else if (key == c && (key == 'd' || key == 'y' || key == 'c')) 92121308Sache { 92221308Sache rl_mark = rl_end; 92321308Sache rl_beg_of_line (1, c); 92421308Sache _rl_vi_last_motion = c; 92521308Sache return (0); 92621308Sache } 92721308Sache else 92821308Sache return (-1); 92921308Sache } 93021308Sache 93121308Sache _rl_vi_last_motion = c; 93221308Sache 93321308Sache /* Append a blank character temporarily so that the motion routines 93421308Sache work right at the end of the line. */ 93521308Sache old_end = rl_end; 93621308Sache rl_line_buffer[rl_end++] = ' '; 93721308Sache rl_line_buffer[rl_end] = '\0'; 93821308Sache 93921308Sache _rl_dispatch (c, _rl_keymap); 94021308Sache 94121308Sache /* Remove the blank that we added. */ 94221308Sache rl_end = old_end; 94321308Sache rl_line_buffer[rl_end] = '\0'; 94421308Sache if (rl_point > rl_end) 94521308Sache rl_point = rl_end; 94621308Sache 94721308Sache /* No change in position means the command failed. */ 94821308Sache if (rl_mark == rl_point) 94921308Sache return (-1); 95021308Sache 95121308Sache /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next 95221308Sache word. If we are not at the end of the line, and we are on a 95321308Sache non-whitespace character, move back one (presumably to whitespace). */ 95421308Sache if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && 95521308Sache !whitespace (rl_line_buffer[rl_point])) 95621308Sache rl_point--; 95721308Sache 95821308Sache /* If cw or cW, back up to the end of a word, so the behaviour of ce 95921308Sache or cE is the actual result. Brute-force, no subtlety. */ 96021308Sache if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) 96121308Sache { 96221308Sache /* Don't move farther back than where we started. */ 96321308Sache while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) 96421308Sache rl_point--; 96521308Sache 96621308Sache /* Posix.2 says that if cw or cW moves the cursor towards the end of 96721308Sache the line, the character under the cursor should be deleted. */ 96821308Sache if (rl_point == rl_mark) 96921308Sache rl_point++; 97021308Sache else 97121308Sache { 97221308Sache /* Move past the end of the word so that the kill doesn't 97321308Sache remove the last letter of the previous word. Only do this 97421308Sache if we are not at the end of the line. */ 97521308Sache if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) 97621308Sache rl_point++; 97721308Sache } 97821308Sache } 97921308Sache 98021308Sache if (rl_mark < rl_point) 981119610Sache SWAP (rl_point, rl_mark); 98221308Sache 98321308Sache return (0); 98421308Sache} 98521308Sache 986157188Sache/* Process C as part of the current numeric argument. Return -1 if the 987157188Sache argument should be aborted, 0 if we should not read any more chars, and 988157188Sache 1 if we should continue to read chars. */ 989157188Sachestatic int 990157188Sache_rl_vi_arg_dispatch (c) 991157188Sache int c; 992157188Sache{ 993157188Sache int key; 994157188Sache 995157188Sache key = c; 996157188Sache if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument) 997157188Sache { 998157188Sache rl_numeric_arg *= 4; 999157188Sache return 1; 1000157188Sache } 1001157188Sache 1002157188Sache c = UNMETA (c); 1003157188Sache 1004157188Sache if (_rl_digit_p (c)) 1005157188Sache { 1006157188Sache if (rl_explicit_arg) 1007157188Sache rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); 1008157188Sache else 1009157188Sache rl_numeric_arg = _rl_digit_value (c); 1010157188Sache rl_explicit_arg = 1; 1011157188Sache return 1; 1012157188Sache } 1013157188Sache else 1014157188Sache { 1015157188Sache rl_clear_message (); 1016157188Sache rl_stuff_char (key); 1017157188Sache return 0; 1018157188Sache } 1019157188Sache} 1020157188Sache 102121308Sache/* A simplified loop for vi. Don't dispatch key at end. 102275406Sache Don't recognize minus sign? 102375406Sache Should this do rl_save_prompt/rl_restore_prompt? */ 102421308Sachestatic int 102521308Sacherl_digit_loop1 () 102621308Sache{ 1027157188Sache int c, r; 102821308Sache 102921308Sache while (1) 103021308Sache { 1031157188Sache if (_rl_arg_overflow ()) 1032157188Sache return 1; 103321308Sache 1034157188Sache c = _rl_arg_getchar (); 103521308Sache 1036157188Sache r = _rl_vi_arg_dispatch (c); 1037157188Sache if (r <= 0) 1038157188Sache break; 103921308Sache } 104075406Sache 104175406Sache RL_UNSETSTATE(RL_STATE_NUMERICARG); 104221308Sache return (0); 104321308Sache} 104421308Sache 104521308Sacheint 104621308Sacherl_vi_delete_to (count, key) 104721308Sache int count, key; 104821308Sache{ 104921308Sache int c; 105021308Sache 105121308Sache if (_rl_uppercase_p (key)) 105221308Sache rl_stuff_char ('$'); 105321308Sache else if (vi_redoing) 105421308Sache rl_stuff_char (_rl_vi_last_motion); 105521308Sache 105621308Sache if (rl_vi_domove (key, &c)) 105721308Sache { 105875406Sache rl_ding (); 105921308Sache return -1; 106021308Sache } 106121308Sache 106221308Sache /* These are the motion commands that do not require adjusting the 106321308Sache mark. */ 106421308Sache if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) 106521308Sache rl_mark++; 106621308Sache 106721308Sache rl_kill_text (rl_point, rl_mark); 106821308Sache return (0); 106921308Sache} 107021308Sache 107121308Sacheint 107221308Sacherl_vi_change_to (count, key) 107321308Sache int count, key; 107421308Sache{ 107521308Sache int c, start_pos; 107621308Sache 107721308Sache if (_rl_uppercase_p (key)) 107821308Sache rl_stuff_char ('$'); 107921308Sache else if (vi_redoing) 108021308Sache rl_stuff_char (_rl_vi_last_motion); 108121308Sache 108221308Sache start_pos = rl_point; 108321308Sache 108421308Sache if (rl_vi_domove (key, &c)) 108521308Sache { 108675406Sache rl_ding (); 108721308Sache return -1; 108821308Sache } 108921308Sache 109021308Sache /* These are the motion commands that do not require adjusting the 109121308Sache mark. c[wW] are handled by special-case code in rl_vi_domove(), 109221308Sache and already leave the mark at the correct location. */ 109321308Sache if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) 109421308Sache rl_mark++; 109521308Sache 109621308Sache /* The cursor never moves with c[wW]. */ 109721308Sache if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) 109821308Sache rl_point = start_pos; 109921308Sache 110021308Sache if (vi_redoing) 110121308Sache { 110221308Sache if (vi_insert_buffer && *vi_insert_buffer) 110321308Sache rl_begin_undo_group (); 110421308Sache rl_delete_text (rl_point, rl_mark); 110521308Sache if (vi_insert_buffer && *vi_insert_buffer) 110621308Sache { 110721308Sache rl_insert_text (vi_insert_buffer); 110821308Sache rl_end_undo_group (); 110921308Sache } 111021308Sache } 111121308Sache else 111221308Sache { 111321308Sache rl_begin_undo_group (); /* to make the `u' command work */ 111421308Sache rl_kill_text (rl_point, rl_mark); 111521308Sache /* `C' does not save the text inserted for undoing or redoing. */ 111621308Sache if (_rl_uppercase_p (key) == 0) 111721308Sache _rl_vi_doing_insert = 1; 1118136759Speter rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign); 111921308Sache } 112021308Sache 112121308Sache return (0); 112221308Sache} 112321308Sache 112421308Sacheint 112521308Sacherl_vi_yank_to (count, key) 112621308Sache int count, key; 112721308Sache{ 1128157188Sache int c, save; 112921308Sache 1130157188Sache save = rl_point; 113121308Sache if (_rl_uppercase_p (key)) 113221308Sache rl_stuff_char ('$'); 113321308Sache 113421308Sache if (rl_vi_domove (key, &c)) 113521308Sache { 113675406Sache rl_ding (); 113721308Sache return -1; 113821308Sache } 113921308Sache 114021308Sache /* These are the motion commands that do not require adjusting the 114121308Sache mark. */ 114221308Sache if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) 114321308Sache rl_mark++; 114421308Sache 114521308Sache rl_begin_undo_group (); 114621308Sache rl_kill_text (rl_point, rl_mark); 114721308Sache rl_end_undo_group (); 114821308Sache rl_do_undo (); 114921308Sache rl_point = save; 115021308Sache 115121308Sache return (0); 115221308Sache} 115321308Sache 115421308Sacheint 1155157188Sacherl_vi_rubout (count, key) 1156157188Sache int count, key; 1157157188Sache{ 1158165675Sache int opoint; 1159157188Sache 1160157188Sache if (count < 0) 1161157188Sache return (rl_vi_delete (-count, key)); 1162157188Sache 1163157188Sache if (rl_point == 0) 1164157188Sache { 1165157188Sache rl_ding (); 1166157188Sache return -1; 1167157188Sache } 1168157188Sache 1169157188Sache opoint = rl_point; 1170157188Sache if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1171157188Sache rl_backward_char (count, key); 1172157188Sache else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1173157188Sache rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 1174157188Sache else 1175157188Sache rl_point -= count; 1176157188Sache 1177157188Sache if (rl_point < 0) 1178157188Sache rl_point = 0; 1179157188Sache 1180157188Sache rl_kill_text (rl_point, opoint); 1181157188Sache 1182157188Sache return (0); 1183157188Sache} 1184157188Sache 1185157188Sacheint 118621308Sacherl_vi_delete (count, key) 118721308Sache int count, key; 118821308Sache{ 118921308Sache int end; 119021308Sache 1191157188Sache if (count < 0) 1192157188Sache return (rl_vi_rubout (-count, key)); 1193157188Sache 119421308Sache if (rl_end == 0) 119521308Sache { 119675406Sache rl_ding (); 119721308Sache return -1; 119821308Sache } 119921308Sache 1200119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1201119610Sache end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); 1202119610Sache else 1203119610Sache end = rl_point + count; 120421308Sache 120521308Sache if (end >= rl_end) 120621308Sache end = rl_end; 120721308Sache 120821308Sache rl_kill_text (rl_point, end); 120921308Sache 121021308Sache if (rl_point > 0 && rl_point == rl_end) 1211119610Sache rl_backward_char (1, key); 1212157188Sache 121321308Sache return (0); 121421308Sache} 121521308Sache 121621308Sacheint 121721308Sacherl_vi_back_to_indent (count, key) 121821308Sache int count, key; 121921308Sache{ 122021308Sache rl_beg_of_line (1, key); 122121308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 122221308Sache rl_point++; 122321308Sache return (0); 122421308Sache} 122521308Sache 122621308Sacheint 122721308Sacherl_vi_first_print (count, key) 122821308Sache int count, key; 122921308Sache{ 123021308Sache return (rl_vi_back_to_indent (1, key)); 123121308Sache} 123221308Sache 1233157188Sachestatic int _rl_cs_dir, _rl_cs_orig_dir; 1234157188Sache 1235157188Sache#if defined (READLINE_CALLBACKS) 1236157188Sachestatic int 1237157188Sache_rl_vi_callback_char_search (data) 1238157188Sache _rl_callback_generic_arg *data; 1239157188Sache{ 1240173406Sache int c; 1241157188Sache#if defined (HANDLE_MULTIBYTE) 1242173406Sache c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1243157188Sache#else 1244157188Sache RL_SETSTATE(RL_STATE_MOREINPUT); 1245173406Sache c = rl_read_key (); 1246157188Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 1247157188Sache#endif 1248157188Sache 1249173406Sache if (c <= 0) 1250173406Sache return -1; 1251173406Sache 1252173406Sache#if !defined (HANDLE_MULTIBYTE) 1253173406Sache _rl_vi_last_search_char = c; 1254173406Sache#endif 1255173406Sache 1256157188Sache _rl_callback_func = 0; 1257157188Sache _rl_want_redisplay = 1; 1258157188Sache 1259157188Sache#if defined (HANDLE_MULTIBYTE) 1260157188Sache return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen)); 1261157188Sache#else 1262157188Sache return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char)); 1263157188Sache#endif 1264157188Sache} 1265157188Sache#endif 1266157188Sache 126721308Sacheint 126821308Sacherl_vi_char_search (count, key) 126921308Sache int count, key; 127021308Sache{ 1271173406Sache int c; 1272119610Sache#if defined (HANDLE_MULTIBYTE) 1273119610Sache static char *target; 1274157188Sache static int tlen; 1275119610Sache#else 127621308Sache static char target; 1277119610Sache#endif 127821308Sache 127921308Sache if (key == ';' || key == ',') 1280157188Sache _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir; 128121308Sache else 128221308Sache { 128321308Sache switch (key) 128421308Sache { 128521308Sache case 't': 1286157188Sache _rl_cs_orig_dir = _rl_cs_dir = FTO; 128721308Sache break; 128821308Sache 128921308Sache case 'T': 1290157188Sache _rl_cs_orig_dir = _rl_cs_dir = BTO; 129121308Sache break; 129221308Sache 129321308Sache case 'f': 1294157188Sache _rl_cs_orig_dir = _rl_cs_dir = FFIND; 129521308Sache break; 129621308Sache 129721308Sache case 'F': 1298157188Sache _rl_cs_orig_dir = _rl_cs_dir = BFIND; 129921308Sache break; 130021308Sache } 1301157188Sache 1302157188Sache if (vi_redoing) 1303157188Sache { 1304157188Sache /* set target and tlen below */ 1305157188Sache } 1306157188Sache#if defined (READLINE_CALLBACKS) 1307157188Sache else if (RL_ISSTATE (RL_STATE_CALLBACK)) 1308157188Sache { 1309157188Sache _rl_callback_data = _rl_callback_data_alloc (count); 1310157188Sache _rl_callback_data->i1 = _rl_cs_dir; 1311157188Sache _rl_callback_func = _rl_vi_callback_char_search; 1312157188Sache return (0); 1313157188Sache } 1314157188Sache#endif 1315157188Sache else 1316157188Sache { 1317157188Sache#if defined (HANDLE_MULTIBYTE) 1318173406Sache c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1319173406Sache if (c <= 0) 1320173406Sache return -1; 1321173406Sache _rl_vi_last_search_mblen = c; 1322157188Sache#else 1323157188Sache RL_SETSTATE(RL_STATE_MOREINPUT); 1324173406Sache c = rl_read_key (); 1325157188Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 1326173406Sache if (c < 0) 1327173406Sache return -1; 1328173406Sache _rl_vi_last_search_char = c; 1329157188Sache#endif 1330157188Sache } 133121308Sache } 133221308Sache 1333119610Sache#if defined (HANDLE_MULTIBYTE) 1334157188Sache target = _rl_vi_last_search_mbchar; 1335157188Sache tlen = _rl_vi_last_search_mblen; 1336119610Sache#else 1337157188Sache target = _rl_vi_last_search_char; 1338119610Sache#endif 1339157188Sache 1340157188Sache#if defined (HANDLE_MULTIBYTE) 1341157188Sache return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen)); 1342157188Sache#else 1343157188Sache return (_rl_char_search_internal (count, _rl_cs_dir, target)); 1344157188Sache#endif 134521308Sache} 134621308Sache 134721308Sache/* Match brackets */ 134821308Sacheint 134921308Sacherl_vi_match (ignore, key) 135021308Sache int ignore, key; 135121308Sache{ 1352119610Sache int count = 1, brack, pos, tmp, pre; 135321308Sache 135421308Sache pos = rl_point; 135521308Sache if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 135621308Sache { 1357119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1358119610Sache { 1359119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1360119610Sache { 1361119610Sache pre = rl_point; 1362119610Sache rl_forward_char (1, key); 1363119610Sache if (pre == rl_point) 1364119610Sache break; 1365119610Sache } 1366119610Sache } 1367119610Sache else 1368119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && 1369119610Sache rl_point < rl_end - 1) 1370119610Sache rl_forward_char (1, key); 137121308Sache 137221308Sache if (brack <= 0) 137321308Sache { 137421308Sache rl_point = pos; 137575406Sache rl_ding (); 137621308Sache return -1; 137721308Sache } 137821308Sache } 137921308Sache 138021308Sache pos = rl_point; 138121308Sache 138221308Sache if (brack < 0) 138321308Sache { 138421308Sache while (count) 138521308Sache { 1386119610Sache tmp = pos; 1387119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1388119610Sache pos--; 1389119610Sache else 139021308Sache { 1391119610Sache pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); 1392119610Sache if (tmp == pos) 1393119610Sache pos--; 1394119610Sache } 1395119610Sache if (pos >= 0) 1396119610Sache { 139721308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 139821308Sache if (b == -brack) 139921308Sache count--; 140021308Sache else if (b == brack) 140121308Sache count++; 140221308Sache } 140321308Sache else 140421308Sache { 140575406Sache rl_ding (); 140621308Sache return -1; 140721308Sache } 140821308Sache } 140921308Sache } 141021308Sache else 141121308Sache { /* brack > 0 */ 141221308Sache while (count) 141321308Sache { 1414119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1415119610Sache pos++; 1416119610Sache else 1417119610Sache pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); 1418119610Sache 1419119610Sache if (pos < rl_end) 142021308Sache { 142121308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 142221308Sache if (b == -brack) 142321308Sache count--; 142421308Sache else if (b == brack) 142521308Sache count++; 142621308Sache } 142721308Sache else 142821308Sache { 142975406Sache rl_ding (); 143021308Sache return -1; 143121308Sache } 143221308Sache } 143321308Sache } 143421308Sache rl_point = pos; 143521308Sache return (0); 143621308Sache} 143721308Sache 143821308Sacheint 143921308Sacherl_vi_bracktype (c) 144021308Sache int c; 144121308Sache{ 144221308Sache switch (c) 144321308Sache { 144421308Sache case '(': return 1; 144521308Sache case ')': return -1; 144621308Sache case '[': return 2; 144721308Sache case ']': return -2; 144821308Sache case '{': return 3; 144921308Sache case '}': return -3; 145021308Sache default: return 0; 145121308Sache } 145221308Sache} 145321308Sache 1454157188Sachestatic int 1455157188Sache_rl_vi_change_char (count, c, mb) 1456157188Sache int count, c; 1457157188Sache char *mb; 145821308Sache{ 1459157188Sache int p; 146021308Sache 146121308Sache if (c == '\033' || c == CTRL ('C')) 146221308Sache return -1; 146321308Sache 1464136759Speter rl_begin_undo_group (); 146521308Sache while (count-- && rl_point < rl_end) 146621308Sache { 1467136759Speter p = rl_point; 1468136759Speter rl_vi_delete (1, c); 1469157188Sache if (rl_point < p) /* Did we retreat at EOL? */ 1470157188Sache rl_point++; 1471119610Sache#if defined (HANDLE_MULTIBYTE) 1472119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1473157188Sache rl_insert_text (mb); 1474119610Sache else 1475119610Sache#endif 1476157188Sache _rl_insert_char (1, c); 1477136759Speter } 1478157188Sache 1479157188Sache /* The cursor shall be left on the last character changed. */ 1480157188Sache rl_backward_char (1, c); 1481157188Sache 1482136759Speter rl_end_undo_group (); 148321308Sache 148421308Sache return (0); 148521308Sache} 148621308Sache 1487157188Sachestatic int 1488165675Sache_rl_vi_callback_getchar (mb, mlen) 1489157188Sache char *mb; 1490165675Sache int mlen; 1491157188Sache{ 1492157188Sache int c; 1493157188Sache 1494157188Sache RL_SETSTATE(RL_STATE_MOREINPUT); 1495157188Sache c = rl_read_key (); 1496157188Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 1497157188Sache 1498173406Sache if (c < 0) 1499173406Sache return -1; 1500173406Sache 1501157188Sache#if defined (HANDLE_MULTIBYTE) 1502157188Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1503165675Sache c = _rl_read_mbstring (c, mb, mlen); 1504157188Sache#endif 1505157188Sache 1506157188Sache return c; 1507157188Sache} 1508157188Sache 1509157188Sache#if defined (READLINE_CALLBACKS) 1510157188Sachestatic int 1511157188Sache_rl_vi_callback_change_char (data) 1512157188Sache _rl_callback_generic_arg *data; 1513157188Sache{ 1514157188Sache int c; 1515157188Sache char mb[MB_LEN_MAX]; 1516157188Sache 1517157188Sache _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); 1518157188Sache 1519173406Sache if (c < 0) 1520173406Sache return -1; 1521173406Sache 1522157188Sache _rl_callback_func = 0; 1523157188Sache _rl_want_redisplay = 1; 1524157188Sache 1525157188Sache return (_rl_vi_change_char (data->count, c, mb)); 1526157188Sache} 1527157188Sache#endif 1528157188Sache 152921308Sacheint 1530157188Sacherl_vi_change_char (count, key) 1531157188Sache int count, key; 1532157188Sache{ 1533157188Sache int c; 1534157188Sache char mb[MB_LEN_MAX]; 1535157188Sache 1536157188Sache if (vi_redoing) 1537157188Sache { 1538157188Sache c = _rl_vi_last_replacement; 1539157188Sache mb[0] = c; 1540157188Sache mb[1] = '\0'; 1541157188Sache } 1542157188Sache#if defined (READLINE_CALLBACKS) 1543157188Sache else if (RL_ISSTATE (RL_STATE_CALLBACK)) 1544157188Sache { 1545157188Sache _rl_callback_data = _rl_callback_data_alloc (count); 1546157188Sache _rl_callback_func = _rl_vi_callback_change_char; 1547157188Sache return (0); 1548157188Sache } 1549157188Sache#endif 1550157188Sache else 1551157188Sache _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); 1552157188Sache 1553173406Sache if (c < 0) 1554173406Sache return -1; 1555173406Sache 1556157188Sache return (_rl_vi_change_char (count, c, mb)); 1557157188Sache} 1558157188Sache 1559157188Sacheint 156021308Sacherl_vi_subst (count, key) 156121308Sache int count, key; 156221308Sache{ 1563119610Sache /* If we are redoing, rl_vi_change_to will stuff the last motion char */ 1564119610Sache if (vi_redoing == 0) 1565136759Speter rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */ 156621308Sache 1567119610Sache return (rl_vi_change_to (count, 'c')); 156821308Sache} 156921308Sache 157021308Sacheint 157121308Sacherl_vi_overstrike (count, key) 157221308Sache int count, key; 157321308Sache{ 157421308Sache if (_rl_vi_doing_insert == 0) 157521308Sache { 157621308Sache _rl_vi_doing_insert = 1; 157721308Sache rl_begin_undo_group (); 157821308Sache } 157921308Sache 1580119610Sache if (count > 0) 158121308Sache { 1582119610Sache _rl_overwrite_char (count, key); 1583119610Sache vi_replace_count += count; 1584119610Sache } 158521308Sache 158621308Sache return (0); 158721308Sache} 158821308Sache 158921308Sacheint 159021308Sacherl_vi_overstrike_delete (count, key) 159121308Sache int count, key; 159221308Sache{ 159321308Sache int i, s; 159421308Sache 159521308Sache for (i = 0; i < count; i++) 159621308Sache { 159721308Sache if (vi_replace_count == 0) 159821308Sache { 159975406Sache rl_ding (); 160021308Sache break; 160121308Sache } 160221308Sache s = rl_point; 160321308Sache 160421308Sache if (rl_do_undo ()) 160521308Sache vi_replace_count--; 160621308Sache 160721308Sache if (rl_point == s) 1608119610Sache rl_backward_char (1, key); 160921308Sache } 161021308Sache 161121308Sache if (vi_replace_count == 0 && _rl_vi_doing_insert) 161221308Sache { 161321308Sache rl_end_undo_group (); 161421308Sache rl_do_undo (); 161521308Sache _rl_vi_doing_insert = 0; 161621308Sache } 161721308Sache return (0); 161821308Sache} 161921308Sache 162021308Sacheint 162121308Sacherl_vi_replace (count, key) 162221308Sache int count, key; 162321308Sache{ 162421308Sache int i; 162521308Sache 162621308Sache vi_replace_count = 0; 162721308Sache 162821308Sache if (!vi_replace_map) 162921308Sache { 163021308Sache vi_replace_map = rl_make_bare_keymap (); 163121308Sache 163221308Sache for (i = ' '; i < KEYMAP_SIZE; i++) 163321308Sache vi_replace_map[i].function = rl_vi_overstrike; 163421308Sache 163521308Sache vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; 163621308Sache vi_replace_map[ESC].function = rl_vi_movement_mode; 163721308Sache vi_replace_map[RETURN].function = rl_newline; 163821308Sache vi_replace_map[NEWLINE].function = rl_newline; 163921308Sache 164021308Sache /* If the normal vi insertion keymap has ^H bound to erase, do the 164121308Sache same here. Probably should remove the assignment to RUBOUT up 164221308Sache there, but I don't think it will make a difference in real life. */ 164321308Sache if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && 164421308Sache vi_insertion_keymap[CTRL ('H')].function == rl_rubout) 164521308Sache vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; 164621308Sache 164721308Sache } 164821308Sache _rl_keymap = vi_replace_map; 164921308Sache return (0); 165021308Sache} 165121308Sache 165221308Sache#if 0 165321308Sache/* Try to complete the word we are standing on or the word that ends with 165421308Sache the previous character. A space matches everything. Word delimiters are 165521308Sache space and ;. */ 165621308Sacheint 165721308Sacherl_vi_possible_completions() 165821308Sache{ 165921308Sache int save_pos = rl_point; 166021308Sache 166121308Sache if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') 166221308Sache { 166321308Sache while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && 166421308Sache rl_line_buffer[rl_point] != ';') 166521308Sache rl_point++; 166621308Sache } 166721308Sache else if (rl_line_buffer[rl_point - 1] == ';') 166821308Sache { 166975406Sache rl_ding (); 167021308Sache return (0); 167121308Sache } 167221308Sache 167321308Sache rl_possible_completions (); 167421308Sache rl_point = save_pos; 167521308Sache 167621308Sache return (0); 167721308Sache} 167821308Sache#endif 167921308Sache 168021308Sache/* Functions to save and restore marks. */ 1681157188Sachestatic int 1682157188Sache_rl_vi_set_mark () 168321308Sache{ 168421308Sache int ch; 168521308Sache 168675406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 168721308Sache ch = rl_read_key (); 168875406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 168975406Sache 1690173406Sache if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ 169121308Sache { 169275406Sache rl_ding (); 169321308Sache return -1; 169421308Sache } 169521308Sache ch -= 'a'; 169621308Sache vi_mark_chars[ch] = rl_point; 169721308Sache return 0; 169821308Sache} 169921308Sache 1700157188Sache#if defined (READLINE_CALLBACKS) 1701157188Sachestatic int 1702157188Sache_rl_vi_callback_set_mark (data) 1703157188Sache _rl_callback_generic_arg *data; 1704157188Sache{ 1705157188Sache _rl_callback_func = 0; 1706157188Sache _rl_want_redisplay = 1; 1707157188Sache 1708157188Sache return (_rl_vi_set_mark ()); 1709157188Sache} 1710157188Sache#endif 1711157188Sache 171221308Sacheint 1713157188Sacherl_vi_set_mark (count, key) 171421308Sache int count, key; 171521308Sache{ 1716157188Sache#if defined (READLINE_CALLBACKS) 1717157188Sache if (RL_ISSTATE (RL_STATE_CALLBACK)) 1718157188Sache { 1719157188Sache _rl_callback_data = 0; 1720157188Sache _rl_callback_func = _rl_vi_callback_set_mark; 1721157188Sache return (0); 1722157188Sache } 1723157188Sache#endif 1724157188Sache 1725157188Sache return (_rl_vi_set_mark ()); 1726157188Sache} 1727157188Sache 1728157188Sachestatic int 1729157188Sache_rl_vi_goto_mark () 1730157188Sache{ 173121308Sache int ch; 173221308Sache 173375406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 173421308Sache ch = rl_read_key (); 173575406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 173675406Sache 173721308Sache if (ch == '`') 173821308Sache { 173921308Sache rl_point = rl_mark; 174021308Sache return 0; 174121308Sache } 1742173406Sache else if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ 174321308Sache { 174475406Sache rl_ding (); 174521308Sache return -1; 174621308Sache } 174721308Sache 174821308Sache ch -= 'a'; 174921308Sache if (vi_mark_chars[ch] == -1) 175021308Sache { 175175406Sache rl_ding (); 175221308Sache return -1; 175321308Sache } 175421308Sache rl_point = vi_mark_chars[ch]; 175521308Sache return 0; 175621308Sache} 175721308Sache 1758157188Sache#if defined (READLINE_CALLBACKS) 1759157188Sachestatic int 1760157188Sache_rl_vi_callback_goto_mark (data) 1761157188Sache _rl_callback_generic_arg *data; 1762157188Sache{ 1763157188Sache _rl_callback_func = 0; 1764157188Sache _rl_want_redisplay = 1; 1765157188Sache 1766157188Sache return (_rl_vi_goto_mark ()); 1767157188Sache} 1768157188Sache#endif 1769157188Sache 1770157188Sacheint 1771157188Sacherl_vi_goto_mark (count, key) 1772157188Sache int count, key; 1773157188Sache{ 1774157188Sache#if defined (READLINE_CALLBACKS) 1775157188Sache if (RL_ISSTATE (RL_STATE_CALLBACK)) 1776157188Sache { 1777157188Sache _rl_callback_data = 0; 1778157188Sache _rl_callback_func = _rl_vi_callback_goto_mark; 1779157188Sache return (0); 1780157188Sache } 1781157188Sache#endif 1782157188Sache 1783157188Sache return (_rl_vi_goto_mark ()); 1784157188Sache} 178521308Sache#endif /* VI_MODE */ 1786