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.
Example: >
: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}
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:
>= 1 When the shada file is read or written.
>= 2 When a file is ":source"'ed.
>= 3 UI info, terminal capabilities
>= 5 Every searched tags file and include file.
>= 8 Files for which a group of autocommands is executed.
>= 9 Every executed autocommand.

View File

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

View File

@ -327,22 +327,26 @@ Ed-compatible mode:
":set noedcompatible" is ignored
":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
terminal capabilities. Instead Nvim treats the terminal as any other UI. For
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
checks. For debugging only; not reliable during startup. >
:echo &term
"builtin_x" means one of the |builtin-terms| was chosen, because the expected
terminfo file was not found on the system.
*termcap*
*termcap*
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
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.

View File

@ -32,6 +32,39 @@ The source files use extensions to hint about their purpose.
- `*.h.generated.h` - exported 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
--------------
@ -39,7 +72,7 @@ Following describes how Nvim processes input.
Consider a typical Vim-like editing session:
01. Vim dispays the welcome screen
01. Vim displays the welcome screen
02. User types: `:`
03. Vim enters command-line mode
04. User types: `edit README.txt<CR>`

View File

@ -4906,15 +4906,14 @@ showoptions (
vimoption_T **items = xmalloc(sizeof(vimoption_T *) * PARAM_COUNT);
/* Highlight title */
if (all == 2)
MSG_PUTS_TITLE(_("\n--- Terminal codes ---"));
else if (opt_flags & OPT_GLOBAL)
// Highlight title
if (opt_flags & OPT_GLOBAL) {
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 ---"));
else
} else {
MSG_PUTS_TITLE(_("\n--- Options ---"));
}
/*
* do the loop two times:

View File

@ -9,7 +9,10 @@
#include <unibilium.h>
#include "nvim/log.h"
#include "nvim/globals.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option.h"
#include "nvim/tui/terminfo.h"
#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);
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);
data->stop = false;
// allow the main thread to continue, we are ready to start handling UI
// callbacks
// Allow main thread to continue, we are ready to handle UI callbacks.
CONTINUE(bridge);
loop_schedule_deferred(&main_loop,
event_create(show_termcap_event, 1, data->ut));
while (!data->stop) {
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);
}
/// 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
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();
}
// Suspend the main thread until CONTINUE is called by the UI thread.
while (!rv->ready) {
uv_cond_wait(&rv->cond, &rv->mutex);
}
@ -149,7 +150,7 @@ static void ui_bridge_suspend(UI *b)
uv_mutex_lock(&data->mutex);
UI_BRIDGE_CALL(b, suspend, 1, b);
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) {
uv_cond_wait(&data->cond, &data->mutex);
}