📄 terminal.c
字号:
sfree(cline); line->temporary = FALSE; /* reconstituted line is now real */ term->tempsblines -= 1; addpos234(term->screen, line, 0); term->curs.y += 1; term->savecurs.y += 1; } else { /* Add a new blank line at the bottom of the screen. */ line = newline(term, newcols, FALSE); addpos234(term->screen, line, count234(term->screen)); } term->rows += 1; } /* Do this loop to shrink the screen if newrows < rows */ while (term->rows > newrows) { if (term->curs.y < term->rows - 1) { /* delete bottom row, unless it contains the cursor */ sfree(delpos234(term->screen, term->rows - 1)); } else { /* push top row to scrollback */ line = delpos234(term->screen, 0); addpos234(term->scrollback, compressline(line), sblen++); freeline(line); term->tempsblines += 1; term->curs.y -= 1; term->savecurs.y -= 1; } term->rows -= 1; } assert(term->rows == newrows); assert(count234(term->screen) == newrows); /* Delete any excess lines from the scrollback. */ while (sblen > newsavelines) { line = delpos234(term->scrollback, 0); sfree(line); sblen--; } if (sblen < term->tempsblines) term->tempsblines = sblen; assert(count234(term->scrollback) <= newsavelines); assert(count234(term->scrollback) >= term->tempsblines); term->disptop = 0; /* Make a new displayed text buffer. */ newdisp = snewn(newrows, termline *); for (i = 0; i < newrows; i++) { newdisp[i] = newline(term, newcols, FALSE); for (j = 0; j < newcols; j++) newdisp[i]->chars[i].attr = ATTR_INVALID; } if (term->disptext) { for (i = 0; i < oldrows; i++) freeline(term->disptext[i]); } sfree(term->disptext); term->disptext = newdisp; term->dispcursx = term->dispcursy = -1; /* Make a new alternate screen. */ newalt = newtree234(NULL); for (i = 0; i < newrows; i++) { line = newline(term, newcols, TRUE); addpos234(newalt, line, i); } if (term->alt_screen) { while (NULL != (line = delpos234(term->alt_screen, 0))) freeline(line); freetree234(term->alt_screen); } term->alt_screen = newalt; term->alt_sblines = 0; term->tabs = sresize(term->tabs, newcols, unsigned char); { int i; for (i = (term->cols > 0 ? term->cols : 0); i < newcols; i++) term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE); } /* Check that the cursor positions are still valid. */ if (term->savecurs.y < 0) term->savecurs.y = 0; if (term->savecurs.y >= newrows) term->savecurs.y = newrows - 1; if (term->curs.y < 0) term->curs.y = 0; if (term->curs.y >= newrows) term->curs.y = newrows - 1; if (term->curs.x >= newcols) term->curs.x = newcols - 1; term->alt_x = term->alt_y = 0; term->wrapnext = term->alt_wnext = FALSE; term->rows = newrows; term->cols = newcols; term->savelines = newsavelines; swap_screen(term, save_alt_which, FALSE, FALSE); update_sbar(term); term_update(term); if (term->resize_fn) term->resize_fn(term->resize_ctx, term->cols, term->rows);}/* * Hand a function and context pointer to the terminal which it can * use to notify a back end of resizes. */void term_provide_resize_fn(Terminal *term, void (*resize_fn)(void *, int, int), void *resize_ctx){ term->resize_fn = resize_fn; term->resize_ctx = resize_ctx; if (term->cols > 0 && term->rows > 0) resize_fn(resize_ctx, term->cols, term->rows);}/* Find the bottom line on the screen that has any content. * If only the top line has content, returns 0. * If no lines have content, return -1. */ static int find_last_nonempty_line(Terminal * term, tree234 * screen){ int i; for (i = count234(screen) - 1; i >= 0; i--) { termline *line = index234(screen, i); int j; for (j = 0; j < line->cols; j++) if (!termchars_equal(&line->chars[j], &term->erase_char)) break; if (j != line->cols) break; } return i;}/* * Swap screens. If `reset' is TRUE and we have been asked to * switch to the alternate screen, we must bring most of its * configuration from the main screen and erase the contents of the * alternate screen completely. (This is even true if we're already * on it! Blame xterm.) */static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos){ int t; tree234 *ttr; if (!which) reset = FALSE; /* do no weird resetting if which==0 */ if (which != term->alt_which) { term->alt_which = which; ttr = term->alt_screen; term->alt_screen = term->screen; term->screen = ttr; term->alt_sblines = find_last_nonempty_line(term, term->alt_screen) + 1; t = term->curs.x; if (!reset && !keep_cur_pos) term->curs.x = term->alt_x; term->alt_x = t; t = term->curs.y; if (!reset && !keep_cur_pos) term->curs.y = term->alt_y; term->alt_y = t; t = term->marg_t; if (!reset) term->marg_t = term->alt_t; term->alt_t = t; t = term->marg_b; if (!reset) term->marg_b = term->alt_b; term->alt_b = t; t = term->dec_om; if (!reset) term->dec_om = term->alt_om; term->alt_om = t; t = term->wrap; if (!reset) term->wrap = term->alt_wrap; term->alt_wrap = t; t = term->wrapnext; if (!reset) term->wrapnext = term->alt_wnext; term->alt_wnext = t; t = term->insert; if (!reset) term->insert = term->alt_ins; term->alt_ins = t; t = term->cset; if (!reset) term->cset = term->alt_cset; term->alt_cset = t; t = term->utf; if (!reset) term->utf = term->alt_utf; term->alt_utf = t; t = term->sco_acs; if (!reset) term->sco_acs = term->alt_sco_acs; term->alt_sco_acs = t; } if (reset && term->screen) { /* * Yes, this _is_ supposed to honour background-colour-erase. */ erase_lots(term, FALSE, TRUE, TRUE); }}/* * Update the scroll bar. */static void update_sbar(Terminal *term){ int nscroll = sblines(term); set_sbar(term->frontend, nscroll + term->rows, nscroll + term->disptop, term->rows);}/* * Check whether the region bounded by the two pointers intersects * the scroll region, and de-select the on-screen selection if so. */static void check_selection(Terminal *term, pos from, pos to){ if (poslt(from, term->selend) && poslt(term->selstart, to)) deselect(term);}/* * Scroll the screen. (`lines' is +ve for scrolling forward, -ve * for backward.) `sb' is TRUE if the scrolling is permitted to * affect the scrollback buffer. */static void scroll(Terminal *term, int topline, int botline, int lines, int sb){ termline *line; int i, seltop, olddisptop, shift; if (topline != 0 || term->alt_which != 0) sb = FALSE; olddisptop = term->disptop; shift = lines; if (lines < 0) { while (lines < 0) { line = delpos234(term->screen, botline); resizeline(term, line, term->cols); for (i = 0; i < term->cols; i++) copy_termchar(line, i, &term->erase_char); line->lattr = LATTR_NORM; addpos234(term->screen, line, topline); if (term->selstart.y >= topline && term->selstart.y <= botline) { term->selstart.y++; if (term->selstart.y > botline) { term->selstart.y = botline + 1; term->selstart.x = 0; } } if (term->selend.y >= topline && term->selend.y <= botline) { term->selend.y++; if (term->selend.y > botline) { term->selend.y = botline + 1; term->selend.x = 0; } } lines++; } } else { while (lines > 0) { line = delpos234(term->screen, topline); cc_check(line); /* XXX-REMOVE-BEFORE-RELEASE */ if (sb && term->savelines > 0) { int sblen = count234(term->scrollback); /* * We must add this line to the scrollback. We'll * remove a line from the top of the scrollback if * the scrollback is full. */ if (sblen == term->savelines) { unsigned char *cline; sblen--; cline = delpos234(term->scrollback, 0); sfree(cline); } else term->tempsblines += 1; addpos234(term->scrollback, compressline(line), sblen); /* now `line' itself can be reused as the bottom line */ /* * If the user is currently looking at part of the * scrollback, and they haven't enabled any options * that are going to reset the scrollback as a * result of this movement, then the chances are * they'd like to keep looking at the same line. So * we move their viewpoint at the same rate as the * scroll, at least until their viewpoint hits the * top end of the scrollback buffer, at which point * we don't have the choice any more. * * Thanks to Jan Holmen Holsten for the idea and * initial implementation. */ if (term->disptop > -term->savelines && term->disptop < 0) term->disptop--; } resizeline(term, line, term->cols); for (i = 0; i < term->cols; i++) copy_termchar(line, i, &term->erase_char); line->lattr = LATTR_NORM; addpos234(term->screen, line, botline); /* * If the selection endpoints move into the scrollback, * we keep them moving until they hit the top. However, * of course, if the line _hasn't_ moved into the * scrollback then we don't do this, and cut them off * at the top of the scroll region. * * This applies to selstart and selend (for an existing * selection), and also selanchor (for one being * selected as we speak). */ seltop = sb ? -term->savelines : topline; if (term->selstate != NO_SELECTION) { if (term->selstart.y >= seltop && term->selstart.y <= botline) { term->selstart.y--; if (term->selstart.y < seltop) { term->selstart.y = seltop; term->selstart.x = 0; } } if (term->selend.y >= seltop && term->selend.y <= botline) { term->selend.y--; if (term->selend.y < seltop) { term->selend.y = seltop; term->selend.x = 0; } } if (term->selanchor.y >= seltop && term->selanchor.y <= botline) { term->selanchor.y--; if (term->selanchor.y < seltop) { term->selanchor.y = seltop; term->selanchor.x = 0; } } } lines--; } }#ifdef OPTIMISE_SCROLL shift += term->disptop - olddisptop; if (shift < term->rows && shift > -term->rows && shift != 0) scroll_display(term, topline, botline, shift);#endif /* OPTIMISE_SCROLL */}#ifdef OPTIMISE_SCROLL/* * Add a scroll of a region on the screen into the pending scroll list. * `lines' is +ve for scrolling forward, -ve for backward. * * If the scroll is on the same area as the last scroll in the list, * merge them. */static void save_scroll(Terminal *term, int topline, int botline, int lines){ struct scrollregion *newscroll; if (term->scrolltail && term->scrolltail->topline == topline && term->scrolltail->botline == botline) { term->scrolltail->lines += lines; } else { newscroll = snew(struct scrollregion); newscroll->topline = topline; newscroll->botline = botline; newscroll->lines = lines; newscroll->next = NULL; if (!term->scrollhead) term->scrollhead = newscroll; else term->scrolltail->next = newscroll; term->scrolltail = newscroll; }}/* * Scroll the physical display, and our conception of it in disptext. */static void scroll_display(Terminal *term, int topline, int botline, int lines){ int distance, nlines, i, j; distance = lines > 0 ? lines : -lines; nlines = botline - topline + 1 - distance; if (lines > 0) { for (i = 0; i < nlines; i++) for (j = 0; j < term->cols; j++) copy_termchar(term->disptext[start+i], j, term->disptext[start+i+distance]->chars+j); if (term->dispcursy >= 0 && term->dispcursy >= topline + distance && term->dispcursy < topline + distance + nlines) term->dispcursy -= distance; for (i = 0; i < distance; i++) for (j = 0; j < term->cols; j++) term->disptext[start+nlines+i]->chars[j].attr |= ATTR_INVALID; } else { for (i = nlines; i-- ;) for (j = 0; j < term->cols; j++) copy_termchar(term->disptext[start+i+distance], j, term->disptext[start+i]->chars+j); if (term->dispcursy >= 0 && term->dispcursy >= topline && term->dispcursy < topline + nlines) term->dispcursy += distance; for (i = 0; i < distance; i++) for (j = 0; j < term->cols; j++) term->disptext[start+i]->chars[j].attr |= ATTR_INVALID; } save_scroll(term, topline, botline, lines);}#endif /* OPTIMISE_SCROLL *//* * Move the cursor to a given position, clipping at boundaries. We * may or may not want to clip at the scroll margin: marg_clip is 0 * not to, 1 to disallow _passing_ the margins, and 2 to disallow * even _being_ outside the margins. */static void move(Terminal *term, int x, int y, int marg_clip){ if (x < 0) x = 0; if (x >= term->cols) x = term->cols - 1; if (marg_clip) { if ((term->curs.y >= term->marg_t || marg_clip == 2) && y < term->marg_t) y = term->marg_t; if ((term->curs.y <= term->marg_b || marg_clip == 2) && y > term->marg_b) y = term->marg_b; } if (y < 0) y = 0; if (y >= term->rows) y = term->rows - 1; term->curs.x = x; term->curs.y = y; term->wrapnext = FALSE;}/* * Save or restore the cursor and SGR mode. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -