tui: dump termcap info if -V3 ('verbose' >= 3)

Get terminal debugging info by starting Nvim with 'verbose' level 3:

    nvim -V3log

This is like Vim's `:set termcap`, which was removed in Nvim (and would
be very awkward to restore because of the decoupled UI).
This commit is contained in:
Justin M. Keyes
2017-11-27 00:35:09 +01:00
parent a494c99918
commit 3aa24042a8
9 changed files with 161 additions and 24 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

@@ -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,21 @@ 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();
}
// XXX: (future) if unibi_term is modified (e.g. after a terminal
// query-response) this is a race condition.
terminfo_info_msg(ut);
}
#ifdef UNIX #ifdef UNIX
static void suspend_event(void **argv) static void suspend_event(void **argv)
{ {

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);
} }