📄 readline.c
字号:
int total_screen_chars = (screenwidth * screenheight); if (!rl_display_fixed || forced_display) { forced_display = 0; /* If we have more than a screenful of material to display, then only display a screenful. We should display the last screen, not the first. I'll fix this in a minute. */ if (out >= total_screen_chars) out = total_screen_chars - 1; /* Number of screen lines to display. */ inv_botlin = out / screenwidth; /* For each line in the buffer, do the updating display. */ for (linenum = 0; linenum <= inv_botlin; linenum++) update_line (linenum > vis_botlin ? "" : &visible_line[linenum * screenwidth], &invisible_line[linenum * screenwidth], linenum); /* We may have deleted some lines. If so, clear the left over blank ones at the bottom out. */ if (vis_botlin > inv_botlin) { char *tt; for (; linenum <= vis_botlin; linenum++) { tt = &visible_line[linenum * screenwidth]; move_vert (linenum); move_cursor_relative (0, tt); clear_to_eol ((linenum == vis_botlin)? strlen (tt) : screenwidth); } } vis_botlin = inv_botlin; /* Move the cursor where it should be. */ move_vert (c_pos / screenwidth); move_cursor_relative (c_pos % screenwidth, &invisible_line[(c_pos / screenwidth) * screenwidth]); } } else /* Do horizontal scrolling. */ { int lmargin; /* Always at top line. */ last_v_pos = 0; /* If the display position of the cursor would be off the edge of the screen, start the display of this line at an offset that leaves the cursor on the screen. */ if (c_pos - last_lmargin > screenwidth - 2) lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3); else if (c_pos - last_lmargin < 1) lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3); else lmargin = last_lmargin; /* If the first character on the screen isn't the first character in the display line, indicate this with a special character. */ if (lmargin > 0) line[lmargin] = '<'; if (lmargin + screenwidth < out) line[lmargin + screenwidth - 1] = '>'; if (!rl_display_fixed || forced_display || lmargin != last_lmargin) { forced_display = 0; update_line (&visible_line[last_lmargin], &invisible_line[lmargin], 0); move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); last_lmargin = lmargin; } } fflush (out_stream); /* Swap visible and non-visible lines. */ { char *temp = visible_line; visible_line = invisible_line; invisible_line = temp; rl_display_fixed = 0; }}/* PWP: update_line() is based on finding the middle difference of each line on the screen; vis: /old first difference /beginning of line | /old last same /old EOL v v v vold: eddie> Oh, my little gruntle-buggy is to me, as lurgid asnew: eddie> Oh, my little buggy says to me, as lurgid as ^ ^ ^ ^ \beginning of line | \new last same \new end of line \new first difference All are character pointers for the sake of speed. Special cases for no differences, as well as for end of line additions must be handeled. Could be made even smarter, but this works well enough */staticupdate_line (old, new, current_line) register char *old, *new; int current_line;{ register char *ofd, *ols, *oe, *nfd, *nls, *ne; int lendiff, wsatend; /* Find first difference. */ for (ofd = old, nfd = new; (ofd - old < screenwidth) && *ofd && (*ofd == *nfd); ofd++, nfd++) ; /* Move to the end of the screen line. */ for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++); for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++); /* If no difference, continue to next line. */ if (ofd == oe && nfd == ne) return; wsatend = 1; /* flag for trailing whitespace */ ols = oe - 1; /* find last same */ nls = ne - 1; while ((*ols == *nls) && (ols > ofd) && (nls > nfd)) { if (*ols != ' ') wsatend = 0; ols--; nls--; } if (wsatend) { ols = oe; nls = ne; } else if (*ols != *nls) { if (*ols) /* don't step past the NUL */ ols++; if (*nls) nls++; } move_vert (current_line); move_cursor_relative (ofd - old, old); /* if (len (new) > len (old)) */ lendiff = (nls - nfd) - (ols - ofd); /* Insert (diff(len(old),len(new)) ch */ if (lendiff > 0) { if (terminal_can_insert) { extern char *term_IC; /* Sometimes it is cheaper to print the characters rather than use the terminal's capabilities. */ if ((2 * (ne - nfd)) < lendiff && !term_IC) { output_some_chars (nfd, (ne - nfd)); last_c_pos += (ne - nfd); } else { if (*ols) { insert_some_chars (nfd, lendiff); last_c_pos += lendiff; } else { /* At the end of a line the characters do not have to be "inserted". They can just be placed on the screen. */ output_some_chars (nfd, lendiff); last_c_pos += lendiff; } /* Copy (new) chars to screen from first diff to last match. */ if (((nls - nfd) - lendiff) > 0) { output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff)); last_c_pos += ((nls - nfd) - lendiff); } } } else { /* cannot insert chars, write to EOL */ output_some_chars (nfd, (ne - nfd)); last_c_pos += (ne - nfd); } } else /* Delete characters from line. */ { /* If possible and inexpensive to use terminal deletion, then do so. */ if (term_dc && (2 * (ne - nfd)) >= (-lendiff)) { if (lendiff) delete_chars (-lendiff); /* delete (diff) characters */ /* Copy (new) chars to screen from first diff to last match */ if ((nls - nfd) > 0) { output_some_chars (nfd, (nls - nfd)); last_c_pos += (nls - nfd); } } /* Otherwise, print over the existing material. */ else { output_some_chars (nfd, (ne - nfd)); last_c_pos += (ne - nfd); clear_to_eol ((oe - old) - (ne - new)); } }}/* (PWP) tell the update routines that we have moved onto a new (empty) line. */rl_on_new_line (){ if (visible_line) visible_line[0] = '\0'; last_c_pos = last_v_pos = 0; vis_botlin = last_lmargin = 0;}/* Actually update the display, period. */rl_forced_update_display (){ if (visible_line) { register char *temp = visible_line; while (*temp) *temp++ = '\0'; } rl_on_new_line (); forced_display++; rl_redisplay ();}/* Move the cursor from last_c_pos to NEW, which are buffer indices. DATA is the contents of the screen line of interest; i.e., where the movement is being done. */static voidmove_cursor_relative (new, data) int new; char *data;{ register int i; /* It may be faster to output a CR, and then move forwards instead of moving backwards. */ if (new + 1 < last_c_pos - new) {#ifdef __MSDOS__ putc('\r', out_stream);#else tputs (term_cr, 1, output_character_function);#endif last_c_pos = 0; } if (last_c_pos == new) return; if (last_c_pos < new) { /* Move the cursor forward. We do it by printing the command to move the cursor forward if there is one, else print that portion of the output buffer again. Which is cheaper? */ /* The above comment is left here for posterity. It is faster to print one character (non-control) than to print a control sequence telling the terminal to move forward one character. That kind of control is for people who don't know what the data is underneath the cursor. */#if defined (HACK_TERMCAP_MOTION) extern char *term_forward_char; if (term_forward_char) for (i = last_c_pos; i < new; i++) tputs (term_forward_char, 1, output_character_function); else for (i = last_c_pos; i < new; i++) putc (data[i], out_stream);#else for (i = last_c_pos; i < new; i++) putc (data[i], out_stream);#endif /* HACK_TERMCAP_MOTION */ } else backspace (last_c_pos - new); last_c_pos = new;}/* PWP: move the cursor up or down. */move_vert (to) int to;{ void output_character_function (); register int delta, i; if (last_v_pos == to) return; if (to > screenheight) return;#ifdef __GO32__ { int cur_r, cur_c; ScreenGetCursor(&cur_r, &cur_c); ScreenSetCursor(cur_r+to-last_v_pos, cur_c); }#else /* __GO32__ */ if ((delta = to - last_v_pos) > 0) { for (i = 0; i < delta; i++) putc ('\n', out_stream); tputs (term_cr, 1, output_character_function); last_c_pos = 0; } else { /* delta < 0 */ if (term_up && *term_up) for (i = 0; i < -delta; i++) tputs (term_up, 1, output_character_function); }#endif /* __GO32__ */ last_v_pos = to; /* now to is here */}/* Physically print C on out_stream. This is for functions which know how to optimize the display. */rl_show_char (c) int c;{ if (c > 127) { fprintf (out_stream, "M-"); c -= 128; }#if defined (DISPLAY_TABS) if (c < 32 && c != '\t')#else if (c < 32)#endif { c += 64; } putc (c, out_stream); fflush (out_stream);}#if defined (DISPLAY_TABS)intrl_character_len (c, pos) register int c, pos;{ if (c < ' ' || c > 126) { if (c == '\t') return (((pos | (int)7) + 1) - pos); else return (3); } else return (1);}#elseintrl_character_len (c) int c;{ if (c < ' ' || c > 126) return (3); else return (1);}#endif /* DISPLAY_TAB *//* How to print things in the "echo-area". The prompt is treated as a mini-modeline. */rl_message (string, arg1, arg2) char *string;{ sprintf (msg_buf, string, arg1, arg2); rl_display_prompt = msg_buf; rl_redisplay ();}/* How to clear things from the "echo-area". */rl_clear_message (){ rl_display_prompt = rl_prompt; rl_redisplay ();}/* **************************************************************** *//* *//* Terminal and Termcap *//* *//* **************************************************************** */static char *term_buffer = (char *)NULL;static char *term_string_buffer = (char *)NULL;/* Non-zero means this terminal can't really do anything. */int dumb_term = 0;/* On Solaris2, sys/types.h brings in sys/reg.h, which screws up the Termcap variable PC, used below. */#undef PC char PC;char *BC, *UP;/* Some strings to control terminal actions. These are output by tputs (). */char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;int screenwidth, screenheight;/* Non-zero if we determine that the terminal can do character insertion. */int terminal_can_insert = 0;/* How to insert characters. */char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;/* How to delete characters. */char *term_dc, *term_DC;#if defined (HACK_TERMCAP_MOTION)char *term_forward_char;#endif /* HACK_TERMCAP_MOTION *//* How to go up a line. */char *term_up;/* A visible bell, if the terminal can be made to flash the screen. */char *visible_bell;/* Re-initialize the terminal considering that the TERM/TERMCAP variable has changed. */rl_reset_terminal (terminal_name) char *terminal_name;{ init_terminal_io (terminal_name);}init_terminal_io (terminal_name) char *terminal_name;{#ifdef __GO32__ screenwidth = ScreenCols(); screenheight = ScreenRows(); term_cr = "\r"; term_im = term_ei = term_ic = term_IC = (char *)NULL; term_up = term_dc = term_DC = visible_bell = (char *)NULL;#if defined (HACK_TERMCAP_MOTION) term_forward_char = (char *)NULL;#endif terminal_can_insert = 0; return;#else extern char *tgetstr (); char *term, *buffer;#if defined (TIOCGWINSZ) struct winsize window_size;#endif int tty; term = terminal_name ? terminal_name : getenv ("TERM"); if (!term_string_buffer) term_string_buffer = (char *)xmalloc (2048); if (!term_buffer) term_buffer = (char *)xmalloc (2048); buffer = term_string_buffer; term_clrpag = term_cr = term_clreol = (char *)NULL; if (!term) term = "dumb"; if (tgetent (term_buffer, term) <= 0) { dumb_term = 1; screenwidth = 79; screenheight = 24; term_cr = "\r"; term_im = term_ei = term_ic = term_IC = (char *)NULL; term_up = term_dc = term_DC = visible_bell = (char *)NULL;#if defined (HACK_TERMCAP_MOTION) term_forward_char = (char *)NULL;#endif terminal_can_insert = 0; return; } BC = tgetstr ("pc", &buffer); PC = buffer ? *buffer : 0; term_backspace = tgetstr ("le", &buffer); term_cr = tgetstr ("cr", &buffer); term_clreol = tgetstr ("ce", &buffer); term_clrpag = tgetstr ("cl", &buffer); if (!term_cr) term_cr = "\r";#if defined (HACK_TERMCAP_MOTION) term_forward_char = tgetstr ("nd", &buffer);#endif /* HACK_TERMCAP_MOTION */ if (rl_instream) tty = fileno (rl_instream); else tty = 0; screenwidth = screenheight = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -