sh.edit.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 3,065 行 · 第 1/4 页

C
3,065
字号
	char *markcursor;	int (*moveop)(), (*deleteop)();	static char lastFKND, lastFCHR;	char holdchar;	int insearch;			/* state of emacs search mode */	/*	 * The line is in the line buffer linebuf,	 * and the cursor at the position cursor.	 */	insearch = 0;	for (;;) {		/*		 * Decode a command.		 * Clear state for decoding of next command.		 */		vglobp = 0;		Xhadcnt = hadcnt = 0;		Xcnt = cnt = 1;		moveop = vmove, deleteop = vdelete;		opf = moveop;		wcursor = cursor;		dir = 1;ereread:		/*		 * Come to reread from below after some macro expansions.		 * The call to map allows use of function key pads		 * by performing a terminal dependent mapping of inputs.		op = getkey();		 */		op = getbr();		maphopcnt = 0;		do {			/*			 * Keep mapping the char as long as it changes.			 * This allows for double mappings, e.g., q to #,			 * #1 to something else.			 */			c = op;			op = map(c,arrows);			if (++maphopcnt > 256)				error("Infinite macro loop");		} while (c != op);		/*		 * Begin to build an image of this cmd in the buffer workcmd.		 */		lastcp = workcmd;		if (!vglobp)			*lastcp++ = c;		/*		 * First level command decode.		 */		switch (c) {		/*		 * ^C		Quit: with no command line.		 */		case CTRL(c):			linebuf[0] = '\0';			destcol = 0;			vclreol();			return;		/*		 * NL, CR	end edit so cmd can be executed.		 */		 case NL:		 case CR:			globp = "x";			return;		/* 006 - GAG */		/*		 * ^U		Repeat count for command.		 */		 case CTRL(u):			if (isdigit(peekkey()) && peekkey() != '0') {				hadcnt = 1;				cnt = vgetcnt();				eforbid (cnt <= 0);			} else {				hadcnt = 1;				cnt = 4;				Xhadcnt = 1;				Xcnt = 4;			};			goto ereread;		/*		 * ^T		Exchange the 2 characters BEFORE the cursor		 */		case CTRL(t):			insearch = 0;			if (cursor-2 < linebuf) {				beep();				continue;			}			wcursor = cursor-2;			holdchar = *wcursor;			*wcursor++ = *(cursor-1);			*wcursor = holdchar;			/* fall into... to redisplay the line */		/*		 * ^L		Redraw the line.		 */		case CTRL(l):			redraw();			continue;		/*		 * ^A		To beginning of real line.		 */		case CTRL(a):			insearch = 0;			wcursor = linebuf;			(*opf)(c);			continue;		/*		 * ^E		To end of line.		 */		case CTRL(e):			insearch = 0;			if (cnt > 1)				cnt = 1;			if (linebuf[0]) {				wcursor = strend(linebuf) - 1;				if (moveop != vmove)					wcursor++;				(*opf)(c);				continue;			}			wcursor = linebuf;			(*opf)(c);			continue;		/*		 * uparrow	Edit prior history event		 */		case 'k':		case CTRL(p):			insearch = 0;			if (maphopcnt < 2)				goto einsrt;	/* no map, its an insert char */			editevent--;			if (reedit(0))				goto enewedit;			else {	/* ran off top of history, so keep old line */				editevent++;				beep();				continue;			}		/*		 * downarrow	Edit next history event		 */		case 'j':		case CTRL(n):			insearch = 0;			if (maphopcnt < 2)				goto einsrt;	/* no map, its an insert char */			editevent++;			if (reedit(0) <= 0) {				/* ran off botm of history, so keep old line */				editevent--;				beep();				continue;			}enewedit:			/*			 * Reset edit state for new command line			 */			vsetcurs(linebuf);			init_globals();			continue;		/*		 * <-		Back a character (arrow key mapped to 'h').		 * ^B		Back a character.		 */		case 'h':			if (maphopcnt < 2)				goto einsrt;	/* no map, its an insert char */			/* fall into ... */		case CTRL(b):			dir = -1;			/* fall into ... */		/*		 * ->		Frwd a character (arrow key mapped to 'l').		 * ^F		Forward a character.		 */		case 'l':			if ((maphopcnt < 2) && c != CTRL(b))				goto einsrt;	/* no map, its an insert char */			/* fall into ... */		case CTRL(f):			insearch = 0;			eforbid (margin() || opf == vmove && edge());			while (cnt > 0 && !margin())				wcursor += dir, cnt--;			if (margin() && opf == vmove || wcursor < linebuf)				wcursor -= dir;			(*opf)(c);			continue;		/*		 * ^K		Delete to end of line, (vi: d$).		 */		case CTRL(k):			insearch = 0;			cnt = INF;			goto edeleteit;		/*		 * ^H,DEL	Delete character before cursor.		 */		case CTRL(h):		case DELETE:			dir = -1;			/* fall into ... */edeleteit:		/*		 * ^D		Delete char at cursor, leaving cursor where it is.		 */		case CTRL(d):			insearch = 0;			CP(oldbuf, linebuf);			oldcursor = cursor;			if (margin())				goto efonfon;			while (cnt > 0 && !margin())				wcursor += dir, cnt--;			if (wcursor == strend(linebuf))				wcursor--;    /* keep blank at eol for emacs */			opf = deleteop;			(*opf)(c);			continue;		/*		 * ^R	Find single character backward in current line.		 */		case CTRL(r):	/* inverted find */			dir = -1;			/* fall into ... */		/*		 * ^S	Find single character forward in current line.		 */		case CTRL(s):	/* find */			insearch = 0;			i = getesc();			if (i == 0)				continue;			*lastcp++ = i;			if (vglobp == 0)				lastFKND = c, lastFCHR = i;			for (; cnt > 0; cnt--)				eforbid (find(i) == 0);			(*opf)(c);			continue;		/*		 * ^Y		Put back text before cursor.		 */		case CTRL(y):			/*			 * Save command for repeat cmd. Save old line state			 * for undo.			 * Use an append or insert to put it back so as to			 * use insert mode.			 */			insearch = 0;			setLAST();			CP(oldbuf, linebuf);			oldcursor = cursor;			if (DEL[0]) {				eforbid (DEL[0] == NULL);				vglobp = DEL;				goto einsrt;			}			beep();			continue;		/*		 * ^space		Set mark.		 */		case 00:			markcursor = cursor;			continue;		/*		 * ^W		Delete to mark		 */		case CTRL(w):			insearch = 0;			if (markcursor < linebuf || markcursor > strend(linebuf)) {				beep();				continue;			}			wcursor = markcursor;			opf = deleteop;			(*opf)(c);			continue;		/*		 * 2 character commands: ESCAPE + something.		 */		case ESCAPE:			insearch = 0;			/*			 * Gobble up counts.			 */			if (isdigit(peekkey()) && peekkey() != '0') {				hadcnt = 1;				cnt = vgetcnt();				eforbid (cnt <= 0);				goto ereread;			}			c = getkey();			*lastcp++ = c;			switch (c) {			/*			 * ESC^C	Exit and execute command.			 */			case CTRL(c):				return;			/*			 * ESC B	Back word.			 */			case 'B':			case 'b':				dir = -1;				/* fall into */			/*			 * ESC F	Forward word.			 */			case 'F':			case 'f':				wdkind = c & ' ';				eforbid(lfind(2,cnt,opf) < 0);				(*opf)(c);				continue;			/*			 * ESC H	delete prev word (vi: db)			 * ESC DEL	delete prev word (vi: db)			 */			case 'H':			case 'h':			case DELETE:				dir = -1;				/* fall into */			/*			 * ESC D	delete next word (vi: dw)			 */			case 'D':			case 'd':				CP(oldbuf, linebuf);				oldcursor = cursor;				moveop = vdelete;				deleteop = beep;				opf = moveop;				wdkind = c & ' ';				eforbid(lfind(2, cnt, opf) < 0);				if (wcursor == strend(linebuf))					wcursor--; /* keep blank at eol for emacs */				(*opf)(c);				continue;			/*			 * 	Abort command (with a little feedback).			 */			default:				beep();				vmacp = 0;				continue;			} /* end switch on char after ESC */		/*		 * 2 character commands: ^X + something.		 */		case CTRL(x):			c = getkey();			*lastcp++ = c;			switch (c) {			/*			 * ^X^C		Exit and execute command.			 */			case CTRL(c):				return;			/*			 * search	Edit some prior history event			 *		Search for a "word" delineated by white space.			 */			case CTRL(s):			    if (insearch) {				/*				 * Repeat last history search command.				 */				if (srchcmd[0] != '\0') {					/*					 * Have a search string					 * If pattern found in history list					 *    edit new line.					 * else (pattern not found) restore state.					 */					editevent--;					if (reedit(1))						goto enewedit;					else {						beep();						editevent++;						continue;					}				} else {					insearch = 0;					beep();					continue;  /* no search string */				}			    } else {				/*				 * Get new string for history search command.				 */				if (srchback()) {					/*					 * Got an input string from user					 * If pattern found in history list					 *    edit new line.					 * else (pattern not found) restore state.					 */					insearch = 1;					if (reedit(1))						goto enewedit;					else {						beep();						editevent++;						redraw();						continue;					}				} else					continue;  /* user aborted command */			    }			/*			 * ^Xu	undo last change (but won't undo an undo)			 */			case 'u':				insearch = 0;				CP(linebuf, oldbuf);				/*				 * Redraw the line				 */				vsetcurs(linebuf);				normline();				/*				 * Clear from last char to end of line				 */				destcol = column(strend(linebuf)) + 1;				vclreol();				/*				 * Reset cursor				 */				cursor = oldcursor;				if (*cursor == '\0')					cursor--;				vsetcurs(cursor);				continue;			/*			 * ^XU	undo: restore current line to initial state.			 */			case 'U':				insearch = 0;				CP(linebuf, cmdline);				/*				 * Redraw the line				 */				vsetcurs(linebuf);				normline();				/*				 * Clear from last char to end of line				 */				destcol = column(strend(linebuf)) + 1;				vclreol();				/*				 * Reset cursor to begining of line				 */				vsetcurs(linebuf);				continue;			/*			 * ^X~	Switch case of letter under cursor			 */			case '~':				/*				 * Save command for repeat cmd.				 * Save old line state for undo.				 */				insearch = 0;				setLAST();				CP(oldbuf, linebuf);				oldcursor = cursor;				while (cnt > 0) {					cnt--;					if (isalpha(*cursor))						*cursor ^= ' ';	/* toggle the case */					exputchar(*cursor);					cursor++;					if (*cursor == '\0') {						cursor--;						vsetcurs(cursor);						break;					}				}				continue;#ifdef notdef			/*			 * ^X-ESC	Repeat the last (modifying) command.			 * This is degenerate in Emacs since there is no			 *    change or replace mode, and only the last			 *    single char inserted is saved (no insert mode).			 */			case ESCAPE:				/*				 * Check that there was a last command, and				 * take its count.				 */				insearch = 0;				eforbid (lastcmd[0] == 0);				if (hadcnt)					lastcnt = cnt;				cnt = lastcnt;				hadcnt = lasthad;				vglobp = lastcmd;				goto ereread;#endif			/*			 * 	Abort command (with a little feedback).			 */			default:efonfon:				insearch = 0;				beep();				vmacp = 0;				continue;			} /* end switch on char after ^X */		/*		 * default	Insert one char in the buffer.		 */		default:einsrt:			/*			 * Save command for repeat cmd. Save old line state			 * for undo.  Position cursor and do append.			 * vappend() detects emacs mode & calls vgetline to get			 * a single char, similar to input for vi 'r' cmd.			 */			setLAST();			CP(oldbuf, linebuf);			oldcursor = cursor;			vgoto(column(cursor), 0);			doomed = 0;			if (!vglobp)				ungetkey(c);	/* the char to insert */			vappend('i', cnt, 0);			continue;		} /* end switch (c) */	} /* end for (;;) */}/* * Initialize global variables that need to be set for the start * of an edit line.  This get done by editmain() and when we * scroll to another command line from the history list. */init_globals(){	doomed = 0;	Peekkey = 0;	Outchar = vputchar;	vmacp = 0;	strip(cmdline);		/* 008 RNF */	CP(linebuf, cmdline);	CP(oldbuf, cmdline);	outcol = 0;	destcol = 0;	outline = 0;	destline = 0;	normline();			/* print out cmd line */	destcol = column(strend(linebuf)) + 1;	vclreol();			/* sets markline and markeol */	vsetcurs(linebuf);		/* get destcol and outcol set */	oldcursor = linebuf;	DEL[0] = 0;	INS[0] = 0;	lastcmd[0] = 0;}/************************************************************* * TTY setup code is in this section. *************************************************************/#include <sys/time.h>ttymodevi_tty_setup(onoff)	int onoff;		/* turn special attributes on or off */{	struct tchars  tchars;	/* INT, QUIT, XON, XOFF, EOF, BRK */	struct sgttyb sgtty;	if (onoff) {		/*		 * Setup tty characteristics		 */		if (ioctl(SHIN, TIOCGETP, &sgtty) == -1) {			Perror ("ioctl");	/* 006 - GAG */		}		hold_tty = sgtty;		sgtty.sg_flags &= ~(ECHO|XTABS|CRMOD);		sgtty.sg_flags |= RAW;		ioctl(SHIN, TIOCSETP, &sgtty);		/* Get and save current break character. */		ioctl (SHIN, TIOCGETC, &tchars);		hold_tchars = tchars;		/* Clear the ESC, if necessary */		if (tchars.t_brkc == ESCAPE)		    tchars.t_brkc = -1;		/*		 * Turn off start/stop char's.		 * Also turn off quit since some ttys send quit for right arrow.		 */		tchars.t_quitc = '\377';		tchars.t_startc = '\377';		tchars.t_stopc = '\377';		ioctl (SHIN, TIOCSETC, &tchars);		putpad(KS);		/* Keypad transmit mode */	} else {		struct timeval timeout;		/*		 * Restore tty modes.		 * On a slow network line the KE sequence doesn't get sent		 *    out fast enough.  So the select is an easey way to pause.		 */		putpad(KE);		/* end keypad transmit mode */		flusho();		timeout.tv_sec = 0;		timeout.tv_usec = 100000;	/* 100,000 is 1/10 sec */		(void) select(0, 0, 0, 0, &timeout);		ioctl(SHIN, TIOCSETP, &hold_tty);		ioctl (SHIN, TIOCSETC, &hold_tchars);	}}char	exttytype[ONMSZ] =	{ 'd', 'u', 'm', 'b' };/* * Terminal type initialization routines, * and calculation of flags at entry. */gettmode(){	struct sgttyb tty;	ioctl(SHIN, TIOCGETP, &tty);	UPPERCASE = (tty.sg_flags & LCASE) != 0;	NONL = (tty.sg_flags & CRMOD) == 0;}char *xPC;char **sstrs[] = {	&BC, &CE, &KD, &KE, &KH, &KL, &KR, &KS, &KU, &ND, &xPC, &TA, &UP};bool *sflags[] = {	&AM, &BS, &HC, &HZ, &NC, &XB};char ltcbuf[TCBUFSIZE];setterm(type)	char *type;{	/*	 * Get termcap entry	 */	if (tgetent(ltcbuf, type) != 1) {		return;		/* 006 - GAG */	}	COLUMNS = tgetnum("co");	aoftspace = tspace;	zap();	/*	 * Initialize keypad arrow keys. (up, down, home are done to prevent	 * them from causing strange edit behavior.)	 */	arrows[0].cap = KU; arrows[0].mapto = "k"; arrows[0].descr = "up";	arrows[1].cap = KD; arrows[1].mapto = "j"; arrows[1].descr = "down";	arrows[2].cap = KL; arrows[2].mapto = "h"; arrows[2].descr = "left";	arrows[3].cap = KR; arrows[3].mapto = "l"; arrows[3].descr = "right";	arrows[4].cap = KH; arrows[4].mapto = "H"; arrows[4].descr = "home";	aoftspace = tspace;	CP(exttytype, longname(ltcbuf, type));}/* * Get terminal capabilities (flag & string values). */zap(){	register char *namp;	register bool **fp;	register char ***sp;	namp = "ambshchzncxb";		/* boolean termcap attributes */	fp = sflags;	do {		*(*fp++) = tgetflag(namp);		namp += 2;	} while (*namp);	namp = "bccekdkekhklkrkskundpctaup";	/* string termcap attributes */	sp = sstrs;	do {		*(*sp++) = tgetstr(namp, &aoftspace);		namp += 2;	} while (*namp);	PC = xPC ? xPC[0] : 0;}intsrchback(){	register int idx, c, i;	char *backptr;		/* for deletes during search string entry */	editevent--;	srchptr = srchcmd;	*srchptr = 0;	for (idx = 1; idx < SRCHLEN; idx++) {		i = getkey();		if (i == hold_tty.sg_erase)			i = CTRL(h);		else if (i == hold_tty.sg_kill)			i = -1;		switch (i) {		/*		 * ^C		 * ESCAPE		 *		 * 	Abort command.		 * 	(Maybe we should look up		 *	 intr char in hold_tchars.t_intrc)		 */		case CTRL(c):		case ESCAPE:			beep();			srchcmd[0] = '\0';			editevent++;			redraw();			return(0);		/*		 * 	Execute search.		 */		case NL:		case CR:			*srchptr = 0;			return(1);		/*		 * ^H	Backs up a character in the input.		 */		case CTRL(h):			backptr = srchptr - 1;			if (backptr < srchcmd) {				beep();				continue; /* get another char */			}			goto srchbackup;		/*		 * ^W		Back up a white/non-white word.		 */		case CTRL(w):			wdkind = 1;

⌨️ 快捷键说明

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