vi_mode.c revision 157188
1125665Sache/* $FreeBSD: head/contrib/libreadline/vi_mode.c 157188 2006-03-27 23:11:32Z ache $ */ 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 113157188Sachestatic int _rl_vi_arg_dispatch PARAMS((int)); 114119610Sachestatic int rl_digit_loop1 PARAMS((void)); 11521308Sache 116157188Sachestatic int _rl_vi_set_mark PARAMS((void)); 117157188Sachestatic int _rl_vi_goto_mark PARAMS((void)); 118157188Sache 119157188Sachestatic int _rl_vi_callback_getchar PARAMS((char *, int)); 120157188Sache 121157188Sache#if defined (READLINE_CALLBACKS) 122157188Sachestatic int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *)); 123157188Sachestatic int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *)); 124157188Sachestatic int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *)); 125157188Sachestatic int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *)); 126157188Sache#endif 127157188Sache 12821308Sachevoid 12921308Sache_rl_vi_initialize_line () 13021308Sache{ 13121308Sache register int i; 13221308Sache 13321308Sache for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) 13421308Sache vi_mark_chars[i] = -1; 135157188Sache 136157188Sache RL_UNSETSTATE(RL_STATE_VICMDONCE); 13721308Sache} 13821308Sache 13921308Sachevoid 14021308Sache_rl_vi_reset_last () 14121308Sache{ 14221308Sache _rl_vi_last_command = 'i'; 14321308Sache _rl_vi_last_repeat = 1; 14421308Sache _rl_vi_last_arg_sign = 1; 14521308Sache _rl_vi_last_motion = 0; 14621308Sache} 14721308Sache 14821308Sachevoid 14921308Sache_rl_vi_set_last (key, repeat, sign) 15021308Sache int key, repeat, sign; 15121308Sache{ 15221308Sache _rl_vi_last_command = key; 15321308Sache _rl_vi_last_repeat = repeat; 15421308Sache _rl_vi_last_arg_sign = sign; 15521308Sache} 15621308Sache 157136759Speter/* A convenience function that calls _rl_vi_set_last to save the last command 158136759Speter information and enters insertion mode. */ 159136759Spetervoid 160136759Speterrl_vi_start_inserting (key, repeat, sign) 161136759Speter int key, repeat, sign; 162136759Speter{ 163136759Speter _rl_vi_set_last (key, repeat, sign); 164136759Speter rl_vi_insertion_mode (1, key); 165136759Speter} 166136759Speter 16721308Sache/* Is the command C a VI mode text modification command? */ 16821308Sacheint 16921308Sache_rl_vi_textmod_command (c) 17021308Sache int c; 17121308Sache{ 17221308Sache return (member (c, vi_textmod)); 17321308Sache} 17421308Sache 17521308Sachestatic void 17621308Sache_rl_vi_stuff_insert (count) 17721308Sache int count; 17821308Sache{ 17921308Sache rl_begin_undo_group (); 18021308Sache while (count--) 18121308Sache rl_insert_text (vi_insert_buffer); 18221308Sache rl_end_undo_group (); 18321308Sache} 18421308Sache 18521308Sache/* Bound to `.'. Called from command mode, so we know that we have to 18621308Sache redo a text modification command. The default for _rl_vi_last_command 18721308Sache puts you back into insert mode. */ 18821308Sacheint 18921308Sacherl_vi_redo (count, c) 19021308Sache int count, c; 19121308Sache{ 192119610Sache int r; 193119610Sache 19421308Sache if (!rl_explicit_arg) 19521308Sache { 19621308Sache rl_numeric_arg = _rl_vi_last_repeat; 19721308Sache rl_arg_sign = _rl_vi_last_arg_sign; 19821308Sache } 19921308Sache 200119610Sache r = 0; 20121308Sache vi_redoing = 1; 20221308Sache /* If we're redoing an insert with `i', stuff in the inserted text 20321308Sache and do not go into insertion mode. */ 20421308Sache if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) 20521308Sache { 20621308Sache _rl_vi_stuff_insert (count); 20721308Sache /* And back up point over the last character inserted. */ 20821308Sache if (rl_point > 0) 20921308Sache rl_point--; 21021308Sache } 21121308Sache else 212119610Sache r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); 21321308Sache vi_redoing = 0; 21421308Sache 215119610Sache return (r); 21621308Sache} 21721308Sache 21821308Sache/* A placeholder for further expansion. */ 21921308Sacheint 22021308Sacherl_vi_undo (count, key) 22121308Sache int count, key; 22221308Sache{ 22321308Sache return (rl_undo_command (count, key)); 22421308Sache} 22521308Sache 22621308Sache/* Yank the nth arg from the previous line into this line at point. */ 22721308Sacheint 22821308Sacherl_vi_yank_arg (count, key) 22921308Sache int count, key; 23021308Sache{ 23121308Sache /* Readline thinks that the first word on a line is the 0th, while vi 23221308Sache thinks the first word on a line is the 1st. Compensate. */ 23321308Sache if (rl_explicit_arg) 23421308Sache rl_yank_nth_arg (count - 1, 0); 23521308Sache else 23621308Sache rl_yank_nth_arg ('$', 0); 23721308Sache 23821308Sache return (0); 23921308Sache} 24021308Sache 24121308Sache/* With an argument, move back that many history lines, else move to the 24221308Sache beginning of history. */ 24321308Sacheint 24421308Sacherl_vi_fetch_history (count, c) 24521308Sache int count, c; 24621308Sache{ 24721308Sache int wanted; 24821308Sache 24921308Sache /* Giving an argument of n means we want the nth command in the history 25021308Sache file. The command number is interpreted the same way that the bash 25121308Sache `history' command does it -- that is, giving an argument count of 450 25221308Sache to this command would get the command listed as number 450 in the 25321308Sache output of `history'. */ 25421308Sache if (rl_explicit_arg) 25521308Sache { 25621308Sache wanted = history_base + where_history () - count; 25721308Sache if (wanted <= 0) 25821308Sache rl_beginning_of_history (0, 0); 25921308Sache else 26021308Sache rl_get_previous_history (wanted, c); 26121308Sache } 26221308Sache else 26321308Sache rl_beginning_of_history (count, 0); 26421308Sache return (0); 26521308Sache} 26621308Sache 26721308Sache/* Search again for the last thing searched for. */ 26821308Sacheint 26921308Sacherl_vi_search_again (count, key) 27021308Sache int count, key; 27121308Sache{ 27221308Sache switch (key) 27321308Sache { 27421308Sache case 'n': 27521308Sache rl_noninc_reverse_search_again (count, key); 27621308Sache break; 27721308Sache 27821308Sache case 'N': 27921308Sache rl_noninc_forward_search_again (count, key); 28021308Sache break; 28121308Sache } 28221308Sache return (0); 28321308Sache} 28421308Sache 28521308Sache/* Do a vi style search. */ 28621308Sacheint 28721308Sacherl_vi_search (count, key) 28821308Sache int count, key; 28921308Sache{ 29021308Sache switch (key) 29121308Sache { 29221308Sache case '?': 293136759Speter _rl_free_saved_history_line (); 29421308Sache rl_noninc_forward_search (count, key); 29521308Sache break; 29621308Sache 29721308Sache case '/': 298136759Speter _rl_free_saved_history_line (); 29921308Sache rl_noninc_reverse_search (count, key); 30021308Sache break; 30121308Sache 30221308Sache default: 30375406Sache rl_ding (); 30421308Sache break; 30521308Sache } 30621308Sache return (0); 30721308Sache} 30821308Sache 30921308Sache/* Completion, from vi's point of view. */ 31021308Sacheint 31121308Sacherl_vi_complete (ignore, key) 31221308Sache int ignore, key; 31321308Sache{ 31421308Sache if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) 31521308Sache { 31621308Sache if (!whitespace (rl_line_buffer[rl_point + 1])) 31721308Sache rl_vi_end_word (1, 'E'); 31821308Sache rl_point++; 31921308Sache } 32021308Sache 32121308Sache if (key == '*') 32221308Sache rl_complete_internal ('*'); /* Expansion and replacement. */ 32321308Sache else if (key == '=') 32421308Sache rl_complete_internal ('?'); /* List possible completions. */ 32521308Sache else if (key == '\\') 32621308Sache rl_complete_internal (TAB); /* Standard Readline completion. */ 32721308Sache else 32821308Sache rl_complete (0, key); 32921308Sache 33021308Sache if (key == '*' || key == '\\') 331136759Speter rl_vi_start_inserting (key, 1, rl_arg_sign); 332136759Speter 33321308Sache return (0); 33421308Sache} 33521308Sache 33621308Sache/* Tilde expansion for vi mode. */ 33721308Sacheint 33821308Sacherl_vi_tilde_expand (ignore, key) 33921308Sache int ignore, key; 34021308Sache{ 34121308Sache rl_tilde_expand (0, key); 342136759Speter rl_vi_start_inserting (key, 1, rl_arg_sign); 34321308Sache return (0); 34421308Sache} 34521308Sache 34621308Sache/* Previous word in vi mode. */ 34721308Sacheint 34821308Sacherl_vi_prev_word (count, key) 34921308Sache int count, key; 35021308Sache{ 35121308Sache if (count < 0) 35221308Sache return (rl_vi_next_word (-count, key)); 35321308Sache 35421308Sache if (rl_point == 0) 35521308Sache { 35675406Sache rl_ding (); 35721308Sache return (0); 35821308Sache } 35921308Sache 36021308Sache if (_rl_uppercase_p (key)) 36147558Sache rl_vi_bWord (count, key); 36221308Sache else 36347558Sache rl_vi_bword (count, key); 36421308Sache 36521308Sache return (0); 36621308Sache} 36721308Sache 36821308Sache/* Next word in vi mode. */ 36921308Sacheint 37021308Sacherl_vi_next_word (count, key) 37121308Sache int count, key; 37221308Sache{ 37321308Sache if (count < 0) 37421308Sache return (rl_vi_prev_word (-count, key)); 37521308Sache 37621308Sache if (rl_point >= (rl_end - 1)) 37721308Sache { 37875406Sache rl_ding (); 37921308Sache return (0); 38021308Sache } 38121308Sache 38221308Sache if (_rl_uppercase_p (key)) 38347558Sache rl_vi_fWord (count, key); 38421308Sache else 38547558Sache rl_vi_fword (count, key); 38621308Sache return (0); 38721308Sache} 38821308Sache 38921308Sache/* Move to the end of the ?next? word. */ 39021308Sacheint 39121308Sacherl_vi_end_word (count, key) 39221308Sache int count, key; 39321308Sache{ 39421308Sache if (count < 0) 39521308Sache { 39675406Sache rl_ding (); 39721308Sache return -1; 39821308Sache } 39921308Sache 40021308Sache if (_rl_uppercase_p (key)) 40147558Sache rl_vi_eWord (count, key); 40221308Sache else 40347558Sache rl_vi_eword (count, key); 40421308Sache return (0); 40521308Sache} 40621308Sache 40721308Sache/* Move forward a word the way that 'W' does. */ 40821308Sacheint 40947558Sacherl_vi_fWord (count, ignore) 41047558Sache int count, ignore; 41121308Sache{ 41221308Sache while (count-- && rl_point < (rl_end - 1)) 41321308Sache { 41421308Sache /* Skip until whitespace. */ 41521308Sache while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 41621308Sache rl_point++; 41721308Sache 41821308Sache /* Now skip whitespace. */ 41921308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 42021308Sache rl_point++; 42121308Sache } 42221308Sache return (0); 42321308Sache} 42421308Sache 42521308Sacheint 42647558Sacherl_vi_bWord (count, ignore) 42747558Sache int count, ignore; 42821308Sache{ 42921308Sache while (count-- && rl_point > 0) 43021308Sache { 43121308Sache /* If we are at the start of a word, move back to whitespace so 43221308Sache we will go back to the start of the previous word. */ 43321308Sache if (!whitespace (rl_line_buffer[rl_point]) && 43421308Sache whitespace (rl_line_buffer[rl_point - 1])) 43521308Sache rl_point--; 43621308Sache 43721308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 43821308Sache rl_point--; 43921308Sache 44021308Sache if (rl_point > 0) 44121308Sache { 44221308Sache while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); 44321308Sache rl_point++; 44421308Sache } 44521308Sache } 44621308Sache return (0); 44721308Sache} 44821308Sache 44921308Sacheint 45047558Sacherl_vi_eWord (count, ignore) 45147558Sache int count, ignore; 45221308Sache{ 45321308Sache while (count-- && rl_point < (rl_end - 1)) 45421308Sache { 45521308Sache if (!whitespace (rl_line_buffer[rl_point])) 45621308Sache rl_point++; 45721308Sache 45821308Sache /* Move to the next non-whitespace character (to the start of the 45921308Sache next word). */ 460136759Speter while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 461136759Speter rl_point++; 46221308Sache 46321308Sache if (rl_point && rl_point < rl_end) 46421308Sache { 46521308Sache /* Skip whitespace. */ 46621308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 46721308Sache rl_point++; 46821308Sache 46921308Sache /* Skip until whitespace. */ 47021308Sache while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) 47121308Sache rl_point++; 47221308Sache 47321308Sache /* Move back to the last character of the word. */ 47421308Sache rl_point--; 47521308Sache } 47621308Sache } 47721308Sache return (0); 47821308Sache} 47921308Sache 48021308Sacheint 48147558Sacherl_vi_fword (count, ignore) 48247558Sache int count, ignore; 48321308Sache{ 48421308Sache while (count-- && rl_point < (rl_end - 1)) 48521308Sache { 48621308Sache /* Move to white space (really non-identifer). */ 487119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 48821308Sache { 489119610Sache while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) 49021308Sache rl_point++; 49121308Sache } 49221308Sache else /* if (!whitespace (rl_line_buffer[rl_point])) */ 49321308Sache { 494119610Sache while (!_rl_isident (rl_line_buffer[rl_point]) && 49521308Sache !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 49621308Sache rl_point++; 49721308Sache } 49821308Sache 49921308Sache /* Move past whitespace. */ 50021308Sache while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 50121308Sache rl_point++; 50221308Sache } 50321308Sache return (0); 50421308Sache} 50521308Sache 50621308Sacheint 50747558Sacherl_vi_bword (count, ignore) 50847558Sache int count, ignore; 50921308Sache{ 51021308Sache while (count-- && rl_point > 0) 51121308Sache { 51221308Sache int last_is_ident; 51321308Sache 51421308Sache /* If we are at the start of a word, move back to whitespace 51521308Sache so we will go back to the start of the previous word. */ 51621308Sache if (!whitespace (rl_line_buffer[rl_point]) && 51721308Sache whitespace (rl_line_buffer[rl_point - 1])) 51821308Sache rl_point--; 51921308Sache 52021308Sache /* If this character and the previous character are `opposite', move 52121308Sache back so we don't get messed up by the rl_point++ down there in 52221308Sache the while loop. Without this code, words like `l;' screw up the 52321308Sache function. */ 524119610Sache last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]); 525119610Sache if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || 526119610Sache (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident)) 52721308Sache rl_point--; 52821308Sache 52921308Sache while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 53021308Sache rl_point--; 53121308Sache 53221308Sache if (rl_point > 0) 53321308Sache { 534119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 535119610Sache while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); 53621308Sache else 537119610Sache while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && 53821308Sache !whitespace (rl_line_buffer[rl_point])); 53921308Sache rl_point++; 54021308Sache } 54121308Sache } 54221308Sache return (0); 54321308Sache} 54421308Sache 54521308Sacheint 54647558Sacherl_vi_eword (count, ignore) 54747558Sache int count, ignore; 54821308Sache{ 54921308Sache while (count-- && rl_point < rl_end - 1) 55021308Sache { 55121308Sache if (!whitespace (rl_line_buffer[rl_point])) 55221308Sache rl_point++; 55321308Sache 55421308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 55521308Sache rl_point++; 55621308Sache 55721308Sache if (rl_point < rl_end) 55821308Sache { 559119610Sache if (_rl_isident (rl_line_buffer[rl_point])) 560119610Sache while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); 56121308Sache else 562119610Sache while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) 56321308Sache && !whitespace (rl_line_buffer[rl_point])); 56421308Sache } 56521308Sache rl_point--; 56621308Sache } 56721308Sache return (0); 56821308Sache} 56921308Sache 57021308Sacheint 57121308Sacherl_vi_insert_beg (count, key) 57221308Sache int count, key; 57321308Sache{ 57421308Sache rl_beg_of_line (1, key); 57521308Sache rl_vi_insertion_mode (1, key); 57621308Sache return (0); 57721308Sache} 57821308Sache 57921308Sacheint 58021308Sacherl_vi_append_mode (count, key) 58121308Sache int count, key; 58221308Sache{ 58321308Sache if (rl_point < rl_end) 584119610Sache { 585119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 586119610Sache rl_point++; 587119610Sache else 588119610Sache { 589119610Sache int point = rl_point; 590119610Sache rl_forward_char (1, key); 591119610Sache if (point == rl_point) 592119610Sache rl_point = rl_end; 593119610Sache } 594119610Sache } 59521308Sache rl_vi_insertion_mode (1, key); 59621308Sache return (0); 59721308Sache} 59821308Sache 59921308Sacheint 60021308Sacherl_vi_append_eol (count, key) 60121308Sache int count, key; 60221308Sache{ 60321308Sache rl_end_of_line (1, key); 60421308Sache rl_vi_append_mode (1, key); 60521308Sache return (0); 60621308Sache} 60721308Sache 60821308Sache/* What to do in the case of C-d. */ 60921308Sacheint 61021308Sacherl_vi_eof_maybe (count, c) 61121308Sache int count, c; 61221308Sache{ 61321308Sache return (rl_newline (1, '\n')); 61421308Sache} 61521308Sache 61621308Sache/* Insertion mode stuff. */ 61721308Sache 61821308Sache/* Switching from one mode to the other really just involves 61921308Sache switching keymaps. */ 62021308Sacheint 62121308Sacherl_vi_insertion_mode (count, key) 62221308Sache int count, key; 62321308Sache{ 62421308Sache _rl_keymap = vi_insertion_keymap; 62521308Sache _rl_vi_last_key_before_insert = key; 62621308Sache return (0); 62721308Sache} 62821308Sache 62921308Sachestatic void 63021308Sache_rl_vi_save_insert (up) 63121308Sache UNDO_LIST *up; 63221308Sache{ 63321308Sache int len, start, end; 63421308Sache 63535486Sache if (up == 0) 63635486Sache { 63735486Sache if (vi_insert_buffer_size >= 1) 63835486Sache vi_insert_buffer[0] = '\0'; 63935486Sache return; 64035486Sache } 64135486Sache 64221308Sache start = up->start; 64321308Sache end = up->end; 64421308Sache len = end - start + 1; 64521308Sache if (len >= vi_insert_buffer_size) 64621308Sache { 64721308Sache vi_insert_buffer_size += (len + 32) - (len % 32); 648119610Sache vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); 64921308Sache } 65021308Sache strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); 65121308Sache vi_insert_buffer[len-1] = '\0'; 65221308Sache} 65321308Sache 65421308Sachevoid 65521308Sache_rl_vi_done_inserting () 65621308Sache{ 65721308Sache if (_rl_vi_doing_insert) 65821308Sache { 659119610Sache /* The `C', `s', and `S' commands set this. */ 66021308Sache rl_end_undo_group (); 66121308Sache /* Now, the text between rl_undo_list->next->start and 66221308Sache rl_undo_list->next->end is what was inserted while in insert 66321308Sache mode. It gets copied to VI_INSERT_BUFFER because it depends 66421308Sache on absolute indices into the line which may change (though they 66521308Sache probably will not). */ 66621308Sache _rl_vi_doing_insert = 0; 66721308Sache _rl_vi_save_insert (rl_undo_list->next); 66821308Sache vi_continued_command = 1; 66921308Sache } 67021308Sache else 67121308Sache { 672136759Speter if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list) 67321308Sache _rl_vi_save_insert (rl_undo_list); 67421308Sache /* XXX - Other keys probably need to be checked. */ 67521308Sache else if (_rl_vi_last_key_before_insert == 'C') 67621308Sache rl_end_undo_group (); 67721308Sache while (_rl_undo_group_level > 0) 67821308Sache rl_end_undo_group (); 67921308Sache vi_continued_command = 0; 68021308Sache } 68121308Sache} 68221308Sache 68321308Sacheint 68421308Sacherl_vi_movement_mode (count, key) 68521308Sache int count, key; 68621308Sache{ 68721308Sache if (rl_point > 0) 688119610Sache rl_backward_char (1, key); 68921308Sache 69021308Sache _rl_keymap = vi_movement_keymap; 69121308Sache _rl_vi_done_inserting (); 692157188Sache 693157188Sache /* This is how POSIX.2 says `U' should behave -- everything up until the 694157188Sache first time you go into command mode should not be undone. */ 695157188Sache if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0) 696157188Sache rl_free_undo_list (); 697157188Sache 698157188Sache RL_SETSTATE (RL_STATE_VICMDONCE); 69921308Sache return (0); 70021308Sache} 70121308Sache 70221308Sacheint 70321308Sacherl_vi_arg_digit (count, c) 70421308Sache int count, c; 70521308Sache{ 70621308Sache if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) 70721308Sache return (rl_beg_of_line (1, c)); 70821308Sache else 70921308Sache return (rl_digit_argument (count, c)); 71021308Sache} 71121308Sache 712119610Sache/* Change the case of the next COUNT characters. */ 713119610Sache#if defined (HANDLE_MULTIBYTE) 714119610Sachestatic int 715119610Sache_rl_vi_change_mbchar_case (count) 716119610Sache int count; 717119610Sache{ 718119610Sache wchar_t wc; 719125665Sache char mb[MB_LEN_MAX+1]; 720136759Speter int mblen, p; 721119610Sache mbstate_t ps; 722119610Sache 723119610Sache memset (&ps, 0, sizeof (mbstate_t)); 724119610Sache if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) 725119610Sache count--; 726119610Sache while (count-- && rl_point < rl_end) 727119610Sache { 728119610Sache mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); 729119610Sache if (iswupper (wc)) 730119610Sache wc = towlower (wc); 731119610Sache else if (iswlower (wc)) 732119610Sache wc = towupper (wc); 733119610Sache else 734119610Sache { 735119610Sache /* Just skip over chars neither upper nor lower case */ 736119610Sache rl_forward_char (1, 0); 737119610Sache continue; 738119610Sache } 739119610Sache 740119610Sache /* Vi is kind of strange here. */ 741119610Sache if (wc) 742119610Sache { 743136759Speter p = rl_point; 744136759Speter mblen = wcrtomb (mb, wc, &ps); 745125665Sache if (mblen >= 0) 746125665Sache mb[mblen] = '\0'; 747119610Sache rl_begin_undo_group (); 748136759Speter rl_vi_delete (1, 0); 749136759Speter if (rl_point < p) /* Did we retreat at EOL? */ 750136759Speter rl_point++; /* XXX - should we advance more than 1 for mbchar? */ 751119610Sache rl_insert_text (mb); 752119610Sache rl_end_undo_group (); 753119610Sache rl_vi_check (); 754119610Sache } 755119610Sache else 756119610Sache rl_forward_char (1, 0); 757119610Sache } 758119610Sache 759119610Sache return 0; 760119610Sache} 761119610Sache#endif 762119610Sache 76321308Sacheint 76421308Sacherl_vi_change_case (count, ignore) 76521308Sache int count, ignore; 76621308Sache{ 767136759Speter int c, p; 76821308Sache 76921308Sache /* Don't try this on an empty line. */ 77021308Sache if (rl_point >= rl_end) 77121308Sache return (0); 77221308Sache 773136759Speter c = 0; 774119610Sache#if defined (HANDLE_MULTIBYTE) 775119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 776119610Sache return (_rl_vi_change_mbchar_case (count)); 777119610Sache#endif 778119610Sache 77921308Sache while (count-- && rl_point < rl_end) 78021308Sache { 78121308Sache if (_rl_uppercase_p (rl_line_buffer[rl_point])) 78221308Sache c = _rl_to_lower (rl_line_buffer[rl_point]); 78321308Sache else if (_rl_lowercase_p (rl_line_buffer[rl_point])) 78421308Sache c = _rl_to_upper (rl_line_buffer[rl_point]); 78521308Sache else 78621308Sache { 78721308Sache /* Just skip over characters neither upper nor lower case. */ 788119610Sache rl_forward_char (1, c); 78921308Sache continue; 79021308Sache } 79121308Sache 79221308Sache /* Vi is kind of strange here. */ 79321308Sache if (c) 79421308Sache { 795136759Speter p = rl_point; 79621308Sache rl_begin_undo_group (); 797136759Speter rl_vi_delete (1, c); 798136759Speter if (rl_point < p) /* Did we retreat at EOL? */ 799136759Speter rl_point++; 800119610Sache _rl_insert_char (1, c); 80121308Sache rl_end_undo_group (); 80221308Sache rl_vi_check (); 80321308Sache } 80421308Sache else 805119610Sache rl_forward_char (1, c); 80621308Sache } 80721308Sache return (0); 80821308Sache} 80921308Sache 81021308Sacheint 81121308Sacherl_vi_put (count, key) 81221308Sache int count, key; 81321308Sache{ 81421308Sache if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) 815119610Sache rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); 81621308Sache 817136759Speter while (count--) 818136759Speter rl_yank (1, key); 819136759Speter 820119610Sache rl_backward_char (1, key); 82121308Sache return (0); 82221308Sache} 82321308Sache 82421308Sacheint 82521308Sacherl_vi_check () 82621308Sache{ 82721308Sache if (rl_point && rl_point == rl_end) 828119610Sache { 829119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 830119610Sache rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 831119610Sache else 832119610Sache rl_point--; 833119610Sache } 83421308Sache return (0); 83521308Sache} 83621308Sache 83721308Sacheint 83821308Sacherl_vi_column (count, key) 83921308Sache int count, key; 84021308Sache{ 84121308Sache if (count > rl_end) 84221308Sache rl_end_of_line (1, key); 84321308Sache else 84421308Sache rl_point = count - 1; 84521308Sache return (0); 84621308Sache} 84721308Sache 84821308Sacheint 84921308Sacherl_vi_domove (key, nextkey) 85021308Sache int key, *nextkey; 85121308Sache{ 85221308Sache int c, save; 85321308Sache int old_end; 85421308Sache 85521308Sache rl_mark = rl_point; 85675406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 85721308Sache c = rl_read_key (); 85875406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 85921308Sache *nextkey = c; 86021308Sache 86121308Sache if (!member (c, vi_motion)) 86221308Sache { 86321308Sache if (_rl_digit_p (c)) 86421308Sache { 86521308Sache save = rl_numeric_arg; 86621308Sache rl_numeric_arg = _rl_digit_value (c); 867136759Speter rl_explicit_arg = 1; 868157188Sache RL_SETSTATE (RL_STATE_NUMERICARG|RL_STATE_VIMOTION); 86921308Sache rl_digit_loop1 (); 870157188Sache RL_UNSETSTATE (RL_STATE_VIMOTION); 87121308Sache rl_numeric_arg *= save; 87275406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 87321308Sache c = rl_read_key (); /* real command */ 87475406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 87521308Sache *nextkey = c; 87621308Sache } 87721308Sache else if (key == c && (key == 'd' || key == 'y' || key == 'c')) 87821308Sache { 87921308Sache rl_mark = rl_end; 88021308Sache rl_beg_of_line (1, c); 88121308Sache _rl_vi_last_motion = c; 88221308Sache return (0); 88321308Sache } 88421308Sache else 88521308Sache return (-1); 88621308Sache } 88721308Sache 88821308Sache _rl_vi_last_motion = c; 88921308Sache 89021308Sache /* Append a blank character temporarily so that the motion routines 89121308Sache work right at the end of the line. */ 89221308Sache old_end = rl_end; 89321308Sache rl_line_buffer[rl_end++] = ' '; 89421308Sache rl_line_buffer[rl_end] = '\0'; 89521308Sache 89621308Sache _rl_dispatch (c, _rl_keymap); 89721308Sache 89821308Sache /* Remove the blank that we added. */ 89921308Sache rl_end = old_end; 90021308Sache rl_line_buffer[rl_end] = '\0'; 90121308Sache if (rl_point > rl_end) 90221308Sache rl_point = rl_end; 90321308Sache 90421308Sache /* No change in position means the command failed. */ 90521308Sache if (rl_mark == rl_point) 90621308Sache return (-1); 90721308Sache 90821308Sache /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next 90921308Sache word. If we are not at the end of the line, and we are on a 91021308Sache non-whitespace character, move back one (presumably to whitespace). */ 91121308Sache if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && 91221308Sache !whitespace (rl_line_buffer[rl_point])) 91321308Sache rl_point--; 91421308Sache 91521308Sache /* If cw or cW, back up to the end of a word, so the behaviour of ce 91621308Sache or cE is the actual result. Brute-force, no subtlety. */ 91721308Sache if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) 91821308Sache { 91921308Sache /* Don't move farther back than where we started. */ 92021308Sache while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) 92121308Sache rl_point--; 92221308Sache 92321308Sache /* Posix.2 says that if cw or cW moves the cursor towards the end of 92421308Sache the line, the character under the cursor should be deleted. */ 92521308Sache if (rl_point == rl_mark) 92621308Sache rl_point++; 92721308Sache else 92821308Sache { 92921308Sache /* Move past the end of the word so that the kill doesn't 93021308Sache remove the last letter of the previous word. Only do this 93121308Sache if we are not at the end of the line. */ 93221308Sache if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) 93321308Sache rl_point++; 93421308Sache } 93521308Sache } 93621308Sache 93721308Sache if (rl_mark < rl_point) 938119610Sache SWAP (rl_point, rl_mark); 93921308Sache 94021308Sache return (0); 94121308Sache} 94221308Sache 943157188Sache/* Process C as part of the current numeric argument. Return -1 if the 944157188Sache argument should be aborted, 0 if we should not read any more chars, and 945157188Sache 1 if we should continue to read chars. */ 946157188Sachestatic int 947157188Sache_rl_vi_arg_dispatch (c) 948157188Sache int c; 949157188Sache{ 950157188Sache int key; 951157188Sache 952157188Sache key = c; 953157188Sache if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument) 954157188Sache { 955157188Sache rl_numeric_arg *= 4; 956157188Sache return 1; 957157188Sache } 958157188Sache 959157188Sache c = UNMETA (c); 960157188Sache 961157188Sache if (_rl_digit_p (c)) 962157188Sache { 963157188Sache if (rl_explicit_arg) 964157188Sache rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); 965157188Sache else 966157188Sache rl_numeric_arg = _rl_digit_value (c); 967157188Sache rl_explicit_arg = 1; 968157188Sache return 1; 969157188Sache } 970157188Sache else 971157188Sache { 972157188Sache rl_clear_message (); 973157188Sache rl_stuff_char (key); 974157188Sache return 0; 975157188Sache } 976157188Sache} 977157188Sache 97821308Sache/* A simplified loop for vi. Don't dispatch key at end. 97975406Sache Don't recognize minus sign? 98075406Sache Should this do rl_save_prompt/rl_restore_prompt? */ 98121308Sachestatic int 98221308Sacherl_digit_loop1 () 98321308Sache{ 984157188Sache int c, r; 98521308Sache 98621308Sache while (1) 98721308Sache { 988157188Sache if (_rl_arg_overflow ()) 989157188Sache return 1; 99021308Sache 991157188Sache c = _rl_arg_getchar (); 99221308Sache 993157188Sache r = _rl_vi_arg_dispatch (c); 994157188Sache if (r <= 0) 995157188Sache break; 99621308Sache } 99775406Sache 99875406Sache RL_UNSETSTATE(RL_STATE_NUMERICARG); 99921308Sache return (0); 100021308Sache} 100121308Sache 100221308Sacheint 100321308Sacherl_vi_delete_to (count, key) 100421308Sache int count, key; 100521308Sache{ 100621308Sache int c; 100721308Sache 100821308Sache if (_rl_uppercase_p (key)) 100921308Sache rl_stuff_char ('$'); 101021308Sache else if (vi_redoing) 101121308Sache rl_stuff_char (_rl_vi_last_motion); 101221308Sache 101321308Sache if (rl_vi_domove (key, &c)) 101421308Sache { 101575406Sache rl_ding (); 101621308Sache return -1; 101721308Sache } 101821308Sache 101921308Sache /* These are the motion commands that do not require adjusting the 102021308Sache mark. */ 102121308Sache if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) 102221308Sache rl_mark++; 102321308Sache 102421308Sache rl_kill_text (rl_point, rl_mark); 102521308Sache return (0); 102621308Sache} 102721308Sache 102821308Sacheint 102921308Sacherl_vi_change_to (count, key) 103021308Sache int count, key; 103121308Sache{ 103221308Sache int c, start_pos; 103321308Sache 103421308Sache if (_rl_uppercase_p (key)) 103521308Sache rl_stuff_char ('$'); 103621308Sache else if (vi_redoing) 103721308Sache rl_stuff_char (_rl_vi_last_motion); 103821308Sache 103921308Sache start_pos = rl_point; 104021308Sache 104121308Sache if (rl_vi_domove (key, &c)) 104221308Sache { 104375406Sache rl_ding (); 104421308Sache return -1; 104521308Sache } 104621308Sache 104721308Sache /* These are the motion commands that do not require adjusting the 104821308Sache mark. c[wW] are handled by special-case code in rl_vi_domove(), 104921308Sache and already leave the mark at the correct location. */ 105021308Sache if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) 105121308Sache rl_mark++; 105221308Sache 105321308Sache /* The cursor never moves with c[wW]. */ 105421308Sache if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) 105521308Sache rl_point = start_pos; 105621308Sache 105721308Sache if (vi_redoing) 105821308Sache { 105921308Sache if (vi_insert_buffer && *vi_insert_buffer) 106021308Sache rl_begin_undo_group (); 106121308Sache rl_delete_text (rl_point, rl_mark); 106221308Sache if (vi_insert_buffer && *vi_insert_buffer) 106321308Sache { 106421308Sache rl_insert_text (vi_insert_buffer); 106521308Sache rl_end_undo_group (); 106621308Sache } 106721308Sache } 106821308Sache else 106921308Sache { 107021308Sache rl_begin_undo_group (); /* to make the `u' command work */ 107121308Sache rl_kill_text (rl_point, rl_mark); 107221308Sache /* `C' does not save the text inserted for undoing or redoing. */ 107321308Sache if (_rl_uppercase_p (key) == 0) 107421308Sache _rl_vi_doing_insert = 1; 1075136759Speter rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign); 107621308Sache } 107721308Sache 107821308Sache return (0); 107921308Sache} 108021308Sache 108121308Sacheint 108221308Sacherl_vi_yank_to (count, key) 108321308Sache int count, key; 108421308Sache{ 1085157188Sache int c, save; 108621308Sache 1087157188Sache save = rl_point; 108821308Sache if (_rl_uppercase_p (key)) 108921308Sache rl_stuff_char ('$'); 109021308Sache 109121308Sache if (rl_vi_domove (key, &c)) 109221308Sache { 109375406Sache rl_ding (); 109421308Sache return -1; 109521308Sache } 109621308Sache 109721308Sache /* These are the motion commands that do not require adjusting the 109821308Sache mark. */ 109921308Sache if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) 110021308Sache rl_mark++; 110121308Sache 110221308Sache rl_begin_undo_group (); 110321308Sache rl_kill_text (rl_point, rl_mark); 110421308Sache rl_end_undo_group (); 110521308Sache rl_do_undo (); 110621308Sache rl_point = save; 110721308Sache 110821308Sache return (0); 110921308Sache} 111021308Sache 111121308Sacheint 1112157188Sacherl_vi_rubout (count, key) 1113157188Sache int count, key; 1114157188Sache{ 1115157188Sache int p, opoint; 1116157188Sache 1117157188Sache if (count < 0) 1118157188Sache return (rl_vi_delete (-count, key)); 1119157188Sache 1120157188Sache if (rl_point == 0) 1121157188Sache { 1122157188Sache rl_ding (); 1123157188Sache return -1; 1124157188Sache } 1125157188Sache 1126157188Sache opoint = rl_point; 1127157188Sache if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1128157188Sache rl_backward_char (count, key); 1129157188Sache else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1130157188Sache rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 1131157188Sache else 1132157188Sache rl_point -= count; 1133157188Sache 1134157188Sache if (rl_point < 0) 1135157188Sache rl_point = 0; 1136157188Sache 1137157188Sache rl_kill_text (rl_point, opoint); 1138157188Sache 1139157188Sache return (0); 1140157188Sache} 1141157188Sache 1142157188Sacheint 114321308Sacherl_vi_delete (count, key) 114421308Sache int count, key; 114521308Sache{ 114621308Sache int end; 114721308Sache 1148157188Sache if (count < 0) 1149157188Sache return (rl_vi_rubout (-count, key)); 1150157188Sache 115121308Sache if (rl_end == 0) 115221308Sache { 115375406Sache rl_ding (); 115421308Sache return -1; 115521308Sache } 115621308Sache 1157119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1158119610Sache end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); 1159119610Sache else 1160119610Sache end = rl_point + count; 116121308Sache 116221308Sache if (end >= rl_end) 116321308Sache end = rl_end; 116421308Sache 116521308Sache rl_kill_text (rl_point, end); 116621308Sache 116721308Sache if (rl_point > 0 && rl_point == rl_end) 1168119610Sache rl_backward_char (1, key); 1169157188Sache 117021308Sache return (0); 117121308Sache} 117221308Sache 117321308Sacheint 117421308Sacherl_vi_back_to_indent (count, key) 117521308Sache int count, key; 117621308Sache{ 117721308Sache rl_beg_of_line (1, key); 117821308Sache while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 117921308Sache rl_point++; 118021308Sache return (0); 118121308Sache} 118221308Sache 118321308Sacheint 118421308Sacherl_vi_first_print (count, key) 118521308Sache int count, key; 118621308Sache{ 118721308Sache return (rl_vi_back_to_indent (1, key)); 118821308Sache} 118921308Sache 1190157188Sachestatic int _rl_cs_dir, _rl_cs_orig_dir; 1191157188Sache 1192157188Sache#if defined (READLINE_CALLBACKS) 1193157188Sachestatic int 1194157188Sache_rl_vi_callback_char_search (data) 1195157188Sache _rl_callback_generic_arg *data; 1196157188Sache{ 1197157188Sache#if defined (HANDLE_MULTIBYTE) 1198157188Sache _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1199157188Sache#else 1200157188Sache RL_SETSTATE(RL_STATE_MOREINPUT); 1201157188Sache _rl_vi_last_search_char = rl_read_key (); 1202157188Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 1203157188Sache#endif 1204157188Sache 1205157188Sache _rl_callback_func = 0; 1206157188Sache _rl_want_redisplay = 1; 1207157188Sache 1208157188Sache#if defined (HANDLE_MULTIBYTE) 1209157188Sache return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen)); 1210157188Sache#else 1211157188Sache return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char)); 1212157188Sache#endif 1213157188Sache} 1214157188Sache#endif 1215157188Sache 121621308Sacheint 121721308Sacherl_vi_char_search (count, key) 121821308Sache int count, key; 121921308Sache{ 1220119610Sache#if defined (HANDLE_MULTIBYTE) 1221119610Sache static char *target; 1222157188Sache static int tlen; 1223119610Sache#else 122421308Sache static char target; 1225119610Sache#endif 122621308Sache 122721308Sache if (key == ';' || key == ',') 1228157188Sache _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir; 122921308Sache else 123021308Sache { 123121308Sache switch (key) 123221308Sache { 123321308Sache case 't': 1234157188Sache _rl_cs_orig_dir = _rl_cs_dir = FTO; 123521308Sache break; 123621308Sache 123721308Sache case 'T': 1238157188Sache _rl_cs_orig_dir = _rl_cs_dir = BTO; 123921308Sache break; 124021308Sache 124121308Sache case 'f': 1242157188Sache _rl_cs_orig_dir = _rl_cs_dir = FFIND; 124321308Sache break; 124421308Sache 124521308Sache case 'F': 1246157188Sache _rl_cs_orig_dir = _rl_cs_dir = BFIND; 124721308Sache break; 124821308Sache } 1249157188Sache 1250157188Sache if (vi_redoing) 1251157188Sache { 1252157188Sache /* set target and tlen below */ 1253157188Sache } 1254157188Sache#if defined (READLINE_CALLBACKS) 1255157188Sache else if (RL_ISSTATE (RL_STATE_CALLBACK)) 1256157188Sache { 1257157188Sache _rl_callback_data = _rl_callback_data_alloc (count); 1258157188Sache _rl_callback_data->i1 = _rl_cs_dir; 1259157188Sache _rl_callback_func = _rl_vi_callback_char_search; 1260157188Sache return (0); 1261157188Sache } 1262157188Sache#endif 1263157188Sache else 1264157188Sache { 1265157188Sache#if defined (HANDLE_MULTIBYTE) 1266157188Sache _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1267157188Sache#else 1268157188Sache RL_SETSTATE(RL_STATE_MOREINPUT); 1269157188Sache _rl_vi_last_search_char = rl_read_key (); 1270157188Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 1271157188Sache#endif 1272157188Sache } 127321308Sache } 127421308Sache 1275119610Sache#if defined (HANDLE_MULTIBYTE) 1276157188Sache target = _rl_vi_last_search_mbchar; 1277157188Sache tlen = _rl_vi_last_search_mblen; 1278119610Sache#else 1279157188Sache target = _rl_vi_last_search_char; 1280119610Sache#endif 1281157188Sache 1282157188Sache#if defined (HANDLE_MULTIBYTE) 1283157188Sache return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen)); 1284157188Sache#else 1285157188Sache return (_rl_char_search_internal (count, _rl_cs_dir, target)); 1286157188Sache#endif 128721308Sache} 128821308Sache 128921308Sache/* Match brackets */ 129021308Sacheint 129121308Sacherl_vi_match (ignore, key) 129221308Sache int ignore, key; 129321308Sache{ 1294119610Sache int count = 1, brack, pos, tmp, pre; 129521308Sache 129621308Sache pos = rl_point; 129721308Sache if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 129821308Sache { 1299119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1300119610Sache { 1301119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1302119610Sache { 1303119610Sache pre = rl_point; 1304119610Sache rl_forward_char (1, key); 1305119610Sache if (pre == rl_point) 1306119610Sache break; 1307119610Sache } 1308119610Sache } 1309119610Sache else 1310119610Sache while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && 1311119610Sache rl_point < rl_end - 1) 1312119610Sache rl_forward_char (1, key); 131321308Sache 131421308Sache if (brack <= 0) 131521308Sache { 131621308Sache rl_point = pos; 131775406Sache rl_ding (); 131821308Sache return -1; 131921308Sache } 132021308Sache } 132121308Sache 132221308Sache pos = rl_point; 132321308Sache 132421308Sache if (brack < 0) 132521308Sache { 132621308Sache while (count) 132721308Sache { 1328119610Sache tmp = pos; 1329119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1330119610Sache pos--; 1331119610Sache else 133221308Sache { 1333119610Sache pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); 1334119610Sache if (tmp == pos) 1335119610Sache pos--; 1336119610Sache } 1337119610Sache if (pos >= 0) 1338119610Sache { 133921308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 134021308Sache if (b == -brack) 134121308Sache count--; 134221308Sache else if (b == brack) 134321308Sache count++; 134421308Sache } 134521308Sache else 134621308Sache { 134775406Sache rl_ding (); 134821308Sache return -1; 134921308Sache } 135021308Sache } 135121308Sache } 135221308Sache else 135321308Sache { /* brack > 0 */ 135421308Sache while (count) 135521308Sache { 1356119610Sache if (MB_CUR_MAX == 1 || rl_byte_oriented) 1357119610Sache pos++; 1358119610Sache else 1359119610Sache pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); 1360119610Sache 1361119610Sache if (pos < rl_end) 136221308Sache { 136321308Sache int b = rl_vi_bracktype (rl_line_buffer[pos]); 136421308Sache if (b == -brack) 136521308Sache count--; 136621308Sache else if (b == brack) 136721308Sache count++; 136821308Sache } 136921308Sache else 137021308Sache { 137175406Sache rl_ding (); 137221308Sache return -1; 137321308Sache } 137421308Sache } 137521308Sache } 137621308Sache rl_point = pos; 137721308Sache return (0); 137821308Sache} 137921308Sache 138021308Sacheint 138121308Sacherl_vi_bracktype (c) 138221308Sache int c; 138321308Sache{ 138421308Sache switch (c) 138521308Sache { 138621308Sache case '(': return 1; 138721308Sache case ')': return -1; 138821308Sache case '[': return 2; 138921308Sache case ']': return -2; 139021308Sache case '{': return 3; 139121308Sache case '}': return -3; 139221308Sache default: return 0; 139321308Sache } 139421308Sache} 139521308Sache 1396157188Sachestatic int 1397157188Sache_rl_vi_change_char (count, c, mb) 1398157188Sache int count, c; 1399157188Sache char *mb; 140021308Sache{ 1401157188Sache int p; 140221308Sache 140321308Sache if (c == '\033' || c == CTRL ('C')) 140421308Sache return -1; 140521308Sache 1406136759Speter rl_begin_undo_group (); 140721308Sache while (count-- && rl_point < rl_end) 140821308Sache { 1409136759Speter p = rl_point; 1410136759Speter rl_vi_delete (1, c); 1411157188Sache if (rl_point < p) /* Did we retreat at EOL? */ 1412157188Sache rl_point++; 1413119610Sache#if defined (HANDLE_MULTIBYTE) 1414119610Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1415157188Sache rl_insert_text (mb); 1416119610Sache else 1417119610Sache#endif 1418157188Sache _rl_insert_char (1, c); 1419136759Speter } 1420157188Sache 1421157188Sache /* The cursor shall be left on the last character changed. */ 1422157188Sache rl_backward_char (1, c); 1423157188Sache 1424136759Speter rl_end_undo_group (); 142521308Sache 142621308Sache return (0); 142721308Sache} 142821308Sache 1429157188Sachestatic int 1430157188Sache_rl_vi_callback_getchar (mb, mblen) 1431157188Sache char *mb; 1432157188Sache int mblen; 1433157188Sache{ 1434157188Sache int c; 1435157188Sache 1436157188Sache RL_SETSTATE(RL_STATE_MOREINPUT); 1437157188Sache c = rl_read_key (); 1438157188Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 1439157188Sache 1440157188Sache#if defined (HANDLE_MULTIBYTE) 1441157188Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1442157188Sache c = _rl_read_mbstring (c, mb, mblen); 1443157188Sache#endif 1444157188Sache 1445157188Sache return c; 1446157188Sache} 1447157188Sache 1448157188Sache#if defined (READLINE_CALLBACKS) 1449157188Sachestatic int 1450157188Sache_rl_vi_callback_change_char (data) 1451157188Sache _rl_callback_generic_arg *data; 1452157188Sache{ 1453157188Sache int c; 1454157188Sache char mb[MB_LEN_MAX]; 1455157188Sache 1456157188Sache _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); 1457157188Sache 1458157188Sache _rl_callback_func = 0; 1459157188Sache _rl_want_redisplay = 1; 1460157188Sache 1461157188Sache return (_rl_vi_change_char (data->count, c, mb)); 1462157188Sache} 1463157188Sache#endif 1464157188Sache 146521308Sacheint 1466157188Sacherl_vi_change_char (count, key) 1467157188Sache int count, key; 1468157188Sache{ 1469157188Sache int c; 1470157188Sache char mb[MB_LEN_MAX]; 1471157188Sache 1472157188Sache if (vi_redoing) 1473157188Sache { 1474157188Sache c = _rl_vi_last_replacement; 1475157188Sache mb[0] = c; 1476157188Sache mb[1] = '\0'; 1477157188Sache } 1478157188Sache#if defined (READLINE_CALLBACKS) 1479157188Sache else if (RL_ISSTATE (RL_STATE_CALLBACK)) 1480157188Sache { 1481157188Sache _rl_callback_data = _rl_callback_data_alloc (count); 1482157188Sache _rl_callback_func = _rl_vi_callback_change_char; 1483157188Sache return (0); 1484157188Sache } 1485157188Sache#endif 1486157188Sache else 1487157188Sache _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); 1488157188Sache 1489157188Sache return (_rl_vi_change_char (count, c, mb)); 1490157188Sache} 1491157188Sache 1492157188Sacheint 149321308Sacherl_vi_subst (count, key) 149421308Sache int count, key; 149521308Sache{ 1496119610Sache /* If we are redoing, rl_vi_change_to will stuff the last motion char */ 1497119610Sache if (vi_redoing == 0) 1498136759Speter rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */ 149921308Sache 1500119610Sache return (rl_vi_change_to (count, 'c')); 150121308Sache} 150221308Sache 150321308Sacheint 150421308Sacherl_vi_overstrike (count, key) 150521308Sache int count, key; 150621308Sache{ 150721308Sache if (_rl_vi_doing_insert == 0) 150821308Sache { 150921308Sache _rl_vi_doing_insert = 1; 151021308Sache rl_begin_undo_group (); 151121308Sache } 151221308Sache 1513119610Sache if (count > 0) 151421308Sache { 1515119610Sache _rl_overwrite_char (count, key); 1516119610Sache vi_replace_count += count; 1517119610Sache } 151821308Sache 151921308Sache return (0); 152021308Sache} 152121308Sache 152221308Sacheint 152321308Sacherl_vi_overstrike_delete (count, key) 152421308Sache int count, key; 152521308Sache{ 152621308Sache int i, s; 152721308Sache 152821308Sache for (i = 0; i < count; i++) 152921308Sache { 153021308Sache if (vi_replace_count == 0) 153121308Sache { 153275406Sache rl_ding (); 153321308Sache break; 153421308Sache } 153521308Sache s = rl_point; 153621308Sache 153721308Sache if (rl_do_undo ()) 153821308Sache vi_replace_count--; 153921308Sache 154021308Sache if (rl_point == s) 1541119610Sache rl_backward_char (1, key); 154221308Sache } 154321308Sache 154421308Sache if (vi_replace_count == 0 && _rl_vi_doing_insert) 154521308Sache { 154621308Sache rl_end_undo_group (); 154721308Sache rl_do_undo (); 154821308Sache _rl_vi_doing_insert = 0; 154921308Sache } 155021308Sache return (0); 155121308Sache} 155221308Sache 155321308Sacheint 155421308Sacherl_vi_replace (count, key) 155521308Sache int count, key; 155621308Sache{ 155721308Sache int i; 155821308Sache 155921308Sache vi_replace_count = 0; 156021308Sache 156121308Sache if (!vi_replace_map) 156221308Sache { 156321308Sache vi_replace_map = rl_make_bare_keymap (); 156421308Sache 156521308Sache for (i = ' '; i < KEYMAP_SIZE; i++) 156621308Sache vi_replace_map[i].function = rl_vi_overstrike; 156721308Sache 156821308Sache vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; 156921308Sache vi_replace_map[ESC].function = rl_vi_movement_mode; 157021308Sache vi_replace_map[RETURN].function = rl_newline; 157121308Sache vi_replace_map[NEWLINE].function = rl_newline; 157221308Sache 157321308Sache /* If the normal vi insertion keymap has ^H bound to erase, do the 157421308Sache same here. Probably should remove the assignment to RUBOUT up 157521308Sache there, but I don't think it will make a difference in real life. */ 157621308Sache if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && 157721308Sache vi_insertion_keymap[CTRL ('H')].function == rl_rubout) 157821308Sache vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; 157921308Sache 158021308Sache } 158121308Sache _rl_keymap = vi_replace_map; 158221308Sache return (0); 158321308Sache} 158421308Sache 158521308Sache#if 0 158621308Sache/* Try to complete the word we are standing on or the word that ends with 158721308Sache the previous character. A space matches everything. Word delimiters are 158821308Sache space and ;. */ 158921308Sacheint 159021308Sacherl_vi_possible_completions() 159121308Sache{ 159221308Sache int save_pos = rl_point; 159321308Sache 159421308Sache if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') 159521308Sache { 159621308Sache while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && 159721308Sache rl_line_buffer[rl_point] != ';') 159821308Sache rl_point++; 159921308Sache } 160021308Sache else if (rl_line_buffer[rl_point - 1] == ';') 160121308Sache { 160275406Sache rl_ding (); 160321308Sache return (0); 160421308Sache } 160521308Sache 160621308Sache rl_possible_completions (); 160721308Sache rl_point = save_pos; 160821308Sache 160921308Sache return (0); 161021308Sache} 161121308Sache#endif 161221308Sache 161321308Sache/* Functions to save and restore marks. */ 1614157188Sachestatic int 1615157188Sache_rl_vi_set_mark () 161621308Sache{ 161721308Sache int ch; 161821308Sache 161975406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 162021308Sache ch = rl_read_key (); 162175406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 162275406Sache 1623119610Sache if (ch < 'a' || ch > 'z') 162421308Sache { 162575406Sache rl_ding (); 162621308Sache return -1; 162721308Sache } 162821308Sache ch -= 'a'; 162921308Sache vi_mark_chars[ch] = rl_point; 163021308Sache return 0; 163121308Sache} 163221308Sache 1633157188Sache#if defined (READLINE_CALLBACKS) 1634157188Sachestatic int 1635157188Sache_rl_vi_callback_set_mark (data) 1636157188Sache _rl_callback_generic_arg *data; 1637157188Sache{ 1638157188Sache _rl_callback_func = 0; 1639157188Sache _rl_want_redisplay = 1; 1640157188Sache 1641157188Sache return (_rl_vi_set_mark ()); 1642157188Sache} 1643157188Sache#endif 1644157188Sache 164521308Sacheint 1646157188Sacherl_vi_set_mark (count, key) 164721308Sache int count, key; 164821308Sache{ 1649157188Sache#if defined (READLINE_CALLBACKS) 1650157188Sache if (RL_ISSTATE (RL_STATE_CALLBACK)) 1651157188Sache { 1652157188Sache _rl_callback_data = 0; 1653157188Sache _rl_callback_func = _rl_vi_callback_set_mark; 1654157188Sache return (0); 1655157188Sache } 1656157188Sache#endif 1657157188Sache 1658157188Sache return (_rl_vi_set_mark ()); 1659157188Sache} 1660157188Sache 1661157188Sachestatic int 1662157188Sache_rl_vi_goto_mark () 1663157188Sache{ 166421308Sache int ch; 166521308Sache 166675406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 166721308Sache ch = rl_read_key (); 166875406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 166975406Sache 167021308Sache if (ch == '`') 167121308Sache { 167221308Sache rl_point = rl_mark; 167321308Sache return 0; 167421308Sache } 1675119610Sache else if (ch < 'a' || ch > 'z') 167621308Sache { 167775406Sache rl_ding (); 167821308Sache return -1; 167921308Sache } 168021308Sache 168121308Sache ch -= 'a'; 168221308Sache if (vi_mark_chars[ch] == -1) 168321308Sache { 168475406Sache rl_ding (); 168521308Sache return -1; 168621308Sache } 168721308Sache rl_point = vi_mark_chars[ch]; 168821308Sache return 0; 168921308Sache} 169021308Sache 1691157188Sache#if defined (READLINE_CALLBACKS) 1692157188Sachestatic int 1693157188Sache_rl_vi_callback_goto_mark (data) 1694157188Sache _rl_callback_generic_arg *data; 1695157188Sache{ 1696157188Sache _rl_callback_func = 0; 1697157188Sache _rl_want_redisplay = 1; 1698157188Sache 1699157188Sache return (_rl_vi_goto_mark ()); 1700157188Sache} 1701157188Sache#endif 1702157188Sache 1703157188Sacheint 1704157188Sacherl_vi_goto_mark (count, key) 1705157188Sache int count, key; 1706157188Sache{ 1707157188Sache#if defined (READLINE_CALLBACKS) 1708157188Sache if (RL_ISSTATE (RL_STATE_CALLBACK)) 1709157188Sache { 1710157188Sache _rl_callback_data = 0; 1711157188Sache _rl_callback_func = _rl_vi_callback_goto_mark; 1712157188Sache return (0); 1713157188Sache } 1714157188Sache#endif 1715157188Sache 1716157188Sache return (_rl_vi_goto_mark ()); 1717157188Sache} 171821308Sache#endif /* VI_MODE */ 1719