📄 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 void
TTYflush()
{
if (ScreenCount) {
(void)write(1, Screen, ScreenCount);
ScreenCount = 0;
}
}
STATIC void
TTYput(c)
CHAR c;
{
Screen[ScreenCount] = c;
if (++ScreenCount >= ScreenSize - 1) {
ScreenSize += SCREEN_INC;
RENEW(Screen, char, ScreenSize);
}
}
STATIC void
TTYputs(p)
CHAR *p;
{
while (*p)
TTYput(*p++);
}
STATIC void
TTYshow(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 void
TTYstring(p)
CHAR *p;
{
while (*p)
TTYshow(*p++);
}
STATIC unsigned int
TTYget()
{
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 void
TTYbackn(n)
int n;
{
while (--n >= 0)
TTYback();
}
STATIC void
TTYinfo()
{
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 void
columns(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 void
reposition()
{
int i;
CHAR *p;
TTYput('\r');
TTYputs((CONST CHAR *)Prompt);
for (i = Point, p = Line; --i >= 0; p++)
TTYshow(*p);
}
STATIC void
left(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 void
right(Change)
STATUS Change;
{
TTYshow(Line[Point]);
if (Change == CSmove)
Point++;
}
STATIC STATUS
ring_bell()
{
TTYput('\07');
TTYflush();
return CSstay;
}
STATIC STATUS
do_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 STATUS
do_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 STATUS
do_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 STATUS
case_down_word()
{
return do_case(TOlower);
}
STATIC STATUS
case_up_word()
{
return do_case(TOupper);
}
STATIC void
ceol()
{
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 void
clear_line()
{
Point = -strlen(Prompt);
TTYput('\r');
ceol();
Point = 0;
End = 0;
Line[0] = '\0';
}
STATIC STATUS
insert_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 STATUS
redisplay()
{
TTYputs((CONST CHAR *)NEWLINE);
TTYputs((CONST CHAR *)Prompt);
TTYstring(Line);
return CSmove;
}
STATIC STATUS
toggle_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 STATUS
do_insert_hist(p)
CHAR *p;
{
if (p == NULL)
return ring_bell();
Point = 0;
reposition();
ceol();
End = 0;
return insert_string(p);
}
STATIC STATUS
do_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 STATUS
h_next()
{
return do_hist(next_hist);
}
STATIC STATUS
h_prev()
{
return do_hist(prev_hist);
}
STATIC STATUS
h_first()
{
return do_insert_hist(H.Lines[H.Pos = 0]);
}
STATIC STATUS
h_last()
{
return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
}
/*
** Return zero if pat appears as a substring in text.
*/
STATIC int
substrcmp(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 STATUS
h_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 STATUS
fd_char()
{
int i;
i = 0;
do {
if (Point >= End)
break;
right(CSmove);
} while (++i < Repeat);
return CSstay;
}
STATIC void
save_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 STATUS
delete_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 + -