📄 editline.c
字号:
/***** Main editing routines for editline library.*/#include <ctype.h>#include "editline.h"#include "edlproto.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)#ifdef NOMETA#define ISMETA(x) ((x) & 0x80)#else#define ISMETA(x) (0) #endif#define UNMETA(x) ((x) & 0x7F)#if !defined(HIST_SIZE)#define HIST_SIZE 20#endif /* !defined(HIST_SIZE) *//*** Key to command mapping.*/typedef struct _KEYMAP { CHAR Key; STATUS (*Func) (void);} KEYMAP;static KEYMAP MetaMap[16] ;static KEYMAP Map[33] ; /*** 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;static CHAR NIL[] = "";static CHAR *Input = NIL;static CHAR *Line = NULL ;static const CHAR *Prompt;static CHAR *Yanked;char *Screen;static char NEWLINE[]= CRLF;/* static char NEWLINE[]= "\r"; */static HISTORY H;int rl_quit;static int Repeat;static int End;static int Mark;static int OldPoint;static int Point;static int PushBack;static int Pushed;static SIZE_T Length;static SIZE_T ScreenCount;SIZE_T ScreenSize;static char *backspace = NULL ;static int TTYwidth;static int TTYrows;/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */#ifdef NOMETAstatic int rl_meta_chars = 0 ;#endif/*** Declarations.*/#ifdef __MSDOS__static int getakey( CHAR *chr );#endif#ifndef __STDC__static CHAR *editinput();extern int read();extern int write();#endif#if 0extern char *getenv();extern char *tgetstr(char * , char ** );extern int tgetent( char * , char *);extern int tgetnum( char * ); #endif /* defined(USE_TERMCAP) *//*** TTY input/output functions.*/voidTTYflush( void ){ if (ScreenCount) { (void)write(1, Screen, ScreenCount); ScreenCount = 0; }}static voidTTYput( const CHAR c ){ Screen[ScreenCount] = c; if (++ScreenCount >= ScreenSize - 1) { ScreenSize += SCREEN_INC; RENEW(Screen, char, ScreenSize); }}static voidTTYputs( const CHAR *p ) { while (*p) TTYput(*p++); fflush(stdout);}static voidTTYshow( CHAR c ){ if (c == DEL) { TTYput('^'); TTYput('?'); } else if (ISCTL(c)) { TTYput('^'); TTYput(UNCTL(c)); }#ifdef NOMETA else if (rl_meta_chars && ISMETA(c)) { TTYput('M'); TTYput('-'); TTYput(UNMETA(c)); }#endif else TTYput(c);}static voidTTYstring( CHAR *p ) { while (*p) TTYshow(*p++);}static UNSI TTYget( void ){ CHAR c; TTYflush(); if (Pushed) { Pushed = 0; return PushBack; } if (*Input) return *Input++;#ifndef __MSDOS__ return read(0, &c, (SIZE_T)1) == 1 ? c : EOF ;#else return getakey( &c ) == 1 ? c : EOF ;#endif}#define TTYback() ((backspace != NULL) ? TTYputs((CHAR *)backspace) : TTYput('\b'))static voidTTYbackn( int n){ while (--n >= 0) TTYback();}static voidTTYinfo( void ){ static int init;#if defined(USE_TERMCAP) const char *term; static 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; } backspace = tgetstr("le", &bp); 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.*/voidcolumns( 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-1; k >= 0; k--, p++) TTYput(*p); if (j + skip < ac) while (++len < longest + 3) TTYput(' '); } TTYputs((CHAR *)NEWLINE); }}static voidreposition(void){ int i; CHAR *p; TTYput('\r'); TTYputs(Prompt); for (i = Point - 1, p = Line; i >= 0; i--, p++) TTYshow(*p);}static voidleft( STATUS Change){ TTYback(); if (Point) { if (ISCTL(Line[Point - 1])) TTYback();#ifdef NOMETA else if (rl_meta_chars && ISMETA(Line[Point - 1])) { TTYback(); TTYback(); }#endif } if (Change == CSmove) Point--;}static voidright( STATUS Change ){ TTYshow(Line[Point]); if (Change == CSmove) Point++;}static STATUSring_bell( void ){ TTYput('\07'); TTYflush(); return CSstay;}static STATUSdo_macro( 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( 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( 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( void ){ return do_case(TOlower);}static STATUScase_up_word( void ){ return do_case(TOupper);}static voidceol( void ){ int extras; int i; CHAR *p; for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) { TTYput(' '); if (ISCTL(*p)) { TTYput(' '); extras++; }#ifdef NOMETA else if (rl_meta_chars && ISMETA(*p)) { TTYput(' '); TTYput(' '); extras += 2; }#endif } for (i += extras; i > Point; i--) TTYback();}static voidclear_line( void ){ Point = ( 0 - strlen(Prompt) ); TTYput('\r'); ceol(); Point = 0; End = 0; Line[0] = '\0';}static STATUSinsert_string( 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) - 1 ; i >= 0; i-- ) q[len + i] = q[i]; COPYFROMTO(&Line[Point], p, len); End += len; Line[End] = '\0'; TTYstring(&Line[Point]); Point += len; if( Point == End ) return CSstay ; else return CSmove;}static CHAR *next_hist( void ){ return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];}static CHAR *prev_hist( void ){ return H.Pos == 0 ? NULL : H.Lines[--H.Pos];}static STATUSdo_insert_hist(CHAR *p){ if (p == NULL) return ring_bell(); Point = 0; reposition(); ceol(); End = 0; return insert_string(p);}static STATUSdo_hist( CHAR *(*move)(void) ){ 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(void){ return do_hist(next_hist);}static STATUSh_prev(void){ return do_hist(prev_hist);}static STATUSh_first(void){ return do_insert_hist(H.Lines[H.Pos = 0]);}static STATUSh_last(void){ return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);}/*** Return zero if pat appears as a substring in text.*/static intsubstrcmp(const char *text, const char *pat, SIZE_T len){ CHAR c; if ((c = *pat) == '\0') return *text == '\0'; for ( ; *text; text++) if ((CHAR) *text == c && strncmp(text, pat, len) == 0) return 0; return 1;}static CHAR *search_hist( CHAR *search, CHAR *(*move)(void) ){ static CHAR *old_search; int len; int pos; int (*match)(const char *, const char *, SIZE_T ); 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( void ){ static int Searching; const CHAR *old_prompt; CHAR *(*move)(void); CHAR *p; if (Searching) return ring_bell(); Searching = 1; clear_line(); old_prompt = Prompt; Prompt = "Search: "; TTYputs(Prompt); move = Repeat == NO_ARG ? prev_hist : next_hist; p = search_hist(editinput(), move); clear_line(); Prompt = old_prompt; TTYputs(Prompt); Searching = 0; return do_insert_hist(p);}static STATUSfd_char( void ){ int i; i = 0; do { if (Point >= End) break; right(CSmove); } while (++i < Repeat); return CSstay;}static voidsave_yank( 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( 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(' '); }#ifdef NOMETA else if (rl_meta_chars && ISMETA(*p)) { i = 3; TTYput(' '); TTYput(' '); }#endif TTYbackn(i); *p = '\0'; return CSmove; } if (Point + count > End && (count = End - Point) <= 0) return CSstay; if (count > 1) save_yank(Point, count); for (p = &Line[Point], i = End - (Point + count) ; i >= 0; i--, p++) p[0] = p[count]; ceol(); End -= count; TTYstring(&Line[Point]); return CSmove;}static STATUSbk_char( void ){ int i; i = 0; do { if (Point == 0) break; left(CSmove); } while (++i < Repeat); return CSstay;}static STATUSbk_del_char( void ){ int i; i = 0; do { if (Point == 0) break; left(CSmove); } while (++i < Repeat); return delete_string(i);}static STATUSdel_char(void){ return delete_string(Repeat == NO_ARG ? 1 : Repeat);}static STATUSredisplay(void){ TTYputs((CHAR *)NEWLINE); TTYputs(Prompt); TTYstring(Line); return CSmove;}static STATUSkill_line(void){ int i; if (Repeat != NO_ARG) { if (Repeat < Point) { i = Point; Point = Repeat; reposition(); (void)delete_string(i - Point); } else if (Repeat > Point) { right(CSmove); (void)delete_string(Repeat - Point - 1); } return CSmove;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -