📄 term.c
字号:
out_buf[out_pos++] = c;
if (out_pos >= OUT_SIZE)
out_flush();
}
/*
* A never-padding out_str.
* use this whenever you don't want to run the string through tputs.
* tputs above is harmless, but tputs from the termcap library
* is likely to strip off leading digits, that it mistakes for padding
* information. (jw)
* This should only be used for writing terminal codes, not for outputting
* normal text (use functions like msg_puts() and screen_putchar() for that).
*/
void
out_str_nf(s)
char_u *s;
{
if (out_pos > OUT_SIZE - 20) /* avoid terminal strings being split up */
out_flush();
while (*s)
out_char_nf(*s++);
/* For testing we write one string at a time. */
if (p_wd)
out_flush();
}
/*
* out_str(s): Put a string character at a time into the output buffer.
* If HAVE_TGETENT is defined use the termcap parser. (jw)
* This should only be used for writing terminal codes, not for outputting
* normal text (use functions like msg_puts() and screen_putchar() for that).
*/
void
out_str(s)
char_u *s;
{
if (out_pos > OUT_SIZE - 20) /* avoid terminal strings being split up */
out_flush();
if (s != NULL && *s)
#ifdef HAVE_TGETENT
tputs((char *)s, 1, TPUTSFUNCAST out_char_nf);
#else
while (*s)
out_char_nf(*s++);
#endif
/* For testing we write one string at a time. */
if (p_wd)
out_flush();
}
/*
* cursor positioning using termcap parser. (jw)
*/
void
term_windgoto(row, col)
int row;
int col;
{
OUT_STR(tgoto((char *)T_CM, col, row));
}
void
term_cursor_right(i)
int i;
{
OUT_STR(tgoto((char *)T_CRI, 0, i));
}
void
term_append_lines(line_count)
int line_count;
{
OUT_STR(tgoto((char *)T_CAL, 0, line_count));
}
void
term_delete_lines(line_count)
int line_count;
{
OUT_STR(tgoto((char *)T_CDL, 0, line_count));
}
void
term_fg_color(n)
int n;
{
/* Use "AF" termcap entry if present, "Sf" entry otherwise */
if (*T_CAF)
term_color(T_CAF, n);
else if (*T_CSF)
term_color(T_CSF, n);
}
void
term_bg_color(n)
int n;
{
/* Use "AB" termcap entry if present, "Sb" entry otherwise */
if (*T_CAB)
term_color(T_CAB, n);
else if (*T_CSB)
term_color(T_CSB, n);
}
static void
term_color(s, n)
char_u *s;
int n;
{
/* Special handling of 16 colors, because termcap can't handle it */
if (n > 7 && atoi((char *)T_CCO) == 16
&& s[0] == ESC && s[1] == '[' && s[2] != NUL
#ifdef TERMINFO
&& STRCMP(s + 3, "%p1%dm") == 0
#else
&& STRCMP(s + 3, "%dm") == 0
#endif
)
{
if (s[2] == '3') /* foreground */
{
#ifdef TERMINFO
OUT_STR(tgoto("\033[9%p1%dm", 0, n - 8));
#else
OUT_STR(tgoto("\033[9%dm", 0, n - 8));
#endif
return;
}
if (s[2] == '4') /* background */
{
#ifdef TERMINFO
OUT_STR(tgoto("\033[10%p1%dm", 0, n - 8));
#else
OUT_STR(tgoto("\033[10%dm", 0, n - 8));
#endif
return;
}
}
OUT_STR(tgoto((char *)s, 0, n));
}
/*
* Make sure we have a valid set or terminal options.
* Replace all entries that are NULL by empty_option
*/
void
ttest(pairs)
int pairs;
{
char *t = NULL;
check_options(); /* make sure no options are NULL */
/* hard requirements */
if (*T_CL == NUL) /* erase display */
t = "cl";
if (*T_CM == NUL) /* cursor motion */
t = "cm";
if (t != NULL)
EMSG2("terminal capability %s required", t);
/*
* if "cs" defined, use a scroll region, it's faster.
*/
if (*T_CS != NUL)
scroll_region = TRUE;
else
scroll_region = FALSE;
if (pairs)
{
/*
* optional pairs
*/
/* TP goes to normal mode for TI (invert) and TB (bold) */
if (*T_ME == NUL)
T_ME = T_MR = T_MD = T_MB = empty_option;
if (*T_SO == NUL || *T_SE == NUL)
T_SO = T_SE = empty_option;
if (*T_US == NUL || *T_UE == NUL)
T_US = T_UE = empty_option;
if (*T_CZH == NUL || *T_CZR == NUL)
T_CZH = T_CZR = empty_option;
/* T_VE is needed even though T_VI is not defined */
if (*T_VE == NUL)
T_VI = empty_option;
/* if 'mr' or 'me' is not defined use 'so' and 'se' */
if (*T_ME == NUL)
{
T_ME = T_SE;
T_MR = T_SO;
T_MD = T_SO;
}
/* if 'so' or 'se' is not defined use 'mr' and 'me' */
if (*T_SO == NUL)
{
T_SE = T_ME;
if (*T_MR == NUL)
T_SO = T_MD;
else
T_SO = T_MR;
}
/* if 'ZH' or 'ZR' is not defined use 'mr' and 'me' */
if (*T_CZH == NUL)
{
T_CZR = T_ME;
if (*T_MR == NUL)
T_CZH = T_MD;
else
T_CZH = T_MR;
}
/* "Sb" and "Sf" come in pairs */
if (*T_CSB == NUL || *T_CSF == NUL)
{
T_CSB = empty_option;
T_CSF = empty_option;
}
/* "AB" and "AF" come in pairs */
if (*T_CAB == NUL || *T_CAF == NUL)
{
T_CAB = empty_option;
T_CAF = empty_option;
}
/* if 'Sb' and 'AB' are not defined, reset "Co" */
if (*T_CSB == NUL && *T_CAB == NUL)
T_CCO = empty_option;
/* Set 'weirdinvert' according to value of 't_xs' */
p_wiv = (*T_XS != NUL);
}
need_gather = TRUE;
}
/*
* Represent the given long_u as individual bytes, with the most significant
* byte first, and store them in dst.
*/
void
add_long_to_buf(val, dst)
long_u val;
char_u *dst;
{
int i;
int shift;
for (i = 1; i <= sizeof(long_u); i++)
{
shift = 8 * (sizeof(long_u) - i);
dst[i - 1] = (char_u) ((val >> shift) & 0xff);
}
}
/*
* Interpret the next string of bytes in buf as a long integer, with the most
* significant byte first. Note that it is assumed that buf has been through
* inchar(), so that NUL and K_SPECIAL will be represented as three bytes each.
* Puts result in val, and returns the number of bytes read from buf
* (between sizeof(long_u) and 2 * sizeof(long_u)), or -1 if not enough bytes
* were present.
*/
int
get_long_from_buf(buf, val)
char_u *buf;
long_u *val;
{
int len;
char_u bytes[sizeof(long_u)];
int i;
int shift;
*val = 0;
len = get_bytes_from_buf(buf, bytes, (int)sizeof(long_u));
if (len != -1)
{
for (i = 0; i < sizeof(long_u); i++)
{
shift = 8 * (sizeof(long_u) - 1 - i);
*val += (long_u)bytes[i] << shift;
}
}
return len;
}
/*
* Read the next num_bytes bytes from buf, and store them in bytes. Assume
* that buf has been through inchar(). Returns the actual number of bytes used
* from buf (between num_bytes and num_bytes*2), or -1 if not enough bytes were
* available.
*/
static int
get_bytes_from_buf(buf, bytes, num_bytes)
char_u *buf;
char_u *bytes;
int num_bytes;
{
int len = 0;
int i;
char_u c;
for (i = 0; i < num_bytes; i++)
{
if ((c = buf[len++]) == NUL)
return -1;
if (c == K_SPECIAL)
{
if (buf[len] == NUL || buf[len + 1] == NUL) /* cannot happen? */
return -1;
if (buf[len++] == (int)KS_ZERO)
c = NUL;
++len; /* skip K_FILLER */
/* else it should be KS_SPECIAL, and c already equals K_SPECIAL */
}
bytes[i] = c;
}
return len;
}
void
check_winsize()
{
static int old_Rows = 0;
if (Columns < MIN_COLUMNS)
Columns = MIN_COLUMNS;
if (Rows < min_rows()) /* need room for one window and command line */
Rows = min_rows();
if (old_Rows != Rows)
{
old_Rows = Rows;
screen_new_rows(); /* may need to update window sizes */
}
}
/*
* set window size
* If 'mustset' is TRUE, we must set Rows and Columns, do not get real
* window size (this is used for the :win command).
* If 'mustset' is FALSE, we may try to get the real window size and if
* it fails use 'width' and 'height'.
*/
void
set_winsize(width, height, mustset)
int width, height;
int mustset;
{
static int busy = FALSE;
/*
* Avoid recursiveness, can happen when setting the window size causes
* another window-changed signal.
*/
if (busy)
return;
if (width < 0 || height < 0) /* just checking... */
return;
if (State == HITRETURN || State == SETWSIZE) /* postpone the resizing */
{
State = SETWSIZE;
return;
}
++busy;
if (State != ASKMORE && State != EXTERNCMD && State != CONFIRM)
screenclear();
else
screen_start(); /* don't know where cursor is now */
#ifdef AMIGA
out_flush(); /* must do this before mch_get_winsize() for some
obscure reason */
#endif /* AMIGA */
if (mustset || (ui_get_winsize() == FAIL && height != 0))
{
Rows = height;
Columns = width;
check_winsize(); /* always check, to get p_scroll right */
ui_set_winsize();
}
else
check_winsize(); /* always check, to get p_scroll right */
if (!starting)
{
maketitle();
/*
* We only redraw when it's needed:
* - While at the more prompt or executing an external command, don't
* redraw, but position the cursor.
* - While editing the command line, only redraw that.
* - in Ex mode, don't redraw anything.
* - Otherwise, redraw right now, and position the cursor.
* Always need to call update_screen() or screenalloc(), to make
* sure Rows/Columns and the size of NextScreen is correct!
*/
if (State == ASKMORE || State == EXTERNCMD || State == CONFIRM)
{
screenalloc(FALSE);
if (State == ASKMORE)
{
msg_moremsg(FALSE); /* display --more-- message again */
msg_row = Rows - 1;
}
#ifdef CON_DIALOG
else if (State == CONFIRM)
{
display_confirm_msg(); /* display ":confirm" message again */
msg_row = Rows - 1;
}
#endif
else
windgoto(msg_row, msg_col); /* put cursor back */
}
else if (State == CMDLINE)
{
update_screen(NOT_VALID);
redrawcmdline();
}
else if (exmode_active)
{
screenalloc(FALSE);
}
else
{
update_topline();
update_screen(NOT_VALID);
if (redrawing())
setcursor();
}
cursor_on(); /* redrawing may have switched it off */
}
out_flush();
--busy;
}
/*
* Set the terminal to TMODE_RAW (for Normal mode) or TMODE_COOK (for external
* commands and Ex mode).
*/
void
settmode(tmode)
int tmode;
{
static int oldtmode = TMODE_COOK;
#ifdef USE_GUI
/* don't set the term where gvim was started to any mode */
if (gui.in_use)
return;
#endif
if (full_screen)
{
/* In Ex mode, never set to RAW */
if (exmode_active)
tmode = TMODE_COOK;
/*
* When returning after calling a shell we want to really set the
* terminal to raw mode, even though we think it already is, because
* the shell program may have reset the terminal mode.
* When we think the terminal is normal, don't try to set it to
* normal again, because that causes problems (logout!) on some
* machines.
*/
if (tmode != TMODE_COOK || oldtmode != TMODE_COOK)
{
out_flush();
mch_settmode(tmode); /* machine specific function */
#ifdef USE_MOUSE
if (tmode != TMODE_RAW)
mch_setmouse(FALSE); /* switch mouse off */
else
setmouse(); /* may switch mouse on */
#endif
out_flush();
oldtmode = tmode;
}
}
}
void
starttermcap()
{
screen_stop_highlight();
if (full_screen && !termcap_active)
{
out_str(T_TI); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -