📄 getline.c
字号:
#endif
/* We'll change the result code only if something happens later. */
gl_result = GL_OK;
/* Even if it appears that "vi" is preferred, we
* don't start in gl_vi_mode. They need to hit
* ESC to go into vi command mode.
*/
gl_vi_mode = 0;
vi_count = 0;
vi_delete = 0;
if (gl_vi_preferred < 0) {
gl_vi_preferred = 0;
cp = (char *) getenv("EDITOR");
if (cp != NULL)
gl_vi_preferred = (strstr(cp, "vi") != NULL);
if (gl_vi_preferred == 0)
gl_check_inputrc_for_vi();
}
gl_init();
gl_prompt = (prompt)? prompt : "";
gl_buf[0] = 0;
if (gl_in_hook)
gl_in_hook(gl_buf);
gl_fixup(gl_prompt, -2, GL_BUF_SIZE);
lastch = 0;
#ifdef __windows__
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
#endif
while ((c = gl_getc()) != (-1)) {
gl_extent = 0; /* reset to full extent */
/* Note: \n may or may not be considered printable */
if ((c != '\t') && ((isprint(c) != 0) || ((c & 0x80) != 0))) {
if (gl_vi_mode > 0) {
/* "vi" emulation -- far from perfect,
* but reasonably functional.
*/
vi:
for (count = 0; ; ) {
if (isdigit(c)) {
if (vi_countbuf[sizeof(vi_countbuf) - 2] == '\0')
vi_countbuf[strlen(vi_countbuf)] = (char) c;
} else if (vi_countbuf[0] != '\0') {
vi_count = atoi(vi_countbuf);
memset(vi_countbuf, 0, sizeof(vi_countbuf));
}
switch (c) {
case 'b':
gl_word(-1);
break;
case 'w':
if (vi_delete) {
gl_killword(1);
} else {
gl_word(1);
}
break;
case 'h': /* left */
if (vi_delete) {
if (gl_pos > 0) {
gl_fixup(gl_prompt, -1, gl_pos-1);
gl_del(0, 1);
}
} else {
gl_fixup(gl_prompt, -1, gl_pos-1);
}
break;
case ' ':
case 'l': /* right */
if (vi_delete) {
gl_del(0, 1);
} else {
gl_fixup(gl_prompt, -1, gl_pos+1);
}
break;
case 'k': /* up */
strcpy(gl_buf, hist_prev());
if (gl_in_hook)
gl_in_hook(gl_buf);
gl_fixup(gl_prompt, 0, GL_BUF_SIZE);
break;
case 'j': /* down */
strcpy(gl_buf, hist_next());
if (gl_in_hook)
gl_in_hook(gl_buf);
gl_fixup(gl_prompt, 0, GL_BUF_SIZE);
break;
case 'd':
if (vi_delete == 1) {
gl_kill(0);
vi_count = 1;
vi_delete = 0;
gl_vi_mode = 0;
goto vi_break;
}
vi_delete = 1;
goto vi_break;
case '^': /* start of line */
if (vi_delete) {
vi_count = gl_pos;
gl_fixup(gl_prompt, -1, 0);
for (c = 0; c < vi_count; c++) {
if (gl_cnt > 0)
gl_del(0, 0);
}
vi_count = 1;
vi_delete = 0;
} else {
gl_fixup(gl_prompt, -1, 0);
}
break;
case '$': /* end of line */
if (vi_delete) {
gl_kill(gl_pos);
} else {
loc = (int) strlen(gl_buf);
if (loc > 1)
loc--;
gl_fixup(gl_prompt, -1, loc);
}
break;
case 'p': /* paste after */
gl_fixup(gl_prompt, -1, gl_pos+1);
gl_yank();
break;
case 'P': /* paste before */
gl_yank();
break;
case 'r': /* replace character */
gl_buf[gl_pos] = (char) gl_getc();
gl_fixup(gl_prompt, gl_pos, gl_pos);
vi_count = 1;
break;
case 'R':
gl_overwrite = 1;
gl_vi_mode = 0;
break;
case 'i':
case 'I':
gl_overwrite = 0;
gl_vi_mode = 0;
break;
case 'o':
case 'O':
case 'a':
case 'A':
gl_overwrite = 0;
gl_fixup(gl_prompt, -1, gl_pos+1);
gl_vi_mode = 0;
break;
}
count++;
if (count >= vi_count)
break;
}
vi_count = 1;
vi_delete = 0;
vi_break:
continue;
} else if (gl_search_mode) {
search_addchar(c);
} else {
gl_addchar(c);
}
} else {
if (gl_search_mode) {
if (c == '\033' || c == '\016' || c == '\020') {
search_term();
c = 0; /* ignore the character */
} else if (c == '\010' || c == '\177') {
search_addchar(-1); /* unwind search string */
c = 0;
} else if (c != '\022' && c != '\023') {
search_term(); /* terminate and handle char */
}
}
switch (c) {
case '\n': case '\r': /* newline */
gl_newline();
gl_cleanup();
return gl_buf;
case '\001': gl_fixup(gl_prompt, -1, 0); /* ^A */
break;
case '\002': gl_fixup(gl_prompt, -1, gl_pos-1); /* ^B */
break;
case '\004': /* ^D */
if (gl_cnt == 0) {
gl_buf[0] = 0;
gl_cleanup();
gl_putc('\n');
gl_result = GL_EOF;
return gl_buf;
} else {
gl_del(0, 1);
}
break;
case '\005': gl_fixup(gl_prompt, -1, gl_cnt); /* ^E */
break;
case '\006': gl_fixup(gl_prompt, -1, gl_pos+1); /* ^F */
break;
case '\010': case '\177': gl_del(-1, 0); /* ^H and DEL */
break;
case '\t': /* TAB */
if (gl_completion_proc) {
tmp = gl_pos;
gl_buf[sizeof(gl_buf) - 1] = '\0';
loc = gl_do_tab_completion(gl_buf, &tmp, sizeof(gl_buf), (lastch == '\t'));
gl_buf[sizeof(gl_buf) - 1] = '\0';
if (loc >= 0 || tmp != gl_pos)
gl_fixup(gl_prompt, /* loc */ -2, tmp);
if (lastch == '\t') {
c = 0;
lastch = 0;
}
} else if (gl_tab_hook) {
tmp = gl_pos;
gl_buf[sizeof(gl_buf) - 1] = '\0';
loc = gl_tab_hook(gl_buf, (int) gl_strlen(gl_prompt), &tmp, sizeof(gl_buf));
gl_buf[sizeof(gl_buf) - 1] = '\0';
if (loc >= 0 || tmp != gl_pos)
gl_fixup(gl_prompt, loc, tmp);
}
break;
case '\013': gl_kill(gl_pos); /* ^K */
break;
case '\014': gl_redraw(); /* ^L */
break;
case '\016': /* ^N */
strcpy(gl_buf, hist_next());
if (gl_in_hook)
gl_in_hook(gl_buf);
gl_fixup(gl_prompt, 0, GL_BUF_SIZE);
break;
case '\017': gl_overwrite = !gl_overwrite; /* ^O */
break;
case '\020': /* ^P */
strcpy(gl_buf, hist_prev());
if (gl_in_hook)
gl_in_hook(gl_buf);
gl_fixup(gl_prompt, 0, GL_BUF_SIZE);
break;
case '\022': search_back(1); /* ^R */
break;
case '\023': search_forw(1); /* ^S */
break;
case '\024': gl_transpose(); /* ^T */
break;
case '\025': gl_kill(0); /* ^U */
break;
case '\027': gl_killword(-1); /* ^W */
break;
case '\031': gl_yank(); /* ^Y */
break;
case '\033': /* ansi arrow keys */
c = gl_getcx(3);
if ((c == '[') || (c == 'O')) {
ansi:
switch(c = gl_getc()) {
case 'A': /* up */
strcpy(gl_buf, hist_prev());
if (gl_in_hook)
gl_in_hook(gl_buf);
gl_fixup(gl_prompt, 0, GL_BUF_SIZE);
break;
case 'B': /* down */
strcpy(gl_buf, hist_next());
if (gl_in_hook)
gl_in_hook(gl_buf);
gl_fixup(gl_prompt, 0, GL_BUF_SIZE);
break;
case 'C':
gl_fixup(gl_prompt, -1, gl_pos+1); /* right */
break;
case 'D':
gl_fixup(gl_prompt, -1, gl_pos-1); /* left */
break;
case '0':
case '1':
goto ansi;
default: gl_beep(); /* who knows */
break;
}
} else if ((gl_vi_preferred == 0) && ((c == 'f') || (c == 'F'))) {
gl_word(1);
} else if ((gl_vi_preferred == 0) && ((c == 'b') || (c == 'B'))) {
gl_word(-1);
} else if (c != (-1)) {
/* enter vi command mode */
#if defined(__windows__) || defined(MSDOS)
if (gl_vi_preferred == 0) {
/* On Windows, ESC acts like a line kill,
* so don't use vi mode unless they prefer
* vi mode.
*/
gl_kill(0);
} else
#endif
if (gl_vi_mode == 0) {
gl_vi_mode = 1;
vi_count = 1;
vi_delete = 0;
memset(vi_countbuf, 0, sizeof(vi_countbuf));
if (gl_pos > 0)
gl_fixup(gl_prompt, -2, gl_pos-1); /* left 1 char */
/* Don't bother if the line is empty and we don't
* know for sure if the user wants vi mode.
*/
if ((gl_cnt > 0) || (gl_vi_preferred == 1)) {
/* We still have to use the char read! */
goto vi;
}
gl_vi_mode = 0;
} else {
gl_beep();
}
}
break;
default: /* check for a terminal signal */
if (c > 0) { /* ignore 0 (reset above) */
if (c == gl_intrc) {
gl_result = GL_INTERRUPT;
gl_buf[0] = 0;
gl_cleanup();
#ifdef SIGINT
raise(SIGINT);
gl_init();
gl_redraw();
#endif
return gl_buf;
}
if (c == gl_quitc) {
gl_result = GL_INTERRUPT;
gl_buf[0] = 0;
gl_cleanup();
#ifdef SIGQUIT
raise(SIGQUIT);
gl_init();
gl_redraw();
#endif
return gl_buf;
}
#ifdef __unix__
if (c == gl_suspc || c == gl_dsuspc) {
#ifdef SIGTSTP
gl_result = GL_INTERRUPT;
gl_buf[0] = 0;
gl_cleanup();
sig = SIGTSTP;
kill(0, sig);
gl_init();
gl_redraw();
return gl_buf;
#endif
}
#endif /* __unix__ */
}
if (c > 0)
gl_beep();
break;
}
}
if (c > 0)
lastch = c;
}
gl_buf[0] = 0;
gl_cleanup();
return gl_buf;
}
static void
gl_addchar(int c)
/* adds the character c to the input buffer at current location */
{
int i;
if (gl_cnt >= GL_BUF_SIZE - 1)
gl_error("\n*** Error: getline(): input buffer overflow\n");
if (gl_overwrite == 0 || gl_pos == gl_cnt) {
for (i=gl_cnt; i >= gl_pos; i--)
gl_buf[i+1] = gl_buf[i];
gl_buf[gl_pos] = (char) c;
gl_fixup(gl_prompt, gl_pos, gl_pos+1);
} else {
gl_buf[gl_pos] = (char) c;
gl_extent = 1;
gl_fixup(gl_prompt, gl_pos, gl_pos+1);
}
}
static void
gl_yank(void)
/* adds the kill buffer to the input buffer at current location */
{
int i, len;
len = (int) strlen(gl_killbuf);
if (len > 0) {
if (gl_overwrite == 0) {
if (gl_cnt + len >= GL_BUF_SIZE - 1)
gl_error("\n*** Error: getline(): input buffer overflow\n");
for (i=gl_cnt; i >= gl_pos; i--)
gl_buf[i+len] = gl_buf[i];
for (i=0; i < len; i++)
gl_buf[gl_pos+i] = gl_killbuf[i];
gl_fixup(gl_prompt, gl_pos, gl_pos+len);
} else {
if (gl_pos + len > gl_cnt) {
if (gl_pos + len >= GL_BUF_SIZE - 1)
gl_error("\n*** Error: getline(): input buffer overflow\n");
gl_buf[gl_pos + len] = 0;
}
for (i=0; i < len; i++)
gl_buf[gl_pos+i] = gl_killbuf[i];
gl_extent = len;
gl_fixup(gl_prompt, gl_pos, gl_pos+len);
}
} else
gl_beep();
}
static void
gl_transpose(void)
/* switch character under cursor and to left of cursor */
{
int c;
if (gl_pos > 0 && gl_cnt > gl_pos) {
c = gl_buf[gl_pos-1];
gl_buf[gl_pos-1] = gl_buf[gl_pos];
gl_buf[gl_pos] = (char) c;
gl_extent = 2;
gl_fixup(gl_prompt, gl_pos-1, gl_pos);
} else
gl_beep();
}
static void
gl_newline(void)
/*
* Cleans up entire line before returning to caller. A \n is appended.
* If line longer than screen, we redraw starting at beginning
*/
{
int change = gl_cnt;
int len = gl_cnt;
int loc = gl_width - 5; /* shifts line back to start position */
if (gl_cnt >= GL_BUF_SIZE - 1)
gl_error("\n*** Error: getline(): input buffer overflow\n");
if (gl_out_hook) {
change = gl_out_hook(gl_buf);
len = (int) strlen(gl_buf);
}
if (loc > len)
loc = len;
gl_fixup(gl_prompt, change, loc); /* must do this before appending \n */
gl_buf[len] = '\n';
gl_buf[len+1] = '\0';
gl_putc('\n');
}
static void
gl_del(int loc, int killsave)
/*
* Delete a character. The loc variable can be:
* -1 : delete character to left of cursor
* 0 : delete character under cursor
*/
{
int i, j;
if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
for (j=0, i=gl_pos+loc; i < gl_cnt; i++) {
if ((j == 0) && (killsave != 0) && (gl_vi_mode != 0)) {
gl_killbuf[0] = gl_buf[i];
gl_killbuf[1] = '\0';
j = 1;
}
gl_buf[i] = gl_buf[i+1];
}
gl_fixup(gl_prompt, gl_pos+loc, gl_pos+loc);
} else
gl_beep();
}
static void
gl_kill(int pos)
/* delete from pos to the end of line */
{
if (pos < gl_cnt) {
strcpy(gl_killbuf, gl_buf + pos);
gl_buf[pos] = '\0';
gl_fixup(gl_prompt, pos, pos);
} else
gl_beep();
}
static void
gl_killword(int direction)
{
int pos = gl_pos;
int startpos = gl_pos;
int tmp;
int i;
if (direction > 0) { /* forward */
while (!isspace(gl_buf[pos]) && pos < gl_cnt)
pos++;
while (isspace(gl_buf[pos]) && pos < gl_cnt)
pos++;
} else { /* backward */
if (pos > 0)
pos--;
while (isspace(gl_buf[pos]) && pos > 0)
pos--;
while (!isspace(gl_buf[pos]) && pos > 0)
pos--;
if (pos < gl_cnt && isspace(gl_buf[pos])) /* move onto word */
pos++;
}
if (pos < startpos) {
tmp = pos;
pos = startpos;
startpos = tmp;
}
memcpy(gl_killbuf, gl_buf + startpos, (size_t) (pos - startpos));
gl_killbuf[pos - startpos] = '\0';
if (isspace(gl_killbuf[pos - startpos - 1]))
gl_killbuf[pos - startpos - 1] = '\0';
gl_fixup(gl_prompt, -1, startpos);
for (i=0, tmp=pos - startpos; i<tmp; i++)
gl_del(0, 0);
} /* gl_killword */
static void
gl_word(int direction)
/* move forward or backword one word */
{
int pos = gl_pos;
if (direction > 0) { /* forward */
while (!isspace(gl_buf[pos]) && pos < gl_cnt)
pos++;
while (isspace(gl_buf[pos]) && pos < gl_cnt)
pos++;
} else { /* backword */
if (pos > 0)
pos--;
while (isspace(gl_buf[pos]) && pos > 0)
pos--;
while (!isspace(gl_buf[pos]) && pos > 0)
pos--;
if (pos < gl_cnt && isspace(gl_buf[pos])) /* move onto word */
pos++;
}
gl_fixup(gl_prompt, -1, pos);
}
static void
gl_redraw(void)
/* emit a newline, reset and redraw prompt and current input line */
{
if (gl_init_done > 0) {
gl_putc('\n');
gl_fixup(gl_prompt, -2, gl_pos);
}
}
static void
gl_fixup(const char *prompt, int change, int cursor)
/*
* This function is used both for redrawing when input changes or for
* moving within the input line. The parameters are:
* prompt: compared to last_prompt[] for changes;
* change : the index of the start of changes in the input buffer,
* with -1 indicating no changes, -2 indicating we're on
* a new line, redraw everything.
* cursor : the desired location of the cursor after the call.
* A value of GL_BUF_SIZE can be used to indicate the cursor should
* move just past the end of the input line.
*/
{
static int gl_shift; /* index of first on screen character */
static int off_right; /* true if more text right of screen */
static int off_left; /* true if more text left of screen */
static char last_prompt[80] = "";
int left = 0, right = -1; /* bounds for redraw */
int pad; /* how much to erase at end of line */
int backup; /* how far to backup before fixing */
int new_shift; /* value of shift based on cursor */
int extra; /* adjusts when shift (scroll) happens */
int i;
int new_right = -1; /* alternate right bound, using gl_extent */
int l1, l2;
if (change == -2) { /* reset */
gl_pos = gl_cnt = gl_shift = off_right = off_left = 0;
gl_putc('\r');
gl_puts(prompt);
strcpy(last_prompt, prompt);
change = 0;
gl_width = gl_termw - (int) gl_strlen(prompt);
} else if (strcmp(prompt, last_prompt) != 0) {
l1 = (int) gl_strlen(last_prompt);
l2 = (int) gl_strlen(prompt);
gl_cnt = gl_cnt + l1 - l2;
strcpy(last_prompt, prompt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -