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

📄 vi.c

📁 一个开放源代码的 AT&T 的 Korn Shell 的复制品, 支持大多数 ksh89 的特性。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	vi command editing *	written by John Rochester (initially for nsh) *	bludgeoned to fit pdksh by Larry Bouzane, Jeff Sparkes & Eric Gisin * */#include "config.h"#ifdef VI#include "sh.h"#include <ctype.h>#include "ksh_stat.h"		/* completion */#include "edit.h"#define CMDLEN		1024#define Ctrl(c)		(c&0x1f)#define	is_wordch(c)	(letnum(c))struct edstate {	int	winleft;	char	*cbuf;	int	cbufsize;	int	linelen;	int	cursor;};static int	vi_hook	ARGS((int ch));static void 	vi_reset ARGS((char *buf, size_t len));static int	nextstate ARGS((int ch));static int	vi_insert ARGS((int ch));static int	vi_cmd ARGS((int argcnt, const char *cmd));static int	domove ARGS((int argcnt, const char *cmd, int sub));static int	redo_insert ARGS((int count));static void	yank_range ARGS((int a, int b));static int	bracktype ARGS((int ch));static void	save_cbuf ARGS((void));static void	restore_cbuf ARGS((void));static void	edit_reset ARGS((char *buf, size_t len));static int	putbuf ARGS((const char *buf, int len, int repl));static void	del_range ARGS((int a, int b));static int	findch ARGS((int ch, int cnt, int forw, int incl));static int	forwword ARGS((int argcnt));static int	backword ARGS((int argcnt));static int	endword ARGS((int argcnt));static int	Forwword ARGS((int argcnt));static int	Backword ARGS((int argcnt));static int	Endword ARGS((int argcnt));static int	grabhist ARGS((int save, int n));static int	grabsearch ARGS((int save, int start, int fwd, char *pat));static void	redraw_line ARGS((int newline));static void	refresh ARGS((int leftside));static int	outofwin ARGS((void));static void	rewindow ARGS((void));static int	newcol ARGS((int ch, int col));static void	display ARGS((char *wb1, char *wb2, int leftside));static void	ed_mov_opt ARGS((int col, char *wb));static int	expand_word ARGS((int command));static int	complete_word ARGS((int command, int count));static int	print_expansions ARGS((struct edstate *e, int command));static int 	char_len ARGS((int c));static void 	x_vi_zotc ARGS((int c));static void	vi_pprompt ARGS((int full));static void	vi_error ARGS((void));static void	vi_macro_reset ARGS((void));#define C_	0x1		/* a valid command that isn't a M_, E_, U_ */#define M_	0x2		/* movement command (h, l, etc.) */#define E_	0x4		/* extended command (c, d, y) */#define X_	0x8		/* long command (@, f, F, t, T, etc.) */#define U_	0x10		/* an UN-undoable command (that isn't a M_) */#define B_	0x20		/* bad command (^@) */#define Z_	0x40		/* repeat count defaults to 0 (not 1) */#define S_	0x80		/* search (/, ?) */#define is_bad(c)	(classify[(c)&0x7f]&B_)#define is_cmd(c)	(classify[(c)&0x7f]&(M_|E_|C_|U_))#define is_move(c)	(classify[(c)&0x7f]&M_)#define is_extend(c)	(classify[(c)&0x7f]&E_)#define is_long(c)	(classify[(c)&0x7f]&X_)#define is_undoable(c)	(!(classify[(c)&0x7f]&U_))#define is_srch(c)	(classify[(c)&0x7f]&S_)#define is_zerocount(c)	(classify[(c)&0x7f]&Z_)const unsigned char	classify[128] = {   /*       0       1       2       3       4       5       6       7        */   /*   0   ^@     ^A      ^B      ^C      ^D      ^E      ^F      ^G        */	    B_,     0,      0,      0,      0,      C_|U_,  C_|Z_,  0,   /*  01   ^H     ^I      ^J      ^K      ^L      ^M      ^N      ^O        */	    M_,     C_|Z_,  0,      0,      C_|U_,  0,      C_,     0,   /*  02   ^P     ^Q      ^R      ^S      ^T      ^U      ^V      ^W        */	    C_,     0,      C_|U_,  0,      0,      0,      C_,     0,   /*  03   ^X     ^Y      ^Z      ^[      ^\      ^]      ^^      ^_        */	    C_,     0,      0,      C_|Z_,  0,      0,      0,      0,   /*  04  <space>  !       "       #       $       %       &       '        */	    M_,     0,      0,      C_,     M_,     M_,     0,      0,   /*  05   (       )       *       +       ,       -       .       /        */	    0,      0,      C_,     C_,     M_,     C_,     0,      C_|S_,   /*  06   0       1       2       3       4       5       6       7        */	    M_,     0,      0,      0,      0,      0,      0,      0,   /*  07   8       9       :       ;       <       =       >       ?        */	    0,      0,      0,      M_,     0,      C_,     0,      C_|S_,   /* 010   @       A       B       C       D       E       F       G        */	    C_|X_,  C_,     M_,     C_,     C_,     M_,     M_|X_,  C_|U_|Z_,   /* 011   H       I       J       K       L       M       N       O        */	    0,      C_,     0,      0,      0,      0,      C_|U_,  0,   /* 012   P       Q       R       S       T       U       V       W        */	    C_,     0,      C_,     C_,     M_|X_,  C_,     0,      M_,   /* 013   X       Y       Z       [       \       ]       ^       _        */	    C_,     C_|U_,  0,      0,      C_|Z_,  0,      M_,     C_|Z_,   /* 014   `       a       b       c       d       e       f       g        */	    0,      C_,     M_,     E_,     E_,     M_,     M_|X_,  C_|Z_,   /* 015   h       i       j       k       l       m       n       o        */	    M_,     C_,     C_|U_,  C_|U_,  M_,     0,      C_|U_,  0,   /* 016   p       q       r       s       t       u       v       w        */	    C_,     0,      X_,     C_,     M_|X_,  C_|U_,  C_|U_|Z_,M_,   /* 017   x       y       z       {       |       }       ~      ^?        */	    C_,     E_|U_,  0,      0,      M_|Z_,  0,      C_,     0};#define MAXVICMD	3#define SRCHLEN		40#define INSERT		1#define REPLACE		2#define VNORMAL		0		/* command, insert or replace mode */#define VARG1		1		/* digit prefix (first, eg, 5l) */#define VEXTCMD		2		/* cmd + movement (eg, cl) */#define VARG2		3		/* digit prefix (second, eg, 2c3l) */#define VXCH		4		/* f, F, t, T, @ */#define VFAIL		5		/* bad command */#define VCMD		6		/* single char command (eg, X) */#define VREDO		7		/* . */#define VLIT		8		/* ^V */#define VSEARCH		9		/* /, ? */#define VVERSION	10		/* <ESC> ^V */static char		undocbuf[CMDLEN];static struct edstate 	*save_edstate ARGS((struct edstate *old));static void		restore_edstate ARGS((struct edstate *old, struct edstate *new));static void 		free_edstate ARGS((struct edstate *old));static struct edstate	ebuf;static struct edstate	undobuf = { 0, undocbuf, CMDLEN, 0, 0 };static struct edstate	*es;			/* current editor state */static struct edstate	*undo;static char	ibuf[CMDLEN];		/* input buffer */static int	first_insert;		/* set when starting in insert mode */static int	saved_inslen;		/* saved inslen for first insert */static int	inslen;			/* length of input buffer */static int	srchlen;		/* length of current search pattern */static char	ybuf[CMDLEN];		/* yank buffer */static int	yanklen;		/* length of yank buffer */static int	fsavecmd = ' ';		/* last find command */static int	fsavech;		/* character to find */static char	lastcmd[MAXVICMD];	/* last non-move command */static int	lastac;			/* argcnt for lastcmd */static int	lastsearch = ' ';	/* last search command */static char	srchpat[SRCHLEN];	/* last search pattern */static int	insert;			/* non-zero in insert mode */static int	hnum;			/* position in history */static int	ohnum;			/* history line copied (after mod) */static int	hlast;			/* 1 past last position in history */static int	modified;		/* buffer has been "modified" */static int	state;/* Information for keeping track of macros that are being expanded. * The format of buf is the alias contents followed by a null byte followed * by the name (letter) of the alias.  The end of the buffer is marked by * a double null.  The name of the alias is stored so recursive macros can * be detected. */struct macro_state {    unsigned char	*p;	/* current position in buf */    unsigned char	*buf;	/* pointer to macro(s) being expanded */    int			len;	/* how much data in buffer */};static struct macro_state macro;enum expand_mode { NONE, EXPAND, COMPLETE, PRINT };static enum expand_mode expanded = NONE;/* last input was expanded */intx_vi(buf, len)	char	*buf;	size_t	len;{	int	c;	vi_reset(buf, len > CMDLEN ? CMDLEN : len);	vi_pprompt(1);	x_flush();	while (1) {		if (macro.p) {			c = *macro.p++;			/* end of current macro? */			if (!c) {				/* more macros left to finish? */				if (*macro.p++)					continue;				/* must be the end of all the macros */				vi_macro_reset();				c = x_getc();			}		} else {			c = x_getc();		}		if (c == -1)			break;		if (state != VLIT) {			if (c == edchars.intr || c == edchars.quit) {				/* pretend we got an interrupt */				x_vi_zotc(c);				x_flush();				trapsig(c == edchars.intr ? SIGINT : SIGQUIT);				x_mode(FALSE);				unwind(LSHELL);			} else if (c == edchars.eof && state != VVERSION) {				if (es->linelen == 0) {					x_vi_zotc(edchars.eof);					c = -1;					break;				}				continue;			}		}		if (vi_hook(c))			break;		x_flush();	}	x_putc('\r'); x_putc('\n'); x_flush();	if (c == -1)		return -1;	if (es->cbuf != buf)		memmove(buf, es->cbuf, es->linelen);	buf[es->linelen++] = '\n';	return es->linelen;}static intvi_hook(ch)	int		ch;{	static char	curcmd[MAXVICMD];	static char	locpat[SRCHLEN];	static int	cmdlen;	static int	argc1, argc2;	switch (state) {	case VNORMAL:		if (insert != 0) {			if (ch == Ctrl('v')) {				state = VLIT;				ch = '^';			}			switch (vi_insert(ch)) {			case -1:#ifdef OS2				/* Arrow keys generate 0xe0X, where X is H.. */				state = VCMD;				argc1 = 1;				switch (x_getc()) {				  case 'H':					*curcmd='k';					break;				  case 'K':					*curcmd='h';					break;				  case 'P':					*curcmd='j';					break;				  case 'M':					*curcmd='l';					break;				  default:					vi_error();					state = VNORMAL;				}				break;#else /* OS2 */				vi_error();				state = VNORMAL;#endif /* OS2 */				break;			case 0:				if (state == VLIT) {					es->cursor--;					refresh(0);				} else					refresh(insert != 0);				break;			case 1:				return 1;			}		} else {			if (ch == '\r' || ch == '\n')				return 1;			cmdlen = 0;			argc1 = 0;			if (ch >= '1' && ch <= '9') {				argc1 = ch - '0';				state = VARG1;			} else {				curcmd[cmdlen++] = ch;				state = nextstate(ch);				if (state == VSEARCH) {					save_cbuf();					es->cursor = 0;					es->linelen = 0;					if (ch == '/') {						if (putbuf("/", 1, 0) != 0) {							return -1;						}					} else if (putbuf("?", 1, 0) != 0)							return -1;					refresh(0);				}				if (state == VVERSION) {					save_cbuf();					es->cursor = 0;					es->linelen = 0;					putbuf(ksh_version + 4,						strlen(ksh_version + 4), 0);					refresh(0);				}			}		}		break;	case VLIT:		if (is_bad(ch)) {			del_range(es->cursor, es->cursor + 1);			vi_error();		} else			es->cbuf[es->cursor++] = ch;		refresh(1);		state = VNORMAL;		break;	case VVERSION:		restore_cbuf();		state = VNORMAL;		refresh(0);		break;	case VARG1:		if (isdigit(ch))			argc1 = argc1 * 10 + ch - '0';		else {			curcmd[cmdlen++] = ch;			state = nextstate(ch);		}		break;	case VEXTCMD:		argc2 = 0;		if (ch >= '1' && ch <= '9') {			argc2 = ch - '0';			state = VARG2;			return 0;		} else {			curcmd[cmdlen++] = ch;			if (ch == curcmd[0])				state = VCMD;			else if (is_move(ch))				state = nextstate(ch);			else				state = VFAIL;		}		break;	case VARG2:		if (isdigit(ch))			argc2 = argc2 * 10 + ch - '0';		else {			if (argc1 == 0)				argc1 = argc2;			else				argc1 *= argc2;			curcmd[cmdlen++] = ch;			if (ch == curcmd[0])				state = VCMD;			else if (is_move(ch))				state = nextstate(ch);			else				state = VFAIL;		}		break;	case VXCH:		if (ch == Ctrl('['))			state = VNORMAL;		else {			curcmd[cmdlen++] = ch;			state = VCMD;		}		break;	case VSEARCH:		if (ch == '\r' || ch == '\n' /*|| ch == Ctrl('[')*/ ) {			restore_cbuf();			/* Repeat last search? */			if (srchlen == 0) {				if (!srchpat[0]) {					vi_error();					state = VNORMAL;					refresh(0);					return 0;				}			} else {				locpat[srchlen] = '\0';				(void) strcpy(srchpat, locpat);			}			state = VCMD;		} else if (ch == edchars.erase || ch == Ctrl('h')) {			if (srchlen != 0) {				srchlen--;				es->linelen -= char_len((unsigned char) locpat[srchlen]);				es->cursor = es->linelen;				refresh(0);				return 0;			}			restore_cbuf();			state = VNORMAL;			refresh(0);		} else if (ch == edchars.kill) {			srchlen = 0;			es->linelen = 1;			es->cursor = 1;			refresh(0);			return 0;		} else if (ch == edchars.werase) {			int i;			int n = srchlen;			while (n > 0 && isspace(locpat[n - 1]))				n--;			while (n > 0 && !isspace(locpat[n - 1]))				n--;			for (i = srchlen; --i >= n; )				es->linelen -= char_len((unsigned char) locpat[i]);			srchlen = n;			es->cursor = es->linelen;			refresh(0);			return 0;		} else {			if (srchlen == SRCHLEN - 1)				vi_error();			else {				locpat[srchlen++] = ch;				if ((ch & 0x80) && Flag(FVISHOW8)) {					es->cbuf[es->linelen++] = 'M';					es->cbuf[es->linelen++] = '-';					ch &= 0x7f;				}				if (ch < ' ' || ch == 0x7f) {					es->cbuf[es->linelen++] = '^';					es->cbuf[es->linelen++] = ch ^ '@';				} else					es->cbuf[es->linelen++] = ch;				es->cursor = es->linelen;				refresh(0);			}			return 0;		}		break;	}	switch (state) {	case VCMD:		state = VNORMAL;		switch (vi_cmd(argc1, curcmd)) {		case -1:			vi_error();			refresh(0);			break;		case 0:			if (insert != 0)				inslen = 0;			refresh(insert != 0);			break;		case 1:			refresh(0);			return 1;		case 2:			/* back from a 'v' command - don't redraw the screen */			return 1;		}		break;	case VREDO:		state = VNORMAL;		if (argc1 != 0)			lastac = argc1;		switch (vi_cmd(lastac, lastcmd)) {		case -1:			vi_error();			refresh(0);			break;		case 0:			if (insert != 0) {				if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||						lastcmd[0] == 'C') {					if (redo_insert(1) != 0)						vi_error();				} else {					if (redo_insert(lastac) != 0)						vi_error();				}			}			refresh(0);			break;		case 1:			refresh(0);			return 1;		case 2:			/* back from a 'v' command - can't happen */			break;		}		break;	case VFAIL:		state = VNORMAL;		vi_error();		break;	}	return 0;}static voidvi_reset(buf, len)	char	*buf;	size_t	len;{	state = VNORMAL;	ohnum = hnum = hlast = histnum(-1) + 1;	insert = INSERT;	saved_inslen = inslen;	first_insert = 1;	inslen = 0;	modified = 1;	vi_macro_reset();	edit_reset(buf, len);}static intnextstate(ch)	int	ch;{	if (is_extend(ch))		return VEXTCMD;	else if (is_srch(ch))		return VSEARCH;	else if (is_long(ch))		return VXCH;	else if (ch == '.')		return VREDO;	else if (ch == Ctrl('v'))		return VVERSION;	else if (is_cmd(ch))		return VCMD;	else		return VFAIL;}static intvi_insert(ch)	int	ch;{	int	tcursor;	if (ch == edchars.erase || ch == Ctrl('h')) {		if (insert == REPLACE) {			if (es->cursor == undo->cursor) {				vi_error();				return 0;			}			if (inslen > 0)				inslen--;			es->cursor--;			if (es->cursor >= undo->linelen)				es->linelen--;			else				es->cbuf[es->cursor] = undo->cbuf[es->cursor];		} else {			if (es->cursor == 0) {				/* x_putc(BEL); no annoying bell here */				return 0;			}			if (inslen > 0)				inslen--;			es->cursor--;			es->linelen--;			memmove(&es->cbuf[es->cursor], &es->cbuf[es->cursor+1],					es->linelen - es->cursor + 1);		}		expanded = NONE;		return 0;	}	if (ch == edchars.kill) {		if (es->cursor != 0) {			inslen = 0;			memmove(es->cbuf, &es->cbuf[es->cursor],						es->linelen - es->cursor);			es->linelen -= es->cursor;			es->cursor = 0;		}		expanded = NONE;		return 0;	}	if (ch == edchars.werase) {		if (es->cursor != 0) {			tcursor = Backword(1);			memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor],						es->linelen - es->cursor);			es->linelen -= es->cursor - tcursor;			if (inslen < es->cursor - tcursor)				inslen = 0;			else				inslen -= es->cursor - tcursor;			es->cursor = tcursor;		}		expanded = NONE;		return 0;	}	/* If any chars are entered before escape, trash the saved insert	 * buffer (if user inserts & deletes char, ibuf gets trashed and	 * we don't want to use it)	 */	if (first_insert && ch != Ctrl('['))		saved_inslen = 0;	switch (ch) {#ifdef OS2	case 224:	 /* function key prefix */#endif /* OS2 */	case '\0':		return -1;	case '\r':	case '\n':		return 1;	case Ctrl('['):		expanded = NONE;		if (first_insert) {			first_insert = 0;			if (inslen == 0) {				inslen = saved_inslen;				return redo_insert(0);			}			lastcmd[0] = 'a';			lastac = 1;		}		if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||				lastcmd[0] == 'C')			return redo_insert(0);		else			return redo_insert(lastac - 1);	/* { Begin nonstandard vi commands */	case Ctrl('x'):		expand_word(0);		break;	case Ctrl('f'):		complete_word(0, 0);		break;	case Ctrl('e'):		print_expansions(es, 0);		break;	case Ctrl('i'):		if (Flag(FVITABCOMPLETE)) {			complete_word(0, 0);			break;		}		/* FALLTHROUGH */	/* End nonstandard vi commands } */	default:		if (es->linelen == es->cbufsize - 1)			return -1;		ibuf[inslen++] = ch;		if (insert == INSERT) {			memmove(&es->cbuf[es->cursor+1], &es->cbuf[es->cursor],					es->linelen - es->cursor);			es->linelen++;		}		es->cbuf[es->cursor++] = ch;		if (insert == REPLACE && es->cursor > es->linelen)			es->linelen++;		expanded = NONE;	}	return 0;}static intvi_cmd(argcnt, cmd)	int		argcnt;	const char	*cmd;{	int		ncursor;	int		cur, c1, c2, c3 = 0;	int		any;	struct edstate	*t;	if (argcnt == 0 && !is_zerocount(*cmd))		argcnt = 1;	if (is_move(*cmd)) {		if ((cur = domove(argcnt, cmd, 0)) >= 0) {			if (cur == es->linelen && cur != 0)				cur--;

⌨️ 快捷键说明

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