📄 terminal.c
字号:
/*
* If the bidi or shaping settings have changed, flush the bidi
* cache completely.
*/
if (term->cfg.arabicshaping != cfg->arabicshaping ||
term->cfg.bidi != cfg->bidi) {
for (i = 0; i < term->bidi_cache_size; i++) {
sfree(term->pre_bidi_cache[i].chars);
sfree(term->post_bidi_cache[i].chars);
term->pre_bidi_cache[i].width = -1;
term->pre_bidi_cache[i].chars = NULL;
term->post_bidi_cache[i].width = -1;
term->post_bidi_cache[i].chars = NULL;
}
}
term->cfg = *cfg; /* STRUCTURE COPY */
if (reset_wrap)
term->alt_wrap = term->wrap = term->cfg.wrap_mode;
if (reset_decom)
term->alt_om = term->dec_om = term->cfg.dec_om;
if (reset_bce) {
term->use_bce = term->cfg.bce;
set_erase_char(term);
}
if (reset_tblink) {
term->blink_is_real = term->cfg.blinktext;
}
if (reset_charclass)
for (i = 0; i < 256; i++)
term->wordness[i] = term->cfg.wordness[i];
if (term->cfg.no_alt_screen)
swap_screen(term, 0, FALSE, FALSE);
if (term->cfg.no_mouse_rep) {
term->xterm_mouse = 0;
set_raw_mouse_mode(term->frontend, 0);
}
if (term->cfg.no_remote_charset) {
term->cset_attr[0] = term->cset_attr[1] = CSET_ASCII;
term->sco_acs = term->alt_sco_acs = 0;
term->utf = 0;
}
if (!*term->cfg.printer) {
term_print_finish(term);
}
term_schedule_tblink(term);
term_schedule_cblink(term);
}
/*
* Clear the scrollback.
*/
void term_clrsb(Terminal *term)
{
unsigned char *line;
term->disptop = 0;
while ((line = delpos234(term->scrollback, 0)) != NULL) {
sfree(line); /* this is compressed data, not a termline */
}
term->tempsblines = 0;
term->alt_sblines = 0;
update_sbar(term);
}
/*
* Initialise the terminal.
*/
Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata,
void *frontend)
{
Terminal *term;
/*
* Allocate a new Terminal structure and initialise the fields
* that need it.
*/
term = snew(Terminal);
term->frontend = frontend;
term->ucsdata = ucsdata;
term->cfg = *mycfg; /* STRUCTURE COPY */
term->logctx = NULL;
term->compatibility_level = TM_PUTTY;
strcpy(term->id_string, "\033[?6c");
term->cblink_pending = term->tblink_pending = FALSE;
term->paste_buffer = NULL;
term->paste_len = 0;
term->last_paste = 0;
bufchain_init(&term->inbuf);
bufchain_init(&term->printer_buf);
term->printing = term->only_printing = FALSE;
term->print_job = NULL;
term->vt52_mode = FALSE;
term->cr_lf_return = FALSE;
term->seen_disp_event = FALSE;
term->xterm_mouse = term->mouse_is_down = FALSE;
term->reset_132 = FALSE;
term->cblinker = term->tblinker = 0;
term->has_focus = 1;
term->repeat_off = FALSE;
term->termstate = TOPLEVEL;
term->selstate = NO_SELECTION;
term->curstype = 0;
term->screen = term->alt_screen = term->scrollback = NULL;
term->tempsblines = 0;
term->alt_sblines = 0;
term->disptop = 0;
term->disptext = NULL;
term->dispcursx = term->dispcursy = -1;
term->tabs = NULL;
deselect(term);
term->rows = term->cols = -1;
power_on(term, TRUE);
term->beephead = term->beeptail = NULL;
#ifdef OPTIMISE_SCROLL
term->scrollhead = term->scrolltail = NULL;
#endif /* OPTIMISE_SCROLL */
term->nbeeps = 0;
term->lastbeep = FALSE;
term->beep_overloaded = FALSE;
term->attr_mask = 0xffffffff;
term->resize_fn = NULL;
term->resize_ctx = NULL;
term->in_term_out = FALSE;
term->ltemp = NULL;
term->ltemp_size = 0;
term->wcFrom = NULL;
term->wcTo = NULL;
term->wcFromTo_size = 0;
term->window_update_pending = FALSE;
term->bidi_cache_size = 0;
term->pre_bidi_cache = term->post_bidi_cache = NULL;
/* FULL-TERMCHAR */
term->basic_erase_char.chr = CSET_ASCII | ' ';
term->basic_erase_char.attr = ATTR_DEFAULT;
term->basic_erase_char.cc_next = 0;
term->erase_char = term->basic_erase_char;
return term;
}
void term_free(Terminal *term)
{
termline *line;
struct beeptime *beep;
int i;
while ((line = delpos234(term->scrollback, 0)) != NULL)
sfree(line); /* compressed data, not a termline */
freetree234(term->scrollback);
while ((line = delpos234(term->screen, 0)) != NULL)
freeline(line);
freetree234(term->screen);
while ((line = delpos234(term->alt_screen, 0)) != NULL)
freeline(line);
freetree234(term->alt_screen);
if (term->disptext) {
for (i = 0; i < term->rows; i++)
freeline(term->disptext[i]);
}
sfree(term->disptext);
while (term->beephead) {
beep = term->beephead;
term->beephead = beep->next;
sfree(beep);
}
bufchain_clear(&term->inbuf);
if(term->print_job)
printer_finish_job(term->print_job);
bufchain_clear(&term->printer_buf);
sfree(term->paste_buffer);
sfree(term->ltemp);
sfree(term->wcFrom);
sfree(term->wcTo);
for (i = 0; i < term->bidi_cache_size; i++) {
sfree(term->pre_bidi_cache[i].chars);
sfree(term->post_bidi_cache[i].chars);
}
sfree(term->pre_bidi_cache);
sfree(term->post_bidi_cache);
expire_timer_context(term);
sfree(term);
}
/*
* Set up the terminal for a given size.
*/
void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
{
tree234 *newalt;
termline **newdisp, *line;
int i, j, oldrows = term->rows;
int sblen;
int save_alt_which = term->alt_which;
if (newrows == term->rows && newcols == term->cols &&
newsavelines == term->savelines)
return; /* nothing to do */
/* Behave sensibly if we're given zero (or negative) rows/cols */
if (newrows < 1) newrows = 1;
if (newcols < 1) newcols = 1;
deselect(term);
swap_screen(term, 0, FALSE, FALSE);
term->alt_t = term->marg_t = 0;
term->alt_b = term->marg_b = newrows - 1;
if (term->rows == -1) {
term->scrollback = newtree234(NULL);
term->screen = newtree234(NULL);
term->tempsblines = 0;
term->rows = 0;
}
/*
* Resize the screen and scrollback. We only need to shift
* lines around within our data structures, because lineptr()
* will take care of resizing each individual line if
* necessary. So:
*
* - If the new screen is longer, we shunt lines in from temporary
* scrollback if possible, otherwise we add new blank lines at
* the bottom.
*
* - If the new screen is shorter, we remove any blank lines at
* the bottom if possible, otherwise shunt lines above the cursor
* to scrollback if possible, otherwise delete lines below the
* cursor.
*
* - Then, if the new scrollback length is less than the
* amount of scrollback we actually have, we must throw some
* away.
*/
sblen = count234(term->scrollback);
/* Do this loop to expand the screen if newrows > rows */
assert(term->rows == count234(term->screen));
while (term->rows < newrows) {
if (term->tempsblines > 0) {
unsigned char *cline;
/* Insert a line from the scrollback at the top of the screen. */
assert(sblen >= term->tempsblines);
cline = delpos234(term->scrollback, --sblen);
line = decompressline(cline, NULL);
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[j].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 (resize_fn && 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;
pos tp;
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -