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 + -
显示快捷键?