Merge #7653 from justinmk/tui-termcap

This commit is contained in:
Justin M. Keyes 2017-12-05 02:42:10 +01:00 committed by GitHub
commit 67848c0b91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 271 additions and 64 deletions

View File

@ -8889,11 +8889,6 @@ This does NOT work: >
value and the global value are changed. value and the global value are changed.
Example: > Example: >
:let &path = &path . ',/usr/local/include' :let &path = &path . ',/usr/local/include'
< This also works for terminal codes in the form t_xx.
But only for alphanumerical names. Example: >
:let &t_k1 = "\<Esc>[234;"
< When the code does not exist yet it will be created as
a terminal key code, there is no error.
:let &{option-name} .= {expr1} :let &{option-name} .= {expr1}
For a string option: Append {expr1} to the value. For a string option: Append {expr1} to the value.

View File

@ -6424,6 +6424,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Currently, these messages are given: Currently, these messages are given:
>= 1 When the shada file is read or written. >= 1 When the shada file is read or written.
>= 2 When a file is ":source"'ed. >= 2 When a file is ":source"'ed.
>= 3 UI info, terminal capabilities
>= 5 Every searched tags file and include file. >= 5 Every searched tags file and include file.
>= 8 Files for which a group of autocommands is executed. >= 8 Files for which a group of autocommands is executed.
>= 9 Every executed autocommand. >= 9 Every executed autocommand.

View File

@ -249,14 +249,14 @@ argument.
for reading or writing a ShaDa file. Can be used to find for reading or writing a ShaDa file. Can be used to find
out what is happening upon startup and exit. out what is happening upon startup and exit.
Example: > Example: >
vim -V8 foobar nvim -V8
-V[N]{filename} -V[N]{filename}
Like -V and set 'verbosefile' to {filename}. The result is Like -V and set 'verbosefile' to {filename}. Messages are not
that messages are not displayed but written to the file displayed; instead they are written to the file {filename}.
{filename}. {filename} must not start with a digit. {filename} must not start with a digit.
Example: > Example: >
vim -V20vimlog foobar nvim -V20vimlog
< <
*-D* *-D*
-D Debugging. Go to debugging mode when executing the first -D Debugging. Go to debugging mode when executing the first

View File

@ -327,22 +327,26 @@ Ed-compatible mode:
":set noedcompatible" is ignored ":set noedcompatible" is ignored
":set edcompatible" is an error ":set edcompatible" is an error
*t_xx* *:set-termcap* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI* *t_xx* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI*
Nvim does not have special `t_XX` options nor <t_XX> keycodes to configure Nvim does not have special `t_XX` options nor <t_XX> keycodes to configure
terminal capabilities. Instead Nvim treats the terminal as any other UI. For terminal capabilities. Instead Nvim treats the terminal as any other UI. For
example, 'guicursor' sets the terminal cursor style if possible. example, 'guicursor' sets the terminal cursor style if possible.
*'term'* *E529* *E530* *E531* *:set-termcap*
Start Nvim with 'verbose' level 3 to see the terminal capabilities. >
nvim -V3
<
*'term'* *E529* *E530* *E531*
'term' reflects the terminal type derived from |$TERM| and other environment 'term' reflects the terminal type derived from |$TERM| and other environment
checks. For debugging only; not reliable during startup. > checks. For debugging only; not reliable during startup. >
:echo &term :echo &term
"builtin_x" means one of the |builtin-terms| was chosen, because the expected "builtin_x" means one of the |builtin-terms| was chosen, because the expected
terminfo file was not found on the system. terminfo file was not found on the system.
*termcap* *termcap*
Nvim never uses the termcap database, only |terminfo| and |builtin-terms|. Nvim never uses the termcap database, only |terminfo| and |builtin-terms|.
*xterm-8bit* *xterm-8-bit* *xterm-8bit* *xterm-8-bit*
Xterm can be run in a mode where it uses true 8-bit CSI. Supporting this Xterm can be run in a mode where it uses true 8-bit CSI. Supporting this
requires autodetection of whether the terminal is in UTF-8 mode or non-UTF-8 requires autodetection of whether the terminal is in UTF-8 mode or non-UTF-8
mode, as the 8-bit CSI character has to be written differently in each case. mode, as the 8-bit CSI character has to be written differently in each case.

View File

@ -32,6 +32,39 @@ The source files use extensions to hint about their purpose.
- `*.h.generated.h` - exported functions declarations. - `*.h.generated.h` - exported functions declarations.
- `*.c.generated.h` - static functions declarations. - `*.c.generated.h` - static functions declarations.
TUI debugging
-------------
### TUI troubleshoot
Nvim logs its internal terminfo state at 'verbose' level 3. This makes it
possible to see exactly what terminfo values Nvim is using on any system.
nvim -V3log
### TUI trace
The ancient `script` command is still the "state of the art" for tracing
terminal behavior. The libvterm `vterm-dump` utility formats the result for
human-readability.
Record a Nvim terminal session and format it with `vterm-dump`:
script foo
./build/bin/nvim -u NONE
# Exit the script session with CTRL-d
# Use `vterm-dump` utility to format the result.
./.deps/usr/bin/vterm-dump foo > bar
Then you can compare `bar` with another session, to debug TUI behavior.
### Terminal reference
- `man terminfo`
- http://bazaar.launchpad.net/~libvterm/libvterm/trunk/view/head:/doc/seqs.txt
- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
Nvim lifecycle Nvim lifecycle
-------------- --------------
@ -39,7 +72,7 @@ Following describes how Nvim processes input.
Consider a typical Vim-like editing session: Consider a typical Vim-like editing session:
01. Vim dispays the welcome screen 01. Vim displays the welcome screen
02. User types: `:` 02. User types: `:`
03. Vim enters command-line mode 03. Vim enters command-line mode
04. User types: `edit README.txt<CR>` 04. User types: `edit README.txt<CR>`

View File

@ -1237,31 +1237,30 @@ void msg_make(char_u *arg)
} }
} }
/* /// Output the string 'str' upto a NUL character.
* Output the string 'str' upto a NUL character. /// Return the number of characters it takes on the screen.
* Return the number of characters it takes on the screen. ///
* /// If K_SPECIAL is encountered, then it is taken in conjunction with the
* If K_SPECIAL is encountered, then it is taken in conjunction with the /// following character and shown as <F1>, <S-Up> etc. Any other character
* following character and shown as <F1>, <S-Up> etc. Any other character /// which is not printable shown in <> form.
* which is not printable shown in <> form. /// If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>.
* If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>. /// If a character is displayed in one of these special ways, is also
* If a character is displayed in one of these special ways, is also /// highlighted (its highlight name is '8' in the p_hl variable).
* highlighted (its highlight name is '8' in the p_hl variable). /// Otherwise characters are not highlighted.
* Otherwise characters are not highlighted. /// This function is used to show mappings, where we want to see how to type
* This function is used to show mappings, where we want to see how to type /// the character/string -- webb
* the character/string -- webb int msg_outtrans_special(
*/ const char_u *strstart,
int int from ///< true for LHS of a mapping
msg_outtrans_special (
char_u *strstart,
int from /* TRUE for lhs of a mapping */
) )
{ {
char_u *str = strstart; if (strstart == NULL) {
return 0; // Do nothing.
}
const char_u *str = strstart;
int retval = 0; int retval = 0;
int attr; int attr = hl_attr(HLF_8);
attr = hl_attr(HLF_8);
while (*str != NUL) { while (*str != NUL) {
const char *string; const char *string;
// Leading and trailing spaces need to be displayed in <> form. // Leading and trailing spaces need to be displayed in <> form.
@ -1307,7 +1306,7 @@ char *str2special_save(const char *const str, const bool replace_spaces,
return (char *)ga.ga_data; return (char *)ga.ga_data;
} }
/// Convert character, replacing key one key code with printable representation /// Convert character, replacing key with printable representation.
/// ///
/// @param[in,out] sp String to convert. Is advanced to the next key code. /// @param[in,out] sp String to convert. Is advanced to the next key code.
/// @param[in] replace_spaces Convert spaces into <Space>, normally used for /// @param[in] replace_spaces Convert spaces into <Space>, normally used for
@ -1392,7 +1391,7 @@ void str2specialbuf(const char *sp, char *buf, size_t len)
while (*sp) { while (*sp) {
const char *s = str2special(&sp, false, false); const char *s = str2special(&sp, false, false);
const size_t s_len = strlen(s); const size_t s_len = strlen(s);
if (s_len <= len) { if (len <= s_len) {
break; break;
} }
memcpy(buf, s, s_len); memcpy(buf, s, s_len);

View File

@ -4906,15 +4906,14 @@ showoptions (
vimoption_T **items = xmalloc(sizeof(vimoption_T *) * PARAM_COUNT); vimoption_T **items = xmalloc(sizeof(vimoption_T *) * PARAM_COUNT);
/* Highlight title */ // Highlight title
if (all == 2) if (opt_flags & OPT_GLOBAL) {
MSG_PUTS_TITLE(_("\n--- Terminal codes ---"));
else if (opt_flags & OPT_GLOBAL)
MSG_PUTS_TITLE(_("\n--- Global option values ---")); MSG_PUTS_TITLE(_("\n--- Global option values ---"));
else if (opt_flags & OPT_LOCAL) } else if (opt_flags & OPT_LOCAL) {
MSG_PUTS_TITLE(_("\n--- Local option values ---")); MSG_PUTS_TITLE(_("\n--- Local option values ---"));
else } else {
MSG_PUTS_TITLE(_("\n--- Options ---")); MSG_PUTS_TITLE(_("\n--- Options ---"));
}
/* /*
* do the loop two times: * do the loop two times:

View File

@ -9,7 +9,10 @@
#include <unibilium.h> #include <unibilium.h>
#include "nvim/log.h" #include "nvim/log.h"
#include "nvim/globals.h"
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option.h"
#include "nvim/tui/terminfo.h" #include "nvim/tui/terminfo.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
@ -166,3 +169,87 @@ unibi_term *terminfo_from_builtin(const char *term, char **termname)
unibi_set_bool(ut, unibi_back_color_erase, false); unibi_set_bool(ut, unibi_back_color_erase, false);
return ut; return ut;
} }
/// 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
void terminfo_info_msg(const unibi_term *const ut)
{
if (exiting) {
return;
}
msg_puts_title("\n\n--- Terminal info --- {{{\n");
char *term;
get_tty_option("term", &term);
msg_printf_attr(0, "&term: %s\n", term);
msg_printf_attr(0, "Description: %s\n", unibi_get_name(ut));
const char **a = unibi_get_aliases(ut);
if (*a) {
msg_puts("Aliases: ");
do {
msg_printf_attr(0, "%s%s\n", *a, a[1] ? " | " : "");
a++;
} while (*a);
}
msg_puts("Boolean capabilities:\n");
for (enum unibi_boolean i = unibi_boolean_begin_ + 1;
i < unibi_boolean_end_; i++) {
msg_printf_attr(0, " %-25s %-10s = %s\n", unibi_name_bool(i),
unibi_short_name_bool(i),
unibi_get_bool(ut, i) ? "true" : "false");
}
msg_puts("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"
msg_printf_attr(0, " %-25s %-10s = %hd\n", unibi_name_num(i),
unibi_short_name_num(i), n);
}
msg_puts("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);
if (s) {
msg_printf_attr(0, " %-25s %-10s = ", unibi_name_str(i),
unibi_short_name_str(i));
// Most of these strings will contain escape sequences.
msg_outtrans_special((char_u *)s, false);
msg_putchar('\n');
}
}
if (unibi_count_ext_bool(ut)) {
msg_puts("Extended boolean capabilities:\n");
for (size_t i = 0; i < unibi_count_ext_bool(ut); i++) {
msg_printf_attr(0, " %-25s = %s\n",
unibi_get_ext_bool_name(ut, i),
unibi_get_ext_bool(ut, i) ? "true" : "false");
}
}
if (unibi_count_ext_num(ut)) {
msg_puts("Extended numeric capabilities:\n");
for (size_t i = 0; i < unibi_count_ext_num(ut); i++) {
msg_printf_attr(0, " %-25s = %hd\n",
unibi_get_ext_num_name(ut, i),
unibi_get_ext_num(ut, i));
}
}
if (unibi_count_ext_str(ut)) {
msg_puts("Extended string capabilities:\n");
for (size_t i = 0; i < unibi_count_ext_str(ut); i++) {
msg_printf_attr(0, " %-25s = ", unibi_get_ext_str_name(ut, i));
msg_outtrans_special((char_u *)unibi_get_ext_str(ut, i), false);
msg_putchar('\n');
}
}
msg_puts("}}}\n");
xfree(term);
}

View File

@ -354,10 +354,12 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
tui_terminal_start(ui); tui_terminal_start(ui);
data->stop = false; data->stop = false;
// allow the main thread to continue, we are ready to start handling UI // Allow main thread to continue, we are ready to handle UI callbacks.
// callbacks
CONTINUE(bridge); CONTINUE(bridge);
loop_schedule_deferred(&main_loop,
event_create(show_termcap_event, 1, data->ut));
while (!data->stop) { while (!data->stop) {
loop_poll_events(&tui_loop, -1); // tui_loop.events is never processed loop_poll_events(&tui_loop, -1); // tui_loop.events is never processed
} }
@ -1061,6 +1063,24 @@ static void tui_flush(UI *ui)
flush_buf(ui, true); flush_buf(ui, true);
} }
/// Dumps termcap info to the messages area, if 'verbose' >= 3.
static void show_termcap_event(void **argv)
{
if (p_verbose < 3) {
return;
}
const unibi_term *const ut = argv[0];
if (!ut) {
abort();
}
verbose_enter();
// XXX: (future) if unibi_term is modified (e.g. after a terminal
// query-response) this is a race condition.
terminfo_info_msg(ut);
verbose_leave();
verbose_stop(); // flush now
}
#ifdef UNIX #ifdef UNIX
static void suspend_event(void **argv) static void suspend_event(void **argv)
{ {
@ -1577,11 +1597,13 @@ static void augment_terminfo(TUIData *data, const char *term,
|| konsole // per commentary in VT102Emulation.cpp || konsole // per commentary in VT102Emulation.cpp
|| teraterm // per TeraTerm "Supported Control Functions" doco || teraterm // per TeraTerm "Supported Control Functions" doco
|| rxvt) { // per command.C || rxvt) { // per command.C
data->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut,
"ext.resize_screen",
"\x1b[8;%p1%d;%p2%dt"); "\x1b[8;%p1%d;%p2%dt");
} }
if (putty || xterm || rxvt) { if (putty || xterm || rxvt) {
data->unibi_ext.reset_scroll_region = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.reset_scroll_region = (int)unibi_add_ext_str(ut,
"ext.reset_scroll_region",
"\x1b[r"); "\x1b[r");
} }
@ -1639,21 +1661,29 @@ static void augment_terminfo(TUIData *data, const char *term,
/// Terminals usually ignore unrecognized private modes, and there is no /// Terminals usually ignore unrecognized private modes, and there is no
/// known ambiguity with these. So we just set them unconditionally. /// known ambiguity with these. So we just set them unconditionally.
data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str(ut,
"ext.enable_lr_margin",
"\x1b[?69h"); "\x1b[?69h");
data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(ut,
"ext.disable_lr_margin",
"\x1b[?69l"); "\x1b[?69l");
data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut,
"ext.enable_bpaste",
"\x1b[?2004h"); "\x1b[?2004h");
data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut,
"ext.disable_bpaste",
"\x1b[?2004l"); "\x1b[?2004l");
data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut,
"ext.enable_focus",
rxvt ? "\x1b]777;focus;on\x7" : "\x1b[?1004h"); rxvt ? "\x1b]777;focus;on\x7" : "\x1b[?1004h");
data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut,
"ext.disable_focus",
rxvt ? "\x1b]777;focus;off\x7" : "\x1b[?1004l"); rxvt ? "\x1b]777;focus;off\x7" : "\x1b[?1004l");
data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut,
"ext.enable_mouse",
"\x1b[?1002h\x1b[?1006h"); "\x1b[?1002h\x1b[?1006h");
data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, NULL, data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut,
"ext.disable_mouse",
"\x1b[?1002l\x1b[?1006l"); "\x1b[?1002l\x1b[?1006l");
} }

View File

@ -82,6 +82,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
abort(); abort();
} }
// Suspend the main thread until CONTINUE is called by the UI thread.
while (!rv->ready) { while (!rv->ready) {
uv_cond_wait(&rv->cond, &rv->mutex); uv_cond_wait(&rv->cond, &rv->mutex);
} }
@ -149,7 +150,7 @@ static void ui_bridge_suspend(UI *b)
uv_mutex_lock(&data->mutex); uv_mutex_lock(&data->mutex);
UI_BRIDGE_CALL(b, suspend, 1, b); UI_BRIDGE_CALL(b, suspend, 1, b);
data->ready = false; data->ready = false;
// suspend the main thread until CONTINUE is called by the UI thread // Suspend the main thread until CONTINUE is called by the UI thread.
while (!data->ready) { while (!data->ready) {
uv_cond_wait(&data->cond, &data->mutex); uv_cond_wait(&data->cond, &data->mutex);
} }

View File

@ -261,6 +261,7 @@ local function retry(max, max_ms, fn)
if status then if status then
return result return result
end end
luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()).
if (max and tries >= max) or (luv.now() - start_time > timeout) then if (max and tries >= max) or (luv.now() - start_time > timeout) then
if type(result) == "string" then if type(result) == "string" then
result = "\nretry() attempts: "..tostring(tries).."\n"..result result = "\nretry() attempts: "..tostring(tries).."\n"..result
@ -333,8 +334,8 @@ local function feed_command(...)
end end
-- Dedent the given text and write it to the file name. -- Dedent the given text and write it to the file name.
local function write_file(name, text, dont_dedent) local function write_file(name, text, no_dedent, append)
local file = io.open(name, 'w') local file = io.open(name, (append and 'a' or 'w'))
if type(text) == 'table' then if type(text) == 'table' then
-- Byte blob -- Byte blob
local bytes = text local bytes = text
@ -342,7 +343,7 @@ local function write_file(name, text, dont_dedent)
for _, char in ipairs(bytes) do for _, char in ipairs(bytes) do
text = ('%s%c'):format(text, char) text = ('%s%c'):format(text, char)
end end
elseif not dont_dedent then elseif not no_dedent then
text = dedent(text) text = dedent(text)
end end
file:write(text) file:write(text)

View File

@ -4,6 +4,7 @@ local global_helpers = require('test.helpers')
local uname = global_helpers.uname local uname = global_helpers.uname
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers') local thelpers = require('test.functional.terminal.helpers')
local eq = helpers.eq
local feed_data = thelpers.feed_data local feed_data = thelpers.feed_data
local feed_command = helpers.feed_command local feed_command = helpers.feed_command
local clear = helpers.clear local clear = helpers.clear
@ -11,6 +12,8 @@ local nvim_dir = helpers.nvim_dir
local retry = helpers.retry local retry = helpers.retry
local nvim_prog = helpers.nvim_prog local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
if helpers.pending_win32(pending) then return end if helpers.pending_win32(pending) then return end
@ -21,9 +24,6 @@ describe('tui', function()
clear() clear()
screen = thelpers.screen_setup(0, '["'..nvim_prog screen = thelpers.screen_setup(0, '["'..nvim_prog
..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler undodir=. directory=. viewdir=. backupdir=."]') ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler undodir=. directory=. viewdir=. backupdir=."]')
-- right now pasting can be really slow in the TUI, especially in ASAN.
-- this will be fixed later but for now we require a high timeout.
screen.timeout = 60000
screen:expect([[ screen:expect([[
{1: } | {1: } |
{4:~ }| {4:~ }|
@ -125,6 +125,9 @@ describe('tui', function()
end) end)
it('automatically sends <Paste> for bracketed paste sequences', function() it('automatically sends <Paste> for bracketed paste sequences', function()
-- Pasting can be really slow in the TUI, specially in ASAN.
-- This will be fixed later but for now we require a high timeout.
screen.timeout = 60000
feed_data('i\027[200~') feed_data('i\027[200~')
screen:expect([[ screen:expect([[
{1: } | {1: } |
@ -158,6 +161,8 @@ describe('tui', function()
end) end)
it('can handle arbitrarily long bursts of input', function() it('can handle arbitrarily long bursts of input', function()
-- Need extra time for this test, specially in ASAN.
screen.timeout = 60000
feed_command('set ruler') feed_command('set ruler')
local t = {} local t = {}
for i = 1, 3000 do for i = 1, 3000 do
@ -639,6 +644,7 @@ end)
describe("tui 'term' option", function() describe("tui 'term' option", function()
local screen local screen
local is_bsd = not not string.find(string.lower(uname()), 'bsd') local is_bsd = not not string.find(string.lower(uname()), 'bsd')
local is_macos = not not string.find(string.lower(uname()), 'darwin')
local function assert_term(term_envvar, term_expected) local function assert_term(term_envvar, term_expected)
clear() clear()
@ -664,11 +670,62 @@ describe("tui 'term' option", function()
end) end)
it('gets system-provided term if $TERM is valid', function() it('gets system-provided term if $TERM is valid', function()
if is_bsd then -- BSD lacks terminfo, we always use builtin there. if is_bsd then -- BSD lacks terminfo, builtin is always used.
assert_term("xterm", "builtin_xterm") assert_term("xterm", "builtin_xterm")
elseif is_macos then
local status, _ = pcall(assert_term, "xterm", "xterm")
if not status then
pending("macOS: unibilium could not find terminfo", function() end)
end
else else
assert_term("xterm", "xterm") assert_term("xterm", "xterm")
end end
end) end)
end) end)
-- These tests require `thelpers` because --headless/--embed
-- does not initialize the TUI.
describe("tui", function()
local screen
local logfile = 'Xtest_tui_verbose_log'
after_each(function()
os.remove(logfile)
end)
-- Runs (child) `nvim` in a TTY (:terminal), to start the builtin TUI.
local function nvim_tui(extra_args)
clear()
-- This is ugly because :term/termopen() forces TERM=xterm-256color.
-- TODO: Revisit this after jobstart/termopen accept `env` dict.
local cmd = string.format(
[=[['sh', '-c', 'LANG=C %s -u NONE -i NONE %s --cmd "%s"']]=],
nvim_prog,
extra_args or "",
nvim_set)
screen = thelpers.screen_setup(0, cmd)
end
it('-V3log logs terminfo values', function()
nvim_tui('-V3'..logfile)
-- Wait for TUI to start.
feed_data('Gitext')
screen:expect([[
text{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
{4:~ }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]])
retry(nil, 3000, function() -- Wait for log file to be flushed.
local log = read_file('Xtest_tui_verbose_log') or ''
eq('--- Terminal info --- {{{\n', string.match(log, '--- Terminal.-\n'))
ok(#log > 50)
end)
end)
end)