📄 editline.c
字号:
/* $Revision: 1.7 $**** Main editing routines for editline library.*/#include "editline.h"#include <signal.h>#include <ctype.h>/*** Manifest constants.*/#define SCREEN_WIDTH 80#define SCREEN_ROWS 24#define NO_ARG (-1)#define DEL 127#define CTL(x) ((x) & 0x1F)#define ISCTL(x) ((x) && (x) < ' ')#define UNCTL(x) ((x) + 64)#define META(x) ((x) | 0x80)#define ISMETA(x) ((x) & 0x80)#define UNMETA(x) ((x) & 0x7F)#if !defined(HIST_SIZE)#define HIST_SIZE 20#endif /* !defined(HIST_SIZE) *//*** Command status codes.*/typedef enum _STATUS { CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal} STATUS;/*** The type of case-changing to perform.*/typedef enum _CASE { TOupper, TOlower} CASE;/*** Key to command mapping.*/typedef struct _KEYMAP { CHAR Key; STATUS (*Function)();} KEYMAP;/*** Command history structure.*/typedef struct _HISTORY { int Size; int Pos; CHAR *Lines[HIST_SIZE];} HISTORY;/*** Globals.*/int rl_eof;int rl_erase;int rl_intr;int rl_kill;int rl_quit;STATIC CHAR NIL[] = "";STATIC CONST CHAR *Input = NIL;STATIC CHAR *Line;STATIC CONST char *Prompt;STATIC CHAR *Yanked;STATIC char *Screen;STATIC char NEWLINE[]= CRLF;STATIC HISTORY H;STATIC int Repeat;STATIC int End;STATIC int Mark;STATIC int OldPoint;STATIC int Point;STATIC int PushBack;STATIC int Pushed;STATIC int Signal;FORWARD KEYMAP Map[33];FORWARD KEYMAP MetaMap[17];STATIC SIZE_T Length;STATIC SIZE_T ScreenCount;STATIC SIZE_T ScreenSize;STATIC char *backspace;STATIC int TTYwidth;STATIC int TTYrows;/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */int rl_meta_chars = 0;/*** Declarations.*/STATIC CHAR *editinput();extern int read();extern int write();#if defined(USE_TERMCAP)extern char *getenv();extern char *tgetstr();extern int tgetent();#endif /* defined(USE_TERMCAP) *//*** TTY input/output functions.*/STATIC voidTTYflush(){ if (ScreenCount) { (void)write(1, Screen, ScreenCount); ScreenCount = 0; }}STATIC voidTTYput(c) CHAR c;{ Screen[ScreenCount] = c; if (++ScreenCount >= ScreenSize - 1) { ScreenSize += SCREEN_INC; RENEW(Screen, char, ScreenSize); }}STATIC voidTTYputs(p) CHAR *p;{ while (*p) TTYput(*p++);}STATIC voidTTYshow(c) CHAR c;{ if (c == DEL) { TTYput('^'); TTYput('?'); } else if (ISCTL(c)) { TTYput('^'); TTYput(UNCTL(c)); } else if (rl_meta_chars && ISMETA(c)) { TTYput('M'); TTYput('-'); TTYput(UNMETA(c)); } else TTYput(c);}STATIC voidTTYstring(p) CHAR *p;{ while (*p) TTYshow(*p++);}STATIC unsigned intTTYget(){ CHAR c; TTYflush(); if (Pushed) { Pushed = 0; return PushBack; } if (*Input) return *Input++; return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;}#define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))STATIC voidTTYbackn(n) int n;{ while (--n >= 0) TTYback();}STATIC voidTTYinfo(){ static int init;#if defined(USE_TERMCAP) char *term; char buff[2048]; char *bp;#endif /* defined(USE_TERMCAP) */#if defined(TIOCGWINSZ) struct winsize W;#endif /* defined(TIOCGWINSZ) */ if (init) {#if defined(TIOCGWINSZ) /* Perhaps we got resized. */ if (ioctl(0, TIOCGWINSZ, &W) >= 0 && W.ws_col > 0 && W.ws_row > 0) { TTYwidth = (int)W.ws_col; TTYrows = (int)W.ws_row; }#endif /* defined(TIOCGWINSZ) */ return; } init++; TTYwidth = TTYrows = 0;#if defined(USE_TERMCAP) bp = &buff[0]; if ((term = getenv("TERM")) == NULL) term = "dumb"; if (tgetent(buff, term) < 0) { TTYwidth = SCREEN_WIDTH; TTYrows = SCREEN_ROWS; return; } if ((backspace = tgetstr("le", &bp)) != NULL) backspace = strdup(backspace); TTYwidth = tgetnum("co"); TTYrows = tgetnum("li");#endif /* defined(USE_TERMCAP) */#if defined(TIOCGWINSZ) if (ioctl(0, TIOCGWINSZ, &W) >= 0) { TTYwidth = (int)W.ws_col; TTYrows = (int)W.ws_row; }#endif /* defined(TIOCGWINSZ) */ if (TTYwidth <= 0 || TTYrows <= 0) { TTYwidth = SCREEN_WIDTH; TTYrows = SCREEN_ROWS; }}/*** Print an array of words in columns.*/STATIC voidcolumns(ac, av) int ac; CHAR **av;{ CHAR *p; int i; int j; int k; int len; int skip; int longest; int cols; /* Find longest name, determine column count from that. */ for (longest = 0, i = 0; i < ac; i++) if ((j = strlen((char *)av[i])) > longest) longest = j; cols = TTYwidth / (longest + 3); TTYputs((CHAR *)NEWLINE); for (skip = ac / cols + 1, i = 0; i < skip; i++) { for (j = i; j < ac; j += skip) { for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++) TTYput(*p); if (j + skip < ac) while (++len < longest + 3) TTYput(' '); } TTYputs((CHAR *)NEWLINE); }}STATIC voidreposition(){ int i; CHAR *p; TTYput('\r'); TTYputs((CONST CHAR *)Prompt); for (i = Point, p = Line; --i >= 0; p++) TTYshow(*p);}STATIC voidleft(Change) STATUS Change;{ TTYback(); if (Point) { if (ISCTL(Line[Point - 1])) TTYback(); else if (rl_meta_chars && ISMETA(Line[Point - 1])) { TTYback(); TTYback(); } } if (Change == CSmove) Point--;}STATIC voidright(Change) STATUS Change;{ TTYshow(Line[Point]); if (Change == CSmove) Point++;}STATIC STATUSring_bell(){ TTYput('\07'); TTYflush(); return CSstay;}STATIC STATUSdo_macro(c) unsigned int c;{ CHAR name[4]; name[0] = '_'; name[1] = c; name[2] = '_'; name[3] = '\0'; if ((Input = (CHAR *)getenv((char *)name)) == NULL) { Input = NIL; return ring_bell(); } return CSstay;}STATIC STATUSdo_forward(move) STATUS move;{ int i; CHAR *p; i = 0; do { p = &Line[Point]; for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++) if (move == CSmove) right(CSstay); for (; Point < End && isalnum(*p); Point++, p++) if (move == CSmove) right(CSstay); if (Point == End) break; } while (++i < Repeat); return CSstay;}STATIC STATUSdo_case(type) CASE type;{ int i; int end; int count; CHAR *p; (void)do_forward(CSstay); if (OldPoint != Point) { if ((count = Point - OldPoint) < 0) count = -count; Point = OldPoint; if ((end = Point + count) > End) end = End; for (i = Point, p = &Line[i]; i < end; i++, p++) { if (type == TOupper) { if (islower(*p)) *p = toupper(*p); } else if (isupper(*p)) *p = tolower(*p); right(CSmove); } } return CSstay;}STATIC STATUScase_down_word(){ return do_case(TOlower);}STATIC STATUScase_up_word(){ return do_case(TOupper);}STATIC voidceol(){ int extras; int i; CHAR *p; for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) { TTYput(' '); if (ISCTL(*p)) { TTYput(' '); extras++; } else if (rl_meta_chars && ISMETA(*p)) { TTYput(' '); TTYput(' '); extras += 2; } } for (i += extras; i > Point; i--) TTYback();}STATIC voidclear_line(){ Point = -strlen(Prompt); TTYput('\r'); ceol(); Point = 0; End = 0; Line[0] = '\0';}STATIC STATUSinsert_string(p) CHAR *p;{ SIZE_T len; int i; CHAR *new; CHAR *q; len = strlen((char *)p); if (End + len >= Length) { if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL) return CSstay; if (Length) { COPYFROMTO(new, Line, Length); DISPOSE(Line); } Line = new; Length += len + MEM_INC; } for (q = &Line[Point], i = End - Point; --i >= 0; ) q[len + i] = q[i]; COPYFROMTO(&Line[Point], p, len); End += len; Line[End] = '\0'; TTYstring(&Line[Point]); Point += len; return Point == End ? CSstay : CSmove;}STATIC STATUSredisplay(){ TTYputs((CONST CHAR *)NEWLINE); TTYputs((CONST CHAR *)Prompt); TTYstring(Line); return CSmove;}STATIC STATUStoggle_meta_mode(){ rl_meta_chars = ! rl_meta_chars; return redisplay();}STATIC CHAR *next_hist(){ return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];}STATIC CHAR *prev_hist(){ return H.Pos == 0 ? NULL : H.Lines[--H.Pos];}STATIC STATUSdo_insert_hist(p) CHAR *p;{ if (p == NULL) return ring_bell(); Point = 0; reposition(); ceol(); End = 0; return insert_string(p);}STATIC STATUSdo_hist(move) CHAR *(*move)();{ CHAR *p; int i; i = 0; do { if ((p = (*move)()) == NULL) return ring_bell(); } while (++i < Repeat); return do_insert_hist(p);}STATIC STATUSh_next(){ return do_hist(next_hist);}STATIC STATUSh_prev(){ return do_hist(prev_hist);}STATIC STATUSh_first(){ return do_insert_hist(H.Lines[H.Pos = 0]);}STATIC STATUSh_last(){ return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);}/*** Return zero if pat appears as a substring in text.*/STATIC intsubstrcmp(text, pat, len) char *text; char *pat; int len;{ char c; if ((c = *pat) == '\0') return *text == '\0'; for ( ; *text; text++) if (*text == c && strncmp(text, pat, len) == 0) return 0; return 1;}STATIC CHAR *search_hist(search, move) CHAR *search; CHAR *(*move)();{ static CHAR *old_search; int len; int pos; int (*match)(); char *pat; /* Save or get remembered search pattern. */ if (search && *search) { if (old_search) DISPOSE(old_search); old_search = (CHAR *)strdup((char *)search); } else { if (old_search == NULL || *old_search == '\0') return NULL; search = old_search; } /* Set up pattern-finder. */ if (*search == '^') { match = strncmp; pat = (char *)(search + 1); } else { match = substrcmp; pat = (char *)search; } len = strlen(pat); for (pos = H.Pos; (*move)() != NULL; ) if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) return H.Lines[H.Pos]; H.Pos = pos; return NULL;}STATIC STATUSh_search(){ static int Searching; CONST char *old_prompt; CHAR *(*move)(); CHAR *p; if (Searching) return ring_bell(); Searching = 1; clear_line(); old_prompt = Prompt; Prompt = "Search: "; TTYputs((CONST CHAR *)Prompt); move = Repeat == NO_ARG ? prev_hist : next_hist; p = editinput(); Prompt = old_prompt; Searching = 0; TTYputs((CONST CHAR *)Prompt); if (p == NULL && Signal > 0) { Signal = 0; clear_line(); return redisplay(); } p = search_hist(p, move); clear_line(); if (p == NULL) { (void)ring_bell(); return redisplay(); } return do_insert_hist(p);}STATIC STATUSfd_char(){ int i; i = 0; do { if (Point >= End) break; right(CSmove); } while (++i < Repeat); return CSstay;}STATIC voidsave_yank(begin, i) int begin; int i;{ if (Yanked) { DISPOSE(Yanked); Yanked = NULL; } if (i < 1) return; if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) { COPYFROMTO(Yanked, &Line[begin], i); Yanked[i] = '\0'; }}STATIC STATUSdelete_string(count) int count;{ int i; CHAR *p; if (count <= 0 || End == Point) return ring_bell(); if (count == 1 && Point == End - 1) { /* Optimize common case of delete at end of line. */ End--; p = &Line[Point]; i = 1; TTYput(' '); if (ISCTL(*p)) { i = 2; TTYput(' '); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -