mirror of
https://github.com/neovim/neovim.git
synced 2026-08-27 01:21:48 +00:00
Merge pull request #35952 from bfredl/neocurses
perf(tui): faster implementation of terminfo
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