feat(tui): ghostty builtin terminfo #36963

Problem:
The builtin terminfo defs don't include xterm-ghostty, so features like
`kTerm_set_underline_style` are missing when building without unibilium.

Solution:
- Add ghostty to `gen_terminfo.lua`.
  - Note: The ncurses defs are somewhat different than what ghostty ships.
- Special-case ghostty in `terminfo_from_builtin`.
This commit is contained in:
Justin M. Keyes
2025-12-15 02:07:51 -05:00
committed by GitHub
parent 2700f6642a
commit 981ea41abb
4 changed files with 157 additions and 8 deletions

View File

@@ -61,11 +61,13 @@ unlike most other environment variables.
>
For this terminal Set $TERM to |builtin-terms|
-------------------------------------------------------------------------
anything libvte-based vte, vte-256color Y
(e.g. GNOME Terminal) (aliases: gnome, gnome-256color)
ansi (unknown) Y
Ghostty ghostty, xterm-ghostty Y
iTerm (original) iterm, iTerm.app N
iTerm2 (new capabilities) iterm2, iTerm2.app Y
Konsole konsole-256color N
libvte-based vte, vte-256color Y
(e.g. GNOME Terminal) (aliases: gnome, gnome-256color)
Linux virtual terminal linux, linux-256color Y
PuTTY putty, putty-256color Y
rxvt rxvt, rxvt-256color Y
@@ -76,22 +78,26 @@ unlike most other environment variables.
Windows/ConEmu conemu Y
Windows/Cygwin-built Nvim cygwin Y
Windows/Interix interix Y
Windows/VTP console vtpcon Y
Windows/legacy console win32con Y
Windows/VTP console vtpcon Y
xterm or compatible xterm, xterm-256color Y
<
*builtin-terms* *builtin_terms*
If a |terminfo| database is not available or there is no entry for the current
terminal, Nvim will map |$TERM| to a builtin entry according to the above
table, or "ansi" if there is no match. For example "TERM=putty-256color" will
be mapped to the builtin "putty" entry. See also |tui-colors|.
Nvim will map |$TERM| to a builtin entry according to the above table if:
- a |terminfo| database is not available on the system
- no terminfo entry found for the current detected terminal
- Nvim was built without terminfo support (`has('terminfo')==0`)
The builtin terminfo is not combined with any external terminfo database, nor
can it be used in preference to one. You can thus entirely override any
omissions or out-of-date information in the builtin terminfo database by
supplying an external one with entries for the terminal type.
For example "TERM=putty-256color" will be mapped to the builtin "putty" entry.
See also |tui-colors|.
Settings depending on terminal *term-dependent-settings*
If you want to set terminal-dependent options or mappings, you can do this in

View File

@@ -20,6 +20,7 @@ local target_enum = 'src/nvim/tui/terminfo_enum_defs.h'
local entries = {
{ 'ansi', 'ansi_terminfo' },
{ 'ghostty', 'ghostty_terminfo' }, -- Note: ncurses defs do not exactly match what ghostty ships.
{ 'interix', 'interix_8colour_terminfo' },
{ 'iterm2', 'iterm_256colour_terminfo' },
{ 'linux', 'linux_16colour_terminfo' },

View File

@@ -70,7 +70,10 @@ bool terminfo_is_bsd_console(const char *term)
/// @return [allocated] terminfo structure
const TerminfoEntry *terminfo_from_builtin(const char *term, char **termname)
{
if (terminfo_is_term_family(term, "xterm")) {
if (strequal(term, "ghostty") || strequal(term, "xterm-ghostty")) {
*termname = "ghostty";
return &ghostty_terminfo;
} else if (terminfo_is_term_family(term, "xterm")) {
*termname = "xterm";
return &xterm_256colour_terminfo;
} else if (terminfo_is_term_family(term, "screen")) {

View File

@@ -82,6 +82,145 @@ static const TerminfoEntry ansi_terminfo = {
},
};
static const TerminfoEntry ghostty_terminfo = {
.bce = true,
.has_Tc_or_RGB = false,
.Su = false,
.max_colors = 0x100,
.lines = 24,
.columns = 80,
.defs = {
[kTerm_carriage_return] = "\r",
[kTerm_change_scroll_region] = "\033[%i%p1%d;%p2%dr",
[kTerm_clear_screen] = "\033[H\033[2J",
[kTerm_clr_eol] = "\033[K",
[kTerm_clr_eos] = "\033[J",
[kTerm_cursor_address] = "\033[%i%p1%d;%p2%dH",
[kTerm_cursor_down] = "\n",
[kTerm_cursor_invisible] = "\033[?25l",
[kTerm_cursor_left] = "\b",
[kTerm_cursor_home] = "\033[H",
[kTerm_cursor_normal] = "\033[?12l\033[?25h",
[kTerm_cursor_up] = "\033[A",
[kTerm_cursor_right] = "\033[C",
[kTerm_delete_line] = "\033[M",
[kTerm_enter_bold_mode] = "\033[1m",
[kTerm_enter_ca_mode] = "\033[?1049h",
[kTerm_enter_italics_mode] = "\033[3m",
[kTerm_enter_reverse_mode] = "\033[7m",
[kTerm_enter_standout_mode] = "\033[7m",
[kTerm_enter_underline_mode] = "\033[4m",
[kTerm_erase_chars] = "\033[%p1%dX",
[kTerm_exit_attribute_mode] = "\033(B\033[m",
[kTerm_exit_ca_mode] = "\033[?1049l",
[kTerm_from_status_line] = "\a",
[kTerm_insert_line] = "\033[L",
[kTerm_keypad_local] = "\033[?1l\033>",
[kTerm_keypad_xmit] = "\033[?1h\033=",
[kTerm_parm_delete_line] = "\033[%p1%dM",
[kTerm_parm_down_cursor] = "\033[%p1%dB",
[kTerm_parm_insert_line] = "\033[%p1%dL",
[kTerm_parm_left_cursor] = "\033[%p1%dD",
[kTerm_parm_right_cursor] = "\033[%p1%dC",
[kTerm_parm_up_cursor] = "\033[%p1%dA",
[kTerm_set_a_background] = "\033[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
[kTerm_set_a_foreground] = "\033[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
[kTerm_set_attributes] = "%?%p9%t\033(0%e\033(B%;\033[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p5%t;2%;%?%p7%t;8%;m",
[kTerm_set_lr_margin] = "\033[?69h\033[%i%p1%d;%p2%ds",
[kTerm_to_status_line] = "\033]2;",
[kTerm_reset_cursor_style] = "\033[2 q",
[kTerm_set_cursor_style] = "\033[%p1%d q",
[kTerm_enter_strikethrough_mode] = "\033[9m",
[kTerm_set_rgb_foreground] = NULL,
[kTerm_set_rgb_background] = NULL,
[kTerm_set_cursor_color] = NULL,
[kTerm_reset_cursor_color] = NULL,
[kTerm_set_underline_style] = "\033[4\072%p1%dm",
},
.keys = {
[kTermKey_backspace] = {"\177", NULL},
[kTermKey_beg] = {NULL, NULL},
[kTermKey_btab] = {"\033[Z", NULL},
[kTermKey_clear] = {NULL, NULL},
[kTermKey_dc] = {"\033[3~", "\033[3;2~"},
[kTermKey_end] = {"\033OF", "\033[1;2F"},
[kTermKey_find] = {NULL, NULL},
[kTermKey_home] = {"\033OH", "\033[1;2H"},
[kTermKey_ic] = {"\033[2~", "\033[2;2~"},
[kTermKey_npage] = {"\033[6~", NULL},
[kTermKey_ppage] = {"\033[5~", NULL},
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
[0] = "\033OP",
[1] = "\033OQ",
[2] = "\033OR",
[3] = "\033OS",
[4] = "\033[15~",
[5] = "\033[17~",
[6] = "\033[18~",
[7] = "\033[19~",
[8] = "\033[20~",
[9] = "\033[21~",
[10] = "\033[23~",
[11] = "\033[24~",
[12] = "\033[1;2P",
[13] = "\033[1;2Q",
[14] = "\033[1;2R",
[15] = "\033[1;2S",
[16] = "\033[15;2~",
[17] = "\033[17;2~",
[18] = "\033[18;2~",
[19] = "\033[19;2~",
[20] = "\033[20;2~",
[21] = "\033[21;2~",
[22] = "\033[23;2~",
[23] = "\033[24;2~",
[24] = "\033[1;5P",
[25] = "\033[1;5Q",
[26] = "\033[1;5R",
[27] = "\033[1;5S",
[28] = "\033[15;5~",
[29] = "\033[17;5~",
[30] = "\033[18;5~",
[31] = "\033[19;5~",
[32] = "\033[20;5~",
[33] = "\033[21;5~",
[34] = "\033[23;5~",
[35] = "\033[24;5~",
[36] = "\033[1;6P",
[37] = "\033[1;6Q",
[38] = "\033[1;6R",
[39] = "\033[1;6S",
[40] = "\033[15;6~",
[41] = "\033[17;6~",
[42] = "\033[18;6~",
[43] = "\033[19;6~",
[44] = "\033[20;6~",
[45] = "\033[21;6~",
[46] = "\033[23;6~",
[47] = "\033[24;6~",
[48] = "\033[1;3P",
[49] = "\033[1;3Q",
[50] = "\033[1;3R",
[51] = "\033[1;3S",
[52] = "\033[15;3~",
[53] = "\033[17;3~",
[54] = "\033[18;3~",
[55] = "\033[19;3~",
[56] = "\033[20;3~",
[57] = "\033[21;3~",
[58] = "\033[23;3~",
[59] = "\033[24;3~",
[60] = "\033[1;4P",
[61] = "\033[1;4Q",
[62] = "\033[1;4R",
},
};
static const TerminfoEntry interix_8colour_terminfo = {
.bce = true,
.has_Tc_or_RGB = false,