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| For this terminal Set $TERM to |builtin-terms|
------------------------------------------------------------------------- -------------------------------------------------------------------------
anything libvte-based vte, vte-256color Y ansi (unknown) Y
(e.g. GNOME Terminal) (aliases: gnome, gnome-256color) Ghostty ghostty, xterm-ghostty Y
iTerm (original) iterm, iTerm.app N iTerm (original) iterm, iTerm.app N
iTerm2 (new capabilities) iterm2, iTerm2.app Y iTerm2 (new capabilities) iterm2, iTerm2.app Y
Konsole konsole-256color N 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 Linux virtual terminal linux, linux-256color Y
PuTTY putty, putty-256color Y PuTTY putty, putty-256color Y
rxvt rxvt, rxvt-256color Y rxvt rxvt, rxvt-256color Y
@@ -76,22 +78,26 @@ unlike most other environment variables.
Windows/ConEmu conemu Y Windows/ConEmu conemu Y
Windows/Cygwin-built Nvim cygwin Y Windows/Cygwin-built Nvim cygwin Y
Windows/Interix interix Y Windows/Interix interix Y
Windows/VTP console vtpcon Y
Windows/legacy console win32con Y Windows/legacy console win32con Y
Windows/VTP console vtpcon Y
xterm or compatible xterm, xterm-256color Y xterm or compatible xterm, xterm-256color Y
< <
*builtin-terms* *builtin_terms* *builtin-terms* *builtin_terms*
If a |terminfo| database is not available or there is no entry for the current Nvim will map |$TERM| to a builtin entry according to the above table if:
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 - a |terminfo| database is not available on the system
be mapped to the builtin "putty" entry. See also |tui-colors|. - 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 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 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 omissions or out-of-date information in the builtin terminfo database by
supplying an external one with entries for the terminal type. 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* Settings depending on terminal *term-dependent-settings*
If you want to set terminal-dependent options or mappings, you can do this in 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 = { local entries = {
{ 'ansi', 'ansi_terminfo' }, { 'ansi', 'ansi_terminfo' },
{ 'ghostty', 'ghostty_terminfo' }, -- Note: ncurses defs do not exactly match what ghostty ships.
{ 'interix', 'interix_8colour_terminfo' }, { 'interix', 'interix_8colour_terminfo' },
{ 'iterm2', 'iterm_256colour_terminfo' }, { 'iterm2', 'iterm_256colour_terminfo' },
{ 'linux', 'linux_16colour_terminfo' }, { 'linux', 'linux_16colour_terminfo' },

View File

@@ -70,7 +70,10 @@ bool terminfo_is_bsd_console(const char *term)
/// @return [allocated] terminfo structure /// @return [allocated] terminfo structure
const TerminfoEntry *terminfo_from_builtin(const char *term, char **termname) 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"; *termname = "xterm";
return &xterm_256colour_terminfo; return &xterm_256colour_terminfo;
} else if (terminfo_is_term_family(term, "screen")) { } 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 = { static const TerminfoEntry interix_8colour_terminfo = {
.bce = true, .bce = true,
.has_Tc_or_RGB = false, .has_Tc_or_RGB = false,