mirror of
https://github.com/neovim/neovim.git
synced 2026-03-11 03:25:45 +00:00
perf(tui): faster implementation of terminfo
The processing of terminfo can be separated into two steps:
1. The initialization of terminfo, which includes trying to find $TERM
in a terminfo database file. As a fallback, common terminfo
definitions are compiled in. After this, we apply a lot of ad-hoc
patching to cover over limitations of terminfo.
2. While processing updates from nvim, actually using terminfo strings
and formatting them with runtime values. for this part, terminfo
essentially is a hyper-enhanced version of snprintf(), including
a sm0l stack based virtual machine which can manipulate the runtime
parameters.
This PR completely replaces libuniblium for step 2, with code
vendored from NetBSD's libtermkey which has been adapted to use typesafe
input parameters and to write into an output buffer in place.
The most immedatiate effects is a performance enhancement of
update_attrs() which is a very hot function when profiling the
TUI-process part of screen updates. In a stupid microbenchmark
(essentially calling nvim__screenshot over and over in a loop) this
leads to a speedup of ca 1.5x for redrawing the screen on the TUI-side.
What this means in practise when using nvim as a text editor is probably
no noticible effect at all, and when reabusing nvim as idk a full screen
RGB ASCII art rendrer maybe an increase from 72 to 75 FPS LMAO.
As nice side-effect, reduce the usage of unibilium to initialization only..
which will make it easier to remove, replace or make unibilium optional,
adressing #31989. Specifically, the builtin fallback doesn't use
unibilium at all, so a unibilium-free build is in principle possible
if the builtin definitions are good enough.
As a caveat, this PR doesn't touch libtermkey at all, which still has a
conditional dependency on unibilium. This will be investigated in a
follow-up PR
Note: the check of $TERMCOLOR was moved from tui/tui.c to
_defaults.lua in d7651b27d5 as we want to
skip the logic in _defaults.lua if the env var was set, but there
is no harm in TUI getting the right value when the TUI is trying to
initialize its terminfo shenanigans. Also this check is needed when
a TUI connects to a `--headless` server later, which will observe
a different $TERMCOLOR value than the nvim core process itself.
This commit is contained in:
@@ -1,87 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# usage: ./scripts/update_terminfo.sh
|
||||
#
|
||||
# This script does:
|
||||
#
|
||||
# 1. Download Dickey's terminfo.src
|
||||
# 2. Compile temporary terminfo database from terminfo.src
|
||||
# 3. Use database to generate src/nvim/tui/terminfo_defs.h
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
url='https://invisible-island.net/datafiles/current/terminfo.src.gz'
|
||||
target='src/nvim/tui/terminfo_defs.h'
|
||||
|
||||
readonly -A entries=(
|
||||
[ansi]=ansi_terminfo
|
||||
[interix]=interix_8colour_terminfo
|
||||
[iterm2]=iterm_256colour_terminfo
|
||||
[linux]=linux_16colour_terminfo
|
||||
[putty-256color]=putty_256colour_terminfo
|
||||
[rxvt-256color]=rxvt_256colour_terminfo
|
||||
[screen-256color]=screen_256colour_terminfo
|
||||
[st-256color]=st_256colour_terminfo
|
||||
[tmux-256color]=tmux_256colour_terminfo
|
||||
[vte-256color]=vte_256colour_terminfo
|
||||
[xterm-256color]=xterm_256colour_terminfo
|
||||
[cygwin]=cygwin_terminfo
|
||||
[win32con]=win32con_terminfo
|
||||
[conemu]=conemu_terminfo
|
||||
[vtpcon]=vtpcon_terminfo
|
||||
)
|
||||
|
||||
db="$(mktemp -du)"
|
||||
|
||||
print_bold() {
|
||||
printf "\\e[1m%b\\e[0m" "$*"
|
||||
}
|
||||
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
#
|
||||
# Get terminfo.src
|
||||
#
|
||||
print_bold '[*] Get terminfo.src\n'
|
||||
curl -O "$url"
|
||||
gunzip -f terminfo.src.gz
|
||||
|
||||
#
|
||||
# Build terminfo database
|
||||
#
|
||||
print_bold '[*] Build terminfo database\n'
|
||||
cat terminfo.src scripts/windows.ti | tic -x -o "$db" -
|
||||
rm -f terminfo.src
|
||||
|
||||
#
|
||||
# Write src/nvim/tui/terminfo_defs.h
|
||||
#
|
||||
print_bold "[*] Writing $target... "
|
||||
sorted_terms="$(echo "${!entries[@]}" | tr ' ' '\n' | sort | xargs)"
|
||||
|
||||
cat > "$target" <<EOF
|
||||
// uncrustify:off
|
||||
|
||||
// Generated by scripts/update_terminfo.sh and $(tic -V)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
EOF
|
||||
|
||||
for term in $sorted_terms; do
|
||||
path="$(find "$db" -name "$term")"
|
||||
if [ -z "$path" ]; then
|
||||
>&2 echo "Not found: $term. Skipping."
|
||||
continue
|
||||
fi
|
||||
printf '\n'
|
||||
infocmp -L -x -1 -A "$db" "$term" | sed -e '1d' -e 's#^#// #' | tr '\t' ' '
|
||||
printf 'static const int8_t %s[] = {\n' "${entries[$term]}"
|
||||
printf ' '
|
||||
od -v -t d1 < "$path" | cut -c9- | xargs | tr ' ' ','
|
||||
printf '};\n'
|
||||
done >> "$target"
|
||||
|
||||
print_bold 'done\n'
|
||||
204
src/gen/gen_terminfo.lua
Normal file
204
src/gen/gen_terminfo.lua
Normal file
@@ -0,0 +1,204 @@
|
||||
-- usage: nvim -ll src/gen/gen_terminfo.lua
|
||||
--
|
||||
-- This script does:
|
||||
--
|
||||
-- 1. Download Dickey's terminfo.src
|
||||
-- 2. Compile temporary terminfo database from terminfo.src
|
||||
-- 3. Use database to generate src/nvim/tui/terminfo_defs.h
|
||||
|
||||
local url = 'https://invisible-island.net/datafiles/current/terminfo.src.gz'
|
||||
local target_gen = 'src/nvim/tui/terminfo_defs.h'
|
||||
local target_enum = 'src/nvim/tui/terminfo_enum_defs.h'
|
||||
|
||||
local entries = {
|
||||
{ 'ansi', 'ansi_terminfo' },
|
||||
{ 'interix', 'interix_8colour_terminfo' },
|
||||
{ 'iterm2', 'iterm_256colour_terminfo' },
|
||||
{ 'linux', 'linux_16colour_terminfo' },
|
||||
{ 'putty-256color', 'putty_256colour_terminfo' },
|
||||
{ 'rxvt-256color', 'rxvt_256colour_terminfo' },
|
||||
{ 'screen-256color', 'screen_256colour_terminfo' },
|
||||
{ 'st-256color', 'st_256colour_terminfo' },
|
||||
{ 'tmux-256color', 'tmux_256colour_terminfo' },
|
||||
{ 'vte-256color', 'vte_256colour_terminfo' },
|
||||
{ 'xterm-256color', 'xterm_256colour_terminfo' },
|
||||
{ 'cygwin', 'cygwin_terminfo' },
|
||||
{ 'win32con', 'win32con_terminfo' },
|
||||
{ 'conemu', 'conemu_terminfo' },
|
||||
{ 'vtpcon', 'vtpcon_terminfo' },
|
||||
}
|
||||
|
||||
local wanted_numbers = { 'max_colors', 'lines', 'columns' }
|
||||
local wanted_strings = {
|
||||
'carriage_return',
|
||||
'change_scroll_region',
|
||||
'clear_screen',
|
||||
'clr_eol',
|
||||
'clr_eos',
|
||||
'cursor_address',
|
||||
'cursor_down',
|
||||
'cursor_invisible',
|
||||
'cursor_left',
|
||||
'cursor_home',
|
||||
'cursor_normal',
|
||||
'cursor_up',
|
||||
'cursor_right',
|
||||
'delete_line',
|
||||
'enter_bold_mode',
|
||||
'enter_ca_mode',
|
||||
'enter_italics_mode',
|
||||
'enter_reverse_mode',
|
||||
'enter_standout_mode',
|
||||
'enter_underline_mode',
|
||||
'erase_chars',
|
||||
'exit_attribute_mode',
|
||||
'exit_ca_mode',
|
||||
'from_status_line',
|
||||
'insert_line',
|
||||
'keypad_local',
|
||||
'keypad_xmit',
|
||||
'parm_delete_line',
|
||||
'parm_down_cursor',
|
||||
'parm_insert_line',
|
||||
'parm_left_cursor',
|
||||
'parm_right_cursor',
|
||||
'parm_up_cursor',
|
||||
'set_a_background',
|
||||
'set_a_foreground',
|
||||
'set_attributes',
|
||||
'set_lr_margin',
|
||||
'to_status_line',
|
||||
}
|
||||
|
||||
local wanted_strings_ext = {
|
||||
-- the following are our custom name for extensions, see "extmap"
|
||||
{ 'reset_cursor_style', 'se' },
|
||||
{ 'set_cursor_style', 'Ss' },
|
||||
-- terminfo describes strikethrough modes as rmxx/smxx with respect
|
||||
-- to the ECMA-48 strikeout/crossed-out attributes.
|
||||
{ 'enter_strikethrough_mode', 'smxx' },
|
||||
{ 'set_rgb_foreground', 'setrgbf' },
|
||||
{ 'set_rgb_background', 'setrgbb' },
|
||||
{ 'set_cursor_color', 'Cs' },
|
||||
{ 'reset_cursor_color', 'Cr' },
|
||||
{ 'set_underline_style', 'Smulx' },
|
||||
}
|
||||
|
||||
local db = '/tmp/nvim_terminfo'
|
||||
if vim.uv.fs_stat(db) == nil then
|
||||
local function sys(cmd)
|
||||
print(cmd)
|
||||
os.execute(cmd)
|
||||
end
|
||||
sys('curl -O ' .. url)
|
||||
sys('gunzip -f terminfo.src.gz')
|
||||
sys('cat terminfo.src scripts/windows.ti | tic -x -o "' .. db .. '" -')
|
||||
sys('rm -f terminfo.src')
|
||||
else
|
||||
print('using cached terminfo in ' .. db)
|
||||
end
|
||||
|
||||
local function enumify(str)
|
||||
return 'kTerm_' .. str
|
||||
end
|
||||
local function quote(str)
|
||||
if str == nil then
|
||||
return 'NULL'
|
||||
end
|
||||
-- remungle the strings to look like C strings
|
||||
str = string.gsub(str, '\\E', '\\033')
|
||||
str = string.gsub(str, '%^G', '\\a')
|
||||
str = string.gsub(str, '%^H', '\\b')
|
||||
str = string.gsub(str, '%^O', '\\017') -- o dod
|
||||
-- str = string.gsub(str, "\\", "\\\\")
|
||||
str = string.gsub(str, '"', '\\"')
|
||||
return '"' .. str .. '"'
|
||||
end
|
||||
|
||||
local dbg = function() end
|
||||
-- dbg = print
|
||||
|
||||
local f_enum = io.open(target_enum, 'wb')
|
||||
f_enum:write('// genenerated by src/gen/gen_terminfo.lua\n\n')
|
||||
f_enum:write('#pragma once\n\n')
|
||||
f_enum:write('typedef enum {\n')
|
||||
for _, name in ipairs(wanted_strings) do
|
||||
f_enum:write(' ' .. enumify(name) .. ',\n')
|
||||
end
|
||||
f_enum:write('#define kTermExtOffset ' .. enumify(wanted_strings_ext[1][1]) .. '\n')
|
||||
for _, item in ipairs(wanted_strings_ext) do
|
||||
f_enum:write(' ' .. enumify(item[1]) .. ',\n')
|
||||
end
|
||||
f_enum:write(' kTermCount, // sentinel\n')
|
||||
f_enum:write('} TerminfoDef;\n')
|
||||
f_enum:close()
|
||||
|
||||
local f_defs = io.open(target_gen, 'wb')
|
||||
|
||||
f_defs:write('// uncrustify:off\n\n')
|
||||
|
||||
local version = io.popen('infocmp -V'):read '*a'
|
||||
f_defs:write('// Generated by src/gen/gen_terminfo.lua and ' .. version .. '\n')
|
||||
|
||||
f_defs:write('#pragma once\n\n')
|
||||
f_defs:write('#include "nvim/tui/terminfo.h"\n')
|
||||
|
||||
for _, entry in ipairs(entries) do
|
||||
local term, target = unpack(entry)
|
||||
local fil = io.popen('infocmp -L -x -1 -A ' .. db .. ' ' .. term):read '*a'
|
||||
local lines = vim.split(fil, '\n')
|
||||
local prepat = '^%s*([%w_]+)'
|
||||
local boolpat = prepat .. ','
|
||||
local numpat = prepat .. '#([^,]+),'
|
||||
local strpat = prepat .. '=([^,]+),'
|
||||
local bools, nums, strs = {}, {}, {}
|
||||
for i, line in ipairs(lines) do
|
||||
local boolmatch = string.match(line, boolpat)
|
||||
local nummatch, numval = string.match(line, numpat)
|
||||
local strmatch, strval = string.match(line, strpat)
|
||||
if boolmatch then
|
||||
dbg('boolean: ' .. boolmatch)
|
||||
bools[boolmatch] = true
|
||||
elseif nummatch then
|
||||
dbg('number: ' .. nummatch .. ' is ' .. numval)
|
||||
nums[nummatch] = numval
|
||||
elseif strmatch then
|
||||
dbg('string: ' .. strmatch .. ' is ' .. strval)
|
||||
strs[strmatch] = strval
|
||||
else
|
||||
dbg('UNKNOWN:', i, line)
|
||||
end
|
||||
end
|
||||
|
||||
f_defs:write('\nstatic const TerminfoEntry ' .. target .. ' = {\n')
|
||||
f_defs:write(' .bce = ' .. tostring(bools.back_color_erase or false) .. ',\n')
|
||||
local has_Tc_or_RGB = (bools.Tc or bools.RGB) or false
|
||||
f_defs:write(' .has_Tc_or_RGB = ' .. tostring(has_Tc_or_RGB or false) .. ',\n')
|
||||
f_defs:write(' .Su = ' .. tostring(bools.Su or false) .. ',\n')
|
||||
|
||||
for _, name in ipairs(wanted_numbers) do
|
||||
f_defs:write(' .' .. name .. ' = ' .. (nums[name] or '-1') .. ',\n')
|
||||
end
|
||||
f_defs:write(' .defs = {\n')
|
||||
for _, name in ipairs(wanted_strings) do
|
||||
f_defs:write(' [' .. enumify(name) .. '] = ' .. quote(strs[name]) .. ',\n')
|
||||
end
|
||||
for _, item in ipairs(wanted_strings_ext) do
|
||||
f_defs:write(' [' .. enumify(item[1]) .. '] = ' .. quote(strs[item[2]]) .. ',\n')
|
||||
end
|
||||
|
||||
f_defs:write(' },\n')
|
||||
f_defs:write('};\n')
|
||||
end
|
||||
|
||||
f_defs:write('\n#define XLIST_TERMINFO_BUILTIN \\\n')
|
||||
for _, name in ipairs(wanted_strings) do
|
||||
f_defs:write(' X(' .. name .. ') \\\n')
|
||||
end
|
||||
f_defs:write('// end of list\n\n')
|
||||
f_defs:write('#define XLIST_TERMINFO_EXT \\\n')
|
||||
for _, item in ipairs(wanted_strings_ext) do
|
||||
f_defs:write(' X(' .. item[1] .. ', ' .. item[2] .. ') \\\n')
|
||||
end
|
||||
f_defs:write('// end of list\n')
|
||||
f_defs:close()
|
||||
@@ -2198,7 +2198,7 @@ DictAs(eval_statusline_ret) nvim_eval_statusline(String str, Dict(eval_statuslin
|
||||
grpname = syn_id2name(-sp->userhl);
|
||||
} else {
|
||||
snprintf(user_group, sizeof(user_group), "User%d", sp->userhl);
|
||||
grpname = arena_memdupz(arena, user_group, strlen(user_group));
|
||||
grpname = arena_strdup(arena, user_group);
|
||||
}
|
||||
|
||||
const char *combine = sp->item == STL_SIGNCOL ? syn_id2name(scl_hl_id)
|
||||
|
||||
@@ -813,12 +813,19 @@ char *arena_allocz(Arena *arena, size_t size)
|
||||
}
|
||||
|
||||
char *arena_memdupz(Arena *arena, const char *buf, size_t size)
|
||||
FUNC_ATTR_NONNULL_ARG(2)
|
||||
{
|
||||
char *mem = arena_allocz(arena, size);
|
||||
memcpy(mem, buf, size);
|
||||
return mem;
|
||||
}
|
||||
|
||||
char *arena_strdup(Arena *arena, const char *str)
|
||||
FUNC_ATTR_NONNULL_ARG(2)
|
||||
{
|
||||
return arena_memdupz(arena, str, strlen(str));
|
||||
}
|
||||
|
||||
#if defined(EXITFREE)
|
||||
|
||||
# include "nvim/autocmd.h"
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
# include "nvim/os/os.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
long nums[20];
|
||||
char *strings[20];
|
||||
size_t offset;
|
||||
} TPSTACK;
|
||||
|
||||
#include "tui/terminfo.c.generated.h"
|
||||
|
||||
bool terminfo_is_term_family(const char *term, const char *family)
|
||||
@@ -57,167 +63,606 @@ bool terminfo_is_bsd_console(const char *term)
|
||||
/// We do not attempt to detect xterm pretenders here.
|
||||
///
|
||||
/// @param term $TERM value
|
||||
/// @param[out,allocated] termname decided builtin 'term' name
|
||||
/// @param[out,static] termname decided builtin 'term' name
|
||||
/// @return [allocated] terminfo structure
|
||||
static unibi_term *terminfo_builtin(const char *term, char **termname)
|
||||
const TerminfoEntry *terminfo_from_builtin(const char *term, char **termname)
|
||||
{
|
||||
if (terminfo_is_term_family(term, "xterm")) {
|
||||
*termname = xstrdup("builtin_xterm");
|
||||
return unibi_from_mem((const char *)xterm_256colour_terminfo,
|
||||
sizeof xterm_256colour_terminfo);
|
||||
*termname = "builtin_xterm";
|
||||
return &xterm_256colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "screen")) {
|
||||
*termname = xstrdup("builtin_screen");
|
||||
return unibi_from_mem((const char *)screen_256colour_terminfo,
|
||||
sizeof screen_256colour_terminfo);
|
||||
*termname = "builtin_screen";
|
||||
return &screen_256colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "tmux")) {
|
||||
*termname = xstrdup("builtin_tmux");
|
||||
return unibi_from_mem((const char *)tmux_256colour_terminfo,
|
||||
sizeof tmux_256colour_terminfo);
|
||||
*termname = "builtin_tmux";
|
||||
return &tmux_256colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "rxvt")) {
|
||||
*termname = xstrdup("builtin_rxvt");
|
||||
return unibi_from_mem((const char *)rxvt_256colour_terminfo,
|
||||
sizeof rxvt_256colour_terminfo);
|
||||
*termname = "builtin_rxvt";
|
||||
return &rxvt_256colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "putty")) {
|
||||
*termname = xstrdup("builtin_putty");
|
||||
return unibi_from_mem((const char *)putty_256colour_terminfo,
|
||||
sizeof putty_256colour_terminfo);
|
||||
*termname = "builtin_putty";
|
||||
return &putty_256colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "linux")) {
|
||||
*termname = xstrdup("builtin_linux");
|
||||
return unibi_from_mem((const char *)linux_16colour_terminfo,
|
||||
sizeof linux_16colour_terminfo);
|
||||
*termname = "builtin_linux";
|
||||
return &linux_16colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "interix")) {
|
||||
*termname = xstrdup("builtin_interix");
|
||||
return unibi_from_mem((const char *)interix_8colour_terminfo,
|
||||
sizeof interix_8colour_terminfo);
|
||||
*termname = "builtin_interix";
|
||||
return &interix_8colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "iterm")
|
||||
|| terminfo_is_term_family(term, "iterm2")
|
||||
|| terminfo_is_term_family(term, "iTerm.app")
|
||||
|| terminfo_is_term_family(term, "iTerm2.app")) {
|
||||
*termname = xstrdup("builtin_iterm");
|
||||
return unibi_from_mem((const char *)iterm_256colour_terminfo,
|
||||
sizeof iterm_256colour_terminfo);
|
||||
*termname = "builtin_iterm";
|
||||
return &iterm_256colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "st")) {
|
||||
*termname = xstrdup("builtin_st");
|
||||
return unibi_from_mem((const char *)st_256colour_terminfo,
|
||||
sizeof st_256colour_terminfo);
|
||||
*termname = "builtin_st";
|
||||
return &st_256colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "gnome")
|
||||
|| terminfo_is_term_family(term, "vte")) {
|
||||
*termname = xstrdup("builtin_vte");
|
||||
return unibi_from_mem((const char *)vte_256colour_terminfo,
|
||||
sizeof vte_256colour_terminfo);
|
||||
*termname = "builtin_vte";
|
||||
return &vte_256colour_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "cygwin")) {
|
||||
*termname = xstrdup("builtin_cygwin");
|
||||
return unibi_from_mem((const char *)cygwin_terminfo,
|
||||
sizeof cygwin_terminfo);
|
||||
*termname = "builtin_cygwin";
|
||||
return &cygwin_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "win32con")) {
|
||||
*termname = xstrdup("builtin_win32con");
|
||||
return unibi_from_mem((const char *)win32con_terminfo,
|
||||
sizeof win32con_terminfo);
|
||||
*termname = "builtin_win32con";
|
||||
return &win32con_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "conemu")) {
|
||||
*termname = xstrdup("builtin_conemu");
|
||||
return unibi_from_mem((const char *)conemu_terminfo,
|
||||
sizeof conemu_terminfo);
|
||||
*termname = "builtin_conemu";
|
||||
return &conemu_terminfo;
|
||||
} else if (terminfo_is_term_family(term, "vtpcon")) {
|
||||
*termname = xstrdup("builtin_vtpcon");
|
||||
return unibi_from_mem((const char *)vtpcon_terminfo,
|
||||
sizeof vtpcon_terminfo);
|
||||
*termname = "builtin_vtpcon";
|
||||
return &vtpcon_terminfo;
|
||||
} else {
|
||||
*termname = xstrdup("builtin_ansi");
|
||||
return unibi_from_mem((const char *)ansi_terminfo,
|
||||
sizeof ansi_terminfo);
|
||||
*termname = "builtin_ansi";
|
||||
return &ansi_terminfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// @param term $TERM value
|
||||
/// @param[out,allocated] termname decided builtin 'term' name
|
||||
/// @return [allocated] terminfo structure
|
||||
unibi_term *terminfo_from_builtin(const char *term, char **termname)
|
||||
static ssize_t unibi_find_ext_str(unibi_term *ut, const char *name)
|
||||
{
|
||||
unibi_term *ut = terminfo_builtin(term, termname);
|
||||
if (*termname == NULL) {
|
||||
*termname = xstrdup("builtin_?");
|
||||
size_t max = unibi_count_ext_str(ut);
|
||||
for (size_t i = 0; i < max; i++) {
|
||||
const char *n = unibi_get_ext_str_name(ut, i);
|
||||
if (n && 0 == strcmp(n, name)) {
|
||||
return (ssize_t)i;
|
||||
}
|
||||
}
|
||||
return ut;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool terminfo_from_unibilium(TerminfoEntry *ti, char *termname, Arena *arena)
|
||||
{
|
||||
unibi_term *ut = unibi_from_term(termname);
|
||||
if (!ut) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ti->bce = unibi_get_bool(ut, unibi_back_color_erase);
|
||||
ti->max_colors = unibi_get_num(ut, unibi_max_colors);
|
||||
ti->lines = unibi_get_num(ut, unibi_lines);
|
||||
ti->columns = unibi_get_num(ut, unibi_columns);
|
||||
|
||||
// Check for Tc or RGB
|
||||
ti->has_Tc_or_RGB = false;
|
||||
ti->Su = false;
|
||||
for (size_t i = 0; i < unibi_count_ext_bool(ut); i++) {
|
||||
const char *n = unibi_get_ext_bool_name(ut, i);
|
||||
if (n && (!strcmp(n, "Tc") || !strcmp(n, "RGB"))) {
|
||||
ti->has_Tc_or_RGB = true;
|
||||
} else if (n && !strcmp(n, "Su")) {
|
||||
ti->Su = true;
|
||||
}
|
||||
}
|
||||
|
||||
static const enum unibi_string uni_ids[] = {
|
||||
#define X(name) unibi_##name,
|
||||
XLIST_TERMINFO_BUILTIN
|
||||
#undef X
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(uni_ids); i++) {
|
||||
const char *val = unibi_get_str(ut, uni_ids[i]);
|
||||
ti->defs[i] = val ? arena_strdup(arena, val) : NULL;
|
||||
}
|
||||
|
||||
static const char *uni_ext[] = {
|
||||
#define X(informal_name, terminfo_name) #terminfo_name,
|
||||
XLIST_TERMINFO_EXT
|
||||
#undef X
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(uni_ext); i++) {
|
||||
ssize_t val = unibi_find_ext_str(ut, uni_ext[i]);
|
||||
if (val >= 0) {
|
||||
const char *data = unibi_get_ext_str(ut, (size_t)val);
|
||||
ti->defs[kTermExtOffset + i] = data ? arena_strdup(arena, data) : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
unibi_destroy(ut);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *fmt(bool val)
|
||||
{
|
||||
return val ? "true" : "false";
|
||||
}
|
||||
|
||||
/// Dumps termcap info to the messages area.
|
||||
/// Serves a similar purpose as Vim `:set termcap` (removed in Nvim).
|
||||
///
|
||||
/// @note adapted from unibilium unibi-dump.c
|
||||
/// @return allocated string
|
||||
String terminfo_info_msg(const unibi_term *ut, const char *termname)
|
||||
String terminfo_info_msg(const TerminfoEntry *ti, const char *termname)
|
||||
{
|
||||
StringBuilder data = KV_INITIAL_VALUE;
|
||||
|
||||
kv_printf(data, "&term: %s\n", termname);
|
||||
kv_printf(data, "Description: %s\n", unibi_get_name(ut));
|
||||
const char **a = unibi_get_aliases(ut);
|
||||
if (*a) {
|
||||
kv_printf(data, "Aliases: ");
|
||||
do {
|
||||
kv_printf(data, "%s%s\n", *a, a[1] ? " | " : "");
|
||||
a++;
|
||||
} while (*a);
|
||||
}
|
||||
kv_printf(data, "\n");
|
||||
|
||||
kv_printf(data, "Boolean capabilities:\n");
|
||||
for (enum unibi_boolean i = unibi_boolean_begin_ + 1;
|
||||
i < unibi_boolean_end_; i++) {
|
||||
kv_printf(data, " %-25s %-10s = %s\n", unibi_name_bool(i),
|
||||
unibi_short_name_bool(i),
|
||||
unibi_get_bool(ut, i) ? "true" : "false");
|
||||
}
|
||||
kv_printf(data, " back_color_erase: %s\n", fmt(ti->bce));
|
||||
kv_printf(data, " truecolor ('Tc' or 'RGB'): %s\n", fmt(ti->has_Tc_or_RGB));
|
||||
kv_printf(data, " extended underline ('Su'): %s\n", fmt(ti->Su));
|
||||
kv_printf(data, "\n");
|
||||
|
||||
kv_printf(data, "Numeric capabilities:\n");
|
||||
for (enum unibi_numeric i = unibi_numeric_begin_ + 1;
|
||||
i < unibi_numeric_end_; i++) {
|
||||
int n = unibi_get_num(ut, i); // -1 means "empty"
|
||||
kv_printf(data, " %-25s %-10s = %d\n", unibi_name_num(i),
|
||||
unibi_short_name_num(i), n);
|
||||
}
|
||||
kv_printf(data, "Numeric capabilities: (-1 for unknown)\n");
|
||||
kv_printf(data, " lines: %d\n", ti->lines);
|
||||
kv_printf(data, " columns: %d\n", ti->columns);
|
||||
kv_printf(data, " max_colors: %d\n", ti->columns);
|
||||
kv_printf(data, "\n");
|
||||
|
||||
kv_printf(data, "String capabilities:\n");
|
||||
for (enum unibi_string i = unibi_string_begin_ + 1;
|
||||
i < unibi_string_end_; i++) {
|
||||
const char *s = unibi_get_str(ut, i);
|
||||
|
||||
static const char *string_names[] = {
|
||||
#define X(name) #name,
|
||||
XLIST_TERMINFO_BUILTIN
|
||||
#undef X
|
||||
#define X(internal_name, terminfo_name) (#internal_name " (" #terminfo_name ")"),
|
||||
XLIST_TERMINFO_EXT
|
||||
#undef X
|
||||
};
|
||||
|
||||
for (size_t i = 0 + 1; i < ARRAY_SIZE(string_names); i++) {
|
||||
const char *s = ti->defs[i];
|
||||
if (s) {
|
||||
kv_printf(data, " %-25s %-10s = ", unibi_name_str(i),
|
||||
unibi_short_name_str(i));
|
||||
kv_printf(data, " %-31s = ", string_names[i]);
|
||||
// Most of these strings will contain escape sequences.
|
||||
kv_transstr(&data, s, false);
|
||||
kv_push(data, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (unibi_count_ext_bool(ut)) {
|
||||
kv_printf(data, "Extended boolean capabilities:\n");
|
||||
for (size_t i = 0; i < unibi_count_ext_bool(ut); i++) {
|
||||
kv_printf(data, " %-25s = %s\n",
|
||||
unibi_get_ext_bool_name(ut, i),
|
||||
unibi_get_ext_bool(ut, i) ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
if (unibi_count_ext_num(ut)) {
|
||||
kv_printf(data, "Extended numeric capabilities:\n");
|
||||
for (size_t i = 0; i < unibi_count_ext_num(ut); i++) {
|
||||
kv_printf(data, " %-25s = %d\n",
|
||||
unibi_get_ext_num_name(ut, i),
|
||||
unibi_get_ext_num(ut, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (unibi_count_ext_str(ut)) {
|
||||
kv_printf(data, "Extended string capabilities:\n");
|
||||
for (size_t i = 0; i < unibi_count_ext_str(ut); i++) {
|
||||
kv_printf(data, " %-25s = ", unibi_get_ext_str_name(ut, i));
|
||||
// NOTE: unibi_get_ext_str(ut, i) might be NULL, as termcap
|
||||
// might include junk data on mac os. kv_transstr will handle this.
|
||||
kv_transstr(&data, unibi_get_ext_str(ut, i), false);
|
||||
kv_push(data, '\n');
|
||||
}
|
||||
}
|
||||
kv_push(data, NUL);
|
||||
|
||||
return cbuf_as_string(data.items, data.size - 1);
|
||||
}
|
||||
|
||||
// The implementation of terminfo_fmt() is based on NetBSD libterminfo,
|
||||
// with full license reproduced below
|
||||
|
||||
// Copyright (c) 2009, 2011, 2013 The NetBSD Foundation, Inc.
|
||||
//
|
||||
// This code is derived from software contributed to The NetBSD Foundation
|
||||
// by Roy Marples.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// nvim modifications:
|
||||
// - use typesafe param args instead of va_args and piss
|
||||
// - caller provides the output buffer
|
||||
// - static variables are not preserved
|
||||
|
||||
static int push(long num, char *string, TPSTACK *stack)
|
||||
{
|
||||
if (stack->offset >= sizeof(stack->nums)) {
|
||||
return -1;
|
||||
}
|
||||
stack->nums[stack->offset] = num;
|
||||
stack->strings[stack->offset] = string;
|
||||
stack->offset++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pop(long *num, char **string, TPSTACK *stack)
|
||||
{
|
||||
if (stack->offset == 0) {
|
||||
if (num) {
|
||||
*num = 0;
|
||||
}
|
||||
if (string) {
|
||||
*string = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
stack->offset--;
|
||||
if (num) {
|
||||
*num = stack->nums[stack->offset];
|
||||
}
|
||||
if (string) {
|
||||
*string = stack->strings[stack->offset];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ochar(char **buf, const char *buf_end, int c)
|
||||
{
|
||||
if (c == 0) {
|
||||
c = 0200;
|
||||
}
|
||||
// Check we have space and a terminator
|
||||
if (buf_end - *buf < 2) {
|
||||
return 0;
|
||||
}
|
||||
*(*buf)++ = (char)c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool onum(char **buf, const char *buf_end, const char *fmt, int num, size_t len)
|
||||
{
|
||||
const size_t LONG_STR_MAX = 21;
|
||||
len = MAX(len, LONG_STR_MAX);
|
||||
|
||||
if (buf_end - *buf < (ssize_t)(len + 2)) {
|
||||
return 0;
|
||||
}
|
||||
int l = snprintf(*buf, len + 2, fmt, num);
|
||||
if (l == -1) {
|
||||
return 0;
|
||||
}
|
||||
*buf += l;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @return number of chars printed or 0 for any error
|
||||
size_t terminfo_fmt(char *buf_start, char *buf_end, const char *str, TPVAR params[9])
|
||||
{
|
||||
char c, fmt[64], *fp, *ostr;
|
||||
long val, val2;
|
||||
long dnums[26]; // dynamic variables a-z, not preserved
|
||||
long snums[26]; // static variables a-z, not preserved EITHER HAHA
|
||||
memset(dnums, 0, sizeof snums);
|
||||
memset(snums, 0, sizeof snums);
|
||||
|
||||
char *buf = buf_start;
|
||||
|
||||
size_t l, width, precision, olen;
|
||||
TPSTACK stack;
|
||||
unsigned done, dot, minus;
|
||||
|
||||
memset(&stack, 0, sizeof(stack));
|
||||
while ((c = *str++) != '\0') {
|
||||
if (c != '%' || (c = *str++) == '%') {
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
if (!ochar(&buf, buf_end, c)) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle formatting.
|
||||
fp = fmt;
|
||||
*fp++ = '%';
|
||||
done = dot = minus = 0;
|
||||
width = precision = 0;
|
||||
val = 0;
|
||||
while (done == 0 && (size_t)(fp - fmt) < sizeof(fmt)) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
case 's':
|
||||
*fp++ = c;
|
||||
done = 1;
|
||||
break;
|
||||
case 'd':
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'X':
|
||||
*fp++ = 'l';
|
||||
*fp++ = c;
|
||||
done = 1;
|
||||
break;
|
||||
case '#':
|
||||
case ' ':
|
||||
*fp++ = c;
|
||||
break;
|
||||
case '.':
|
||||
*fp++ = c;
|
||||
if (dot == 0) {
|
||||
dot = 1;
|
||||
width = (size_t)val;
|
||||
} else {
|
||||
done = 2;
|
||||
}
|
||||
val = 0;
|
||||
break;
|
||||
case ':':
|
||||
minus = 1;
|
||||
break;
|
||||
case '-':
|
||||
if (minus) {
|
||||
*fp++ = c;
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (isdigit((unsigned char)c)) {
|
||||
val = (val * 10) + (c - '0');
|
||||
if (val > 10000) {
|
||||
done = 2;
|
||||
} else {
|
||||
*fp++ = c;
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
if (done == 0) {
|
||||
c = *str++;
|
||||
}
|
||||
}
|
||||
if (done == 2) {
|
||||
// Found an error in the format
|
||||
fp = fmt + 1;
|
||||
*fp = *str;
|
||||
olen = 0;
|
||||
} else {
|
||||
if (dot == 0) {
|
||||
width = (size_t)val;
|
||||
} else {
|
||||
precision = (size_t)val;
|
||||
}
|
||||
olen = MAX(width, precision);
|
||||
}
|
||||
*fp++ = '\0';
|
||||
|
||||
// Handle commands
|
||||
switch (c) {
|
||||
case 'c':
|
||||
pop(&val, NULL, &stack);
|
||||
if (!ochar(&buf, buf_end, (unsigned char)val)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
pop(NULL, &ostr, &stack);
|
||||
if (ostr != NULL) {
|
||||
int r;
|
||||
|
||||
l = strlen(ostr);
|
||||
if (l < olen) {
|
||||
l = olen;
|
||||
}
|
||||
if ((size_t)(buf_end - buf) < (l + 1)) {
|
||||
return false;
|
||||
}
|
||||
r = snprintf(buf, l + 1,
|
||||
fmt, ostr);
|
||||
if (r != -1) {
|
||||
buf += (size_t)r;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
pop(NULL, &ostr, &stack);
|
||||
if (ostr == NULL) {
|
||||
l = 0;
|
||||
} else {
|
||||
l = strlen(ostr);
|
||||
}
|
||||
push((long)l, NULL, &stack);
|
||||
break;
|
||||
case 'd':
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'X':
|
||||
pop(&val, NULL, &stack);
|
||||
if (onum(&buf, buf_end, fmt, (int)val, olen) == 0) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if (*str < '1' || *str > '9') {
|
||||
break;
|
||||
}
|
||||
l = (size_t)(*str++ - '1');
|
||||
if (push(params[l].num, params[l].string, &stack)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
pop(&val, NULL, &stack);
|
||||
if (*str >= 'a' && *str <= 'z') {
|
||||
dnums[*str - 'a'] = val;
|
||||
} else if (*str >= 'A' && *str <= 'Z') {
|
||||
snums[*str - 'A'] = val;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
if (*str >= 'a' && *str <= 'z') {
|
||||
if (push(dnums[*str - 'a'], NULL, &stack)) {
|
||||
return 0;
|
||||
}
|
||||
} else if (*str >= 'A' && *str <= 'Z') {
|
||||
if (push(snums[*str - 'A'], NULL, &stack)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
params[0].num++;
|
||||
params[1].num++;
|
||||
break;
|
||||
case '\'':
|
||||
if (push((long)(unsigned char)(*str++), NULL, &stack)) {
|
||||
return 0;
|
||||
}
|
||||
while (*str != '\0' && *str != '\'') {
|
||||
str++;
|
||||
}
|
||||
if (*str == '\'') {
|
||||
str++;
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
val = 0;
|
||||
for (; isdigit((unsigned char)(*str)); str++) {
|
||||
val = (val * 10) + (*str - '0');
|
||||
}
|
||||
if (push(val, NULL, &stack)) {
|
||||
return 0;
|
||||
}
|
||||
while (*str != '\0' && *str != '}') {
|
||||
str++;
|
||||
}
|
||||
if (*str == '}') {
|
||||
str++;
|
||||
}
|
||||
break;
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case 'm':
|
||||
case 'A':
|
||||
case 'O':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case '=':
|
||||
case '<':
|
||||
case '>':
|
||||
pop(&val, NULL, &stack);
|
||||
pop(&val2, NULL, &stack);
|
||||
switch (c) {
|
||||
case '+':
|
||||
val = val + val2;
|
||||
break;
|
||||
case '-':
|
||||
val = val2 - val;
|
||||
break;
|
||||
case '*':
|
||||
val = val * val2;
|
||||
break;
|
||||
case '/':
|
||||
val = val ? val2 / val : 0;
|
||||
break;
|
||||
case 'm':
|
||||
val = val ? val2 % val : 0;
|
||||
break;
|
||||
case 'A':
|
||||
val = val && val2;
|
||||
break;
|
||||
case 'O':
|
||||
val = val || val2;
|
||||
break;
|
||||
case '&':
|
||||
val = val & val2;
|
||||
break;
|
||||
case '|':
|
||||
val = val | val2;
|
||||
break;
|
||||
case '^':
|
||||
val = val ^ val2;
|
||||
break;
|
||||
case '=':
|
||||
val = val == val2;
|
||||
break;
|
||||
case '<':
|
||||
val = val2 < val;
|
||||
break;
|
||||
case '>':
|
||||
val = val2 > val;
|
||||
break;
|
||||
}
|
||||
if (push(val, NULL, &stack)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case '!':
|
||||
case '~':
|
||||
pop(&val, NULL, &stack);
|
||||
switch (c) {
|
||||
case '!':
|
||||
val = !val;
|
||||
break;
|
||||
case '~':
|
||||
val = ~val;
|
||||
break;
|
||||
}
|
||||
if (push(val, NULL, &stack)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case '?': // if
|
||||
break;
|
||||
case 't': // then
|
||||
pop(&val, NULL, &stack);
|
||||
if (val == 0) {
|
||||
l = 0;
|
||||
for (; *str != '\0'; str++) {
|
||||
if (*str != '%') {
|
||||
continue;
|
||||
}
|
||||
str++;
|
||||
if (*str == '?') {
|
||||
l++;
|
||||
} else if (*str == ';') {
|
||||
if (l > 0) {
|
||||
l--;
|
||||
} else {
|
||||
str++;
|
||||
break;
|
||||
}
|
||||
} else if (*str == 'e' && l == 0) {
|
||||
str++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'e': // else
|
||||
l = 0;
|
||||
for (; *str != '\0'; str++) {
|
||||
if (*str != '%') {
|
||||
continue;
|
||||
}
|
||||
str++;
|
||||
if (*str == '?') {
|
||||
l++;
|
||||
} else if (*str == ';') {
|
||||
if (l > 0) {
|
||||
l--;
|
||||
} else {
|
||||
str++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ';': // fi
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (size_t)(buf - buf_start);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <unibilium.h> // IWYU pragma: keep
|
||||
|
||||
#include "nvim/api/private/defs.h" // IWYU pragma: keep
|
||||
#include "nvim/tui/terminfo_enum_defs.h"
|
||||
|
||||
typedef struct {
|
||||
bool bce;
|
||||
// these extended booleans indicate likely 24-color support
|
||||
bool has_Tc_or_RGB;
|
||||
bool Su;
|
||||
|
||||
int max_colors;
|
||||
int lines;
|
||||
int columns;
|
||||
const char *defs[kTermCount];
|
||||
} TerminfoEntry;
|
||||
|
||||
typedef struct {
|
||||
long num;
|
||||
char *string;
|
||||
} TPVAR;
|
||||
|
||||
#include "tui/terminfo.h.generated.h"
|
||||
|
||||
File diff suppressed because one or more lines are too long
54
src/nvim/tui/terminfo_enum_defs.h
Normal file
54
src/nvim/tui/terminfo_enum_defs.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// genenerated by src/gen/gen_terminfo.lua
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
kTerm_carriage_return,
|
||||
kTerm_change_scroll_region,
|
||||
kTerm_clear_screen,
|
||||
kTerm_clr_eol,
|
||||
kTerm_clr_eos,
|
||||
kTerm_cursor_address,
|
||||
kTerm_cursor_down,
|
||||
kTerm_cursor_invisible,
|
||||
kTerm_cursor_left,
|
||||
kTerm_cursor_home,
|
||||
kTerm_cursor_normal,
|
||||
kTerm_cursor_up,
|
||||
kTerm_cursor_right,
|
||||
kTerm_delete_line,
|
||||
kTerm_enter_bold_mode,
|
||||
kTerm_enter_ca_mode,
|
||||
kTerm_enter_italics_mode,
|
||||
kTerm_enter_reverse_mode,
|
||||
kTerm_enter_standout_mode,
|
||||
kTerm_enter_underline_mode,
|
||||
kTerm_erase_chars,
|
||||
kTerm_exit_attribute_mode,
|
||||
kTerm_exit_ca_mode,
|
||||
kTerm_from_status_line,
|
||||
kTerm_insert_line,
|
||||
kTerm_keypad_local,
|
||||
kTerm_keypad_xmit,
|
||||
kTerm_parm_delete_line,
|
||||
kTerm_parm_down_cursor,
|
||||
kTerm_parm_insert_line,
|
||||
kTerm_parm_left_cursor,
|
||||
kTerm_parm_right_cursor,
|
||||
kTerm_parm_up_cursor,
|
||||
kTerm_set_a_background,
|
||||
kTerm_set_a_foreground,
|
||||
kTerm_set_attributes,
|
||||
kTerm_set_lr_margin,
|
||||
kTerm_to_status_line,
|
||||
#define kTermExtOffset kTerm_reset_cursor_style
|
||||
kTerm_reset_cursor_style,
|
||||
kTerm_set_cursor_style,
|
||||
kTerm_enter_strikethrough_mode,
|
||||
kTerm_set_rgb_foreground,
|
||||
kTerm_set_rgb_background,
|
||||
kTerm_set_cursor_color,
|
||||
kTerm_reset_cursor_color,
|
||||
kTerm_set_underline_style,
|
||||
kTermCount, // sentinel
|
||||
} TerminfoDef;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4005,7 +4005,9 @@ describe('TUI client', function()
|
||||
screen_client:expect({ any = 'GUI Running: 0' })
|
||||
|
||||
if is_os('mac') then
|
||||
assert_log('uv_tty_set_mode failed: Unknown system error %-102', testlog)
|
||||
-- this might either be "Unknown system error %-102" or
|
||||
-- "inappropriate ioctl for device" depending on the phase of the moon
|
||||
assert_log('uv_tty_set_mode failed', testlog)
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -4037,7 +4039,7 @@ describe('TUI client', function()
|
||||
ffi.C.ui_call_set_title(title)
|
||||
]=])
|
||||
screen_client:expect_unchanged()
|
||||
assert_log('TUI: escape sequence for ext%.set_title too long', testlog)
|
||||
assert_log('set_title: title string too long!', testlog)
|
||||
eq(bufname, api.nvim_buf_get_var(0, 'term_title'))
|
||||
|
||||
-- Following escape sequences are not affected.
|
||||
|
||||
Reference in New Issue
Block a user