⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vi_mode.c

📁 UNIX下SH的实现源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* vi_mode.c -- A vi emulation mode for Bash.   Derived from code written by Jeff Sparkes (jsparkes@bnr.ca).  *//* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.   This file is part of the GNU Readline Library, a library for   reading lines of text with interactive input and history editing.   The GNU Readline Library is free software; you can redistribute it   and/or modify it under the terms of the GNU General Public License   as published by the Free Software Foundation; either version 2, or   (at your option) any later version.   The GNU Readline Library is distributed in the hope that it will be   useful, but WITHOUT ANY WARRANTY; without even the implied warranty   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   The GNU General Public License is often shipped with GNU software, and   is generally kept in a file called COPYING or LICENSE.  If you do not   have a copy of the license, write to the Free Software Foundation,   59 Temple Place, Suite 330, Boston, MA 02111 USA. */#define READLINE_LIBRARY/* **************************************************************** *//*								    *//*			VI Emulation Mode			    *//*								    *//* **************************************************************** */#include "rlconf.h"#if defined (VI_MODE)#if defined (HAVE_CONFIG_H)#  include <config.h>#endif#include <sys/types.h>#if defined (HAVE_STDLIB_H)#  include <stdlib.h>#else#  include "ansi_stdlib.h"#endif /* HAVE_STDLIB_H */#if defined (HAVE_UNISTD_H)#  include <unistd.h>#endif#include <stdio.h>/* Some standard library routines. */#include "rldefs.h"#include "readline.h"#include "history.h"#include "rlprivate.h"#include "xmalloc.h"#ifndef _rl_digit_p#define _rl_digit_p(c)  ((c) >= '0' && (c) <= '9')#endif#ifndef _rl_digit_value#define _rl_digit_value(c) ((c) - '0')#endif#ifndef member#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)#endif#ifndef isident#define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_'))#endif#ifndef exchange#define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0)#endif/* Non-zero means enter insertion mode. */static int _rl_vi_doing_insert;/* Command keys which do movement for xxx_to commands. */static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";/* Keymap used for vi replace characters.  Created dynamically since   rarely used. */static Keymap vi_replace_map;/* The number of characters inserted in the last replace operation. */static int vi_replace_count;/* If non-zero, we have text inserted after a c[motion] command that put   us implicitly into insert mode.  Some people want this text to be   attached to the command so that it is `redoable' with `.'. */static int vi_continued_command;static char *vi_insert_buffer;static int vi_insert_buffer_size;static int _rl_vi_last_command = 'i';	/* default `.' puts you in insert mode */static int _rl_vi_last_repeat = 1;static int _rl_vi_last_arg_sign = 1;static int _rl_vi_last_motion;static int _rl_vi_last_search_char;static int _rl_vi_last_replacement;static int _rl_vi_last_key_before_insert;static int vi_redoing;/* Text modification commands.  These are the `redoable' commands. */static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";/* Arrays for the saved marks. */static int vi_mark_chars[27];static int rl_digit_loop1 __P((void));void_rl_vi_initialize_line (){  register int i;  for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)    vi_mark_chars[i] = -1;}void_rl_vi_reset_last (){  _rl_vi_last_command = 'i';  _rl_vi_last_repeat = 1;  _rl_vi_last_arg_sign = 1;  _rl_vi_last_motion = 0;}void_rl_vi_set_last (key, repeat, sign)     int key, repeat, sign;{  _rl_vi_last_command = key;  _rl_vi_last_repeat = repeat;  _rl_vi_last_arg_sign = sign;}/* Is the command C a VI mode text modification command? */int_rl_vi_textmod_command (c)     int c;{  return (member (c, vi_textmod));}static void_rl_vi_stuff_insert (count)     int count;{  rl_begin_undo_group ();  while (count--)    rl_insert_text (vi_insert_buffer);  rl_end_undo_group ();}/* Bound to `.'.  Called from command mode, so we know that we have to   redo a text modification command.  The default for _rl_vi_last_command   puts you back into insert mode. */intrl_vi_redo (count, c)     int count, c;{  if (!rl_explicit_arg)    {      rl_numeric_arg = _rl_vi_last_repeat;      rl_arg_sign = _rl_vi_last_arg_sign;    }  vi_redoing = 1;  /* If we're redoing an insert with `i', stuff in the inserted text     and do not go into insertion mode. */  if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)    {      _rl_vi_stuff_insert (count);      /* And back up point over the last character inserted. */      if (rl_point > 0)	rl_point--;    }  else    _rl_dispatch (_rl_vi_last_command, _rl_keymap);  vi_redoing = 0;  return (0);}/* A placeholder for further expansion. */intrl_vi_undo (count, key)     int count, key;{  return (rl_undo_command (count, key));}    /* Yank the nth arg from the previous line into this line at point. */intrl_vi_yank_arg (count, key)     int count, key;{  /* Readline thinks that the first word on a line is the 0th, while vi     thinks the first word on a line is the 1st.  Compensate. */  if (rl_explicit_arg)    rl_yank_nth_arg (count - 1, 0);  else    rl_yank_nth_arg ('$', 0);  return (0);}/* With an argument, move back that many history lines, else move to the   beginning of history. */intrl_vi_fetch_history (count, c)     int count, c;{  int wanted;  /* Giving an argument of n means we want the nth command in the history     file.  The command number is interpreted the same way that the bash     `history' command does it -- that is, giving an argument count of 450     to this command would get the command listed as number 450 in the     output of `history'. */  if (rl_explicit_arg)    {      wanted = history_base + where_history () - count;      if (wanted <= 0)        rl_beginning_of_history (0, 0);      else        rl_get_previous_history (wanted, c);    }  else    rl_beginning_of_history (count, 0);  return (0);}/* Search again for the last thing searched for. */intrl_vi_search_again (count, key)     int count, key;{  switch (key)    {    case 'n':      rl_noninc_reverse_search_again (count, key);      break;    case 'N':      rl_noninc_forward_search_again (count, key);      break;    }  return (0);}/* Do a vi style search. */intrl_vi_search (count, key)     int count, key;{  switch (key)    {    case '?':      rl_noninc_forward_search (count, key);      break;    case '/':      rl_noninc_reverse_search (count, key);      break;    default:      ding ();      break;    }  return (0);}/* Completion, from vi's point of view. */intrl_vi_complete (ignore, key)     int ignore, key;{  if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))    {      if (!whitespace (rl_line_buffer[rl_point + 1]))	rl_vi_end_word (1, 'E');      rl_point++;    }  if (key == '*')    rl_complete_internal ('*');	/* Expansion and replacement. */  else if (key == '=')    rl_complete_internal ('?');	/* List possible completions. */  else if (key == '\\')    rl_complete_internal (TAB);	/* Standard Readline completion. */  else    rl_complete (0, key);  if (key == '*' || key == '\\')    {      _rl_vi_set_last (key, 1, rl_arg_sign);      rl_vi_insertion_mode (1, key);    }  return (0);}/* Tilde expansion for vi mode. */intrl_vi_tilde_expand (ignore, key)     int ignore, key;{  rl_tilde_expand (0, key);  _rl_vi_set_last (key, 1, rl_arg_sign);	/* XXX */  rl_vi_insertion_mode (1, key);  return (0);}/* Previous word in vi mode. */intrl_vi_prev_word (count, key)     int count, key;{  if (count < 0)    return (rl_vi_next_word (-count, key));  if (rl_point == 0)    {      ding ();      return (0);    }  if (_rl_uppercase_p (key))    rl_vi_bWord (count, key);  else    rl_vi_bword (count, key);  return (0);}/* Next word in vi mode. */intrl_vi_next_word (count, key)     int count, key;{  if (count < 0)    return (rl_vi_prev_word (-count, key));  if (rl_point >= (rl_end - 1))    {      ding ();      return (0);    }  if (_rl_uppercase_p (key))    rl_vi_fWord (count, key);  else    rl_vi_fword (count, key);  return (0);}/* Move to the end of the ?next? word. */intrl_vi_end_word (count, key)     int count, key;{  if (count < 0)    {      ding ();      return -1;    }  if (_rl_uppercase_p (key))    rl_vi_eWord (count, key);  else    rl_vi_eword (count, key);  return (0);}/* Move forward a word the way that 'W' does. */intrl_vi_fWord (count, ignore)     int count, ignore;{  while (count-- && rl_point < (rl_end - 1))    {      /* Skip until whitespace. */      while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)	rl_point++;      /* Now skip whitespace. */      while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)	rl_point++;    }  return (0);}intrl_vi_bWord (count, ignore)     int count, ignore;{  while (count-- && rl_point > 0)    {      /* If we are at the start of a word, move back to whitespace so	 we will go back to the start of the previous word. */      if (!whitespace (rl_line_buffer[rl_point]) &&	  whitespace (rl_line_buffer[rl_point - 1]))	rl_point--;      while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))	rl_point--;      if (rl_point > 0)	{	  while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));	  rl_point++;	}    }  return (0);}intrl_vi_eWord (count, ignore)     int count, ignore;{  while (count-- && rl_point < (rl_end - 1))    {      if (!whitespace (rl_line_buffer[rl_point]))	rl_point++;      /* Move to the next non-whitespace character (to the start of the	 next word). */      while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));      if (rl_point && rl_point < rl_end)	{	  /* Skip whitespace. */	  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))	    rl_point++;	  /* Skip until whitespace. */	  while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))	    rl_point++;	  /* Move back to the last character of the word. */	  rl_point--;	}    }  return (0);}intrl_vi_fword (count, ignore)     int count, ignore;{  while (count-- && rl_point < (rl_end - 1))    {      /* Move to white space (really non-identifer). */      if (isident (rl_line_buffer[rl_point]))	{	  while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)	    rl_point++;	}      else /* if (!whitespace (rl_line_buffer[rl_point])) */	{	  while (!isident (rl_line_buffer[rl_point]) &&		 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)	    rl_point++;	}      /* Move past whitespace. */      while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)	rl_point++;    }  return (0);}intrl_vi_bword (count, ignore)     int count, ignore;{  while (count-- && rl_point > 0)    {      int last_is_ident;      /* If we are at the start of a word, move back to whitespace	 so we will go back to the start of the previous word. */      if (!whitespace (rl_line_buffer[rl_point]) &&	  whitespace (rl_line_buffer[rl_point - 1]))	rl_point--;      /* If this character and the previous character are `opposite', move	 back so we don't get messed up by the rl_point++ down there in	 the while loop.  Without this code, words like `l;' screw up the	 function. */      last_is_ident = isident (rl_line_buffer[rl_point - 1]);      if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||	  (!isident (rl_line_buffer[rl_point]) && last_is_ident))	rl_point--;      while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))	rl_point--;      if (rl_point > 0)	{	  if (isident (rl_line_buffer[rl_point]))	    while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));	  else	    while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&		   !whitespace (rl_line_buffer[rl_point]));	  rl_point++;	}    }  return (0);}intrl_vi_eword (count, ignore)     int count, ignore;{  while (count-- && rl_point < rl_end - 1)    {      if (!whitespace (rl_line_buffer[rl_point]))	rl_point++;      while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))	rl_point++;      if (rl_point < rl_end)	{	  if (isident (rl_line_buffer[rl_point]))	    while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));	  else	    while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])		   && !whitespace (rl_line_buffer[rl_point]));	}      rl_point--;    }  return (0);}intrl_vi_insert_beg (count, key)     int count, key;{  rl_beg_of_line (1, key);  rl_vi_insertion_mode (1, key);  return (0);}intrl_vi_append_mode (count, key)     int count, key;{  if (rl_point < rl_end)    rl_point++;  rl_vi_insertion_mode (1, key);  return (0);}intrl_vi_append_eol (count, key)     int count, key;{  rl_end_of_line (1, key);  rl_vi_append_mode (1, key);  return (0);}/* What to do in the case of C-d. */intrl_vi_eof_maybe (count, c)     int count, c;{  return (rl_newline (1, '\n'));}/* Insertion mode stuff. *//* Switching from one mode to the other really just involves   switching keymaps. */intrl_vi_insertion_mode (count, key)     int count, key;{  _rl_keymap = vi_insertion_keymap;  _rl_vi_last_key_before_insert = key;  return (0);}static void_rl_vi_save_insert (up)      UNDO_LIST *up;{  int len, start, end;  if (up == 0)    {      if (vi_insert_buffer_size >= 1)	vi_insert_buffer[0] = '\0';      return;    }  start = up->start;  end = up->end;  len = end - start + 1;  if (len >= vi_insert_buffer_size)    {      vi_insert_buffer_size += (len + 32) - (len % 32);      vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size);    }  strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);  vi_insert_buffer[len-1] = '\0';}    void_rl_vi_done_inserting (){  if (_rl_vi_doing_insert)    {      rl_end_undo_group ();      /* Now, the text between rl_undo_list->next->start and	 rl_undo_list->next->end is what was inserted while in insert	 mode.  It gets copied to VI_INSERT_BUFFER because it depends	 on absolute indices into the line which may change (though they	 probably will not). */      _rl_vi_doing_insert = 0;      _rl_vi_save_insert (rl_undo_list->next);      vi_continued_command = 1;    }  else    {      if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list)        _rl_vi_save_insert (rl_undo_list);      /* XXX - Other keys probably need to be checked. */      else if (_rl_vi_last_key_before_insert == 'C')	rl_end_undo_group ();      while (_rl_undo_group_level > 0)	rl_end_undo_group ();      vi_continued_command = 0;    }}intrl_vi_movement_mode (count, key)     int count, key;{  if (rl_point > 0)    rl_backward (1, key);  _rl_keymap = vi_movement_keymap;  _rl_vi_done_inserting ();  return (0);}intrl_vi_arg_digit (count, c)     int count, c;{  if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)    return (rl_beg_of_line (1, c));  else    return (rl_digit_argument (count, c));}intrl_vi_change_case (count, ignore)     int count, ignore;{  char c = 0;  /* Don't try this on an empty line. */  if (rl_point >= rl_end)    return (0);  while (count-- && rl_point < rl_end)    {      if (_rl_uppercase_p (rl_line_buffer[rl_point]))	c = _rl_to_lower (rl_line_buffer[rl_point]);      else if (_rl_lowercase_p (rl_line_buffer[rl_point]))	c = _rl_to_upper (rl_line_buffer[rl_point]);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -