📄 display.c
字号:
temp = pmtlen + out + 2; if (temp >= line_size) { line_size = (temp + 1024) - (temp % 1024); visible_line = xrealloc (visible_line, line_size); line = invisible_line = xrealloc (invisible_line, line_size); } strncpy (line + out, prompt_this_line, pmtlen); out += pmtlen; line[out] = '\0'; wrap_offset = 0; }#define CHECK_INV_LBREAKS() \ do { \ if (newlines >= (inv_lbsize - 2)) \ { \ inv_lbsize *= 2; \ inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ } \ } while (0) #define CHECK_LPOS() \ do { \ lpos++; \ if (lpos >= screenwidth) \ { \ if (newlines >= (inv_lbsize - 2)) \ { \ inv_lbsize *= 2; \ inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ } \ inv_lbreaks[++newlines] = out; \ lpos = 0; \ } \ } while (0) /* inv_lbreaks[i] is where line i starts in the buffer. */ inv_lbreaks[newlines = 0] = 0; lpos = out - wrap_offset; /* XXX - what if lpos is already >= screenwidth before we start drawing the contents of the command line? */ while (lpos >= screenwidth) { /* XXX - possible fix from Darin Johnson <darin@acuson.com> for prompt string with invisible characters that is longer than the screen width. XXX - this doesn't work right if invisible characters have to be put on the second screen line -- it adds too much (the number of invisible chars after the screenwidth). */ temp = ((newlines + 1) * screenwidth) + ((newlines == 0) ? wrap_offset : 0); inv_lbreaks[++newlines] = temp; lpos -= screenwidth; } lb_linenum = 0; for (in = 0; in < rl_end; in++) { c = (unsigned char)rl_line_buffer[in]; if (out + 8 >= line_size) /* XXX - 8 for \t */ { line_size *= 2; visible_line = xrealloc (visible_line, line_size); invisible_line = xrealloc (invisible_line, line_size); line = invisible_line; } if (in == rl_point) { c_pos = out; lb_linenum = newlines; } if (META_CHAR (c)) { if (_rl_output_meta_chars == 0) { sprintf (line + out, "\\%o", c); if (lpos + 4 >= screenwidth) { temp = screenwidth - lpos; CHECK_INV_LBREAKS (); inv_lbreaks[++newlines] = out + temp; lpos = 4 - temp; } else lpos += 4; out += 4; } else { line[out++] = c; CHECK_LPOS(); } }#if defined (DISPLAY_TABS) else if (c == '\t') { register int temp, newout;#if 0 newout = (out | (int)7) + 1;#else newout = out + 8 - lpos % 8;#endif temp = newout - out; if (lpos + temp >= screenwidth) { register int temp2; temp2 = screenwidth - lpos; CHECK_INV_LBREAKS (); inv_lbreaks[++newlines] = out + temp2; lpos = temp - temp2; while (out < newout) line[out++] = ' '; } else { while (out < newout) line[out++] = ' '; lpos += temp; } }#endif else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && term_up && *term_up) { line[out++] = '\0'; /* XXX - sentinel */ CHECK_INV_LBREAKS (); inv_lbreaks[++newlines] = out; lpos = 0; } else if (CTRL_CHAR (c) || c == RUBOUT) { line[out++] = '^'; CHECK_LPOS(); line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?'; CHECK_LPOS(); } else { line[out++] = c; CHECK_LPOS(); } } line[out] = '\0'; if (c_pos < 0) { c_pos = out; lb_linenum = newlines; } inv_botlin = lb_botlin = newlines; CHECK_INV_LBREAKS (); inv_lbreaks[newlines+1] = out; cursor_linenum = lb_linenum; /* C_POS == position in buffer where cursor should be placed. */ /* PWP: now is when things get a bit hairy. The visible and invisible line buffers are really multiple lines, which would wrap every (screenwidth - 1) characters. Go through each in turn, finding the changed region and updating it. The line order is top to bottom. */ /* If we can move the cursor up and down, then use multiple lines, otherwise, let long lines display in a single terminal line, and horizontally scroll it. */ if (_rl_horizontal_scroll_mode == 0 && term_up && *term_up) { int nleft, pos, changed_screen_line; 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. */ if (out >= screenchars) out = screenchars - 1; /* The first line is at character position 0 in the buffer. The second and subsequent lines start at inv_lbreaks[N], offset by OFFSET (which has already been calculated above). */#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0)#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l]))#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l])#define VIS_CHARS(line) (visible_line + vis_lbreaks[line])#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line)#define INV_LINE(line) (invisible_line + inv_lbreaks[line]) /* For each line in the buffer, do the updating display. */ for (linenum = 0; linenum <= inv_botlin; linenum++) { update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); /* If this is the line with the prompt, we might need to compensate for invisible characters in the new line. Do this only if there is not more than one new line (which implies that we completely overwrite the old visible line) and the new line is shorter than the old. Make sure we are at the end of the new line before clearing. */ if (linenum == 0 && inv_botlin == 0 && _rl_last_c_pos == out && (wrap_offset > visible_wrap_offset) && (_rl_last_c_pos < visible_first_line_len)) { nleft = screenwidth + wrap_offset - _rl_last_c_pos; if (nleft) _rl_clear_to_eol (nleft); } /* Since the new first line is now visible, save its length. */ if (linenum == 0) visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset; } /* We may have deleted some lines. If so, clear the left over blank ones at the bottom out. */ if (_rl_vis_botlin > inv_botlin) { char *tt; for (; linenum <= _rl_vis_botlin; linenum++) { tt = VIS_CHARS (linenum); _rl_move_vert (linenum); _rl_move_cursor_relative (0, tt); _rl_clear_to_eol ((linenum == _rl_vis_botlin) ? strlen (tt) : screenwidth); } } _rl_vis_botlin = inv_botlin; /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a different screen line during this redisplay. */ changed_screen_line = _rl_last_v_pos != cursor_linenum; if (changed_screen_line) { _rl_move_vert (cursor_linenum); /* If we moved up to the line with the prompt using term_up, the physical cursor position on the screen stays the same, but the buffer position needs to be adjusted to account for invisible characters. */ if (cursor_linenum == 0 && wrap_offset) _rl_last_c_pos += wrap_offset; } /* We have to reprint the prompt if it contains invisible characters, since it's not generally OK to just reprint the characters from the current cursor position. But we only need to reprint it if the cursor is before the last invisible character in the prompt string. */ nleft = visible_length + wrap_offset; if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 && _rl_last_c_pos <= last_invisible && local_prompt) {#if defined (__MSDOS__) putc ('\r', rl_outstream);#else if (term_cr) tputs (term_cr, 1, _rl_output_character_function);#endif _rl_output_some_chars (local_prompt, nleft); _rl_last_c_pos = nleft; } /* Where on that line? And where does that line start in the buffer? */ pos = inv_lbreaks[cursor_linenum]; /* nleft == number of characters in the line buffer between the start of the line and the cursor position. */ nleft = c_pos - pos; /* Since _rl_backspace() doesn't know about invisible characters in the prompt, and there's no good way to tell it, we compensate for those characters here and call _rl_backspace() directly. */ if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos) { _rl_backspace (_rl_last_c_pos - nleft); _rl_last_c_pos = nleft; } if (nleft != _rl_last_c_pos) _rl_move_cursor_relative (nleft, &invisible_line[pos]); } } else /* Do horizontal scrolling. */ {#define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0) int lmargin, ndisp, nleft, phys_c_pos, t; /* Always at top line. */ _rl_last_v_pos = 0; /* Compute where in the buffer the displayed line should start. This will be LMARGIN. */ /* The number of characters that will be displayed before the cursor. */ ndisp = c_pos - wrap_offset; nleft = visible_length + wrap_offset; /* Where the new cursor position will be on the screen. This can be longer than SCREENWIDTH; if it is, lmargin will be adjusted. */ phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset); t = screenwidth / 3; /* If the number of characters had already exceeded the screenwidth, last_lmargin will be > 0. */ /* If the number of characters to be displayed is more than the screen width, compute the starting offset so that the cursor is about two-thirds of the way across the screen. */ if (phys_c_pos > screenwidth - 2) { lmargin = c_pos - (2 * t); if (lmargin < 0) lmargin = 0; /* If the left margin would be in the middle of a prompt with invisible characters, don't display the prompt at all. */ if (wrap_offset && lmargin > 0 && lmargin < nleft) lmargin = nleft; } else if (ndisp < screenwidth - 2) /* XXX - was -1 */ lmargin = 0; else if (phys_c_pos < 1) { /* If we are moving back towards the beginning of the line and the last margin is no longer correct, compute a new one. */ lmargin = ((c_pos - 1) / t) * t; /* XXX */ if (wrap_offset && lmargin > 0 && lmargin < nleft) lmargin = nleft; } 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 SCREENWIDTH characters starting at LMARGIN do not encompass the whole line, indicate that with a special character at the right edge of the screen. If LMARGIN is 0, we need to take the wrap offset into account. */ t = lmargin + M_OFFSET (lmargin, wrap_offset) + screenwidth; if (t < out) line[t - 1] = '>'; if (!rl_display_fixed || forced_display || lmargin != last_lmargin) { forced_display = 0; update_line (&visible_line[last_lmargin], &invisible_line[lmargin], 0, screenwidth + visible_wrap_offset, screenwidth + (lmargin ? 0 : wrap_offset), 0); /* If the visible new line is shorter than the old, but the number of invisible characters is greater, and we are at the end of the new line, we need to clear to eol. */ t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset); if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) && (_rl_last_c_pos == out) && t < visible_first_line_len) { nleft = screenwidth - t; _rl_clear_to_eol (nleft); } visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset); if (visible_first_line_len > screenwidth) visible_first_line_len = screenwidth; _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); last_lmargin = lmargin; } } fflush (rl_outstream); /* Swap visible and non-visible lines. */ { char *temp = visible_line; int *itemp = vis_lbreaks, ntemp = vis_lbsize; visible_line = invisible_line; invisible_line = temp; vis_lbreaks = inv_lbreaks; inv_lbreaks = itemp; vis_lbsize = inv_lbsize; inv_lbsize = ntemp; rl_display_fixed = 0; /* If we are displaying on a single line, and last_lmargin is > 0, we are not displaying any invisible characters, so set visible_wrap_offset to 0. */ if (_rl_horizontal_scroll_mode && last_lmargin) visible_wrap_offset = 0; else visible_wrap_offset = wrap_offset; }}/* 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 handled. Could be made even smarter, but this works well enough */static voidupdate_line (old, new, current_line, omax, nmax, inv_botlin) register char *old, *new;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -