aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Anders <8965202+gpanders@users.noreply.github.com>2023-12-06 10:55:50 -0800
committerGitHub <noreply@github.com>2023-12-06 10:55:50 -0800
commit08545bd45b80e3056fc8c6c4eb25e2ef1fddd897 (patch)
tree798ac51dc30ebc95617ffdbaaa4c474d70b3d226
parentca7f8786a0eb578895400e23cd21e25cc0f91800 (diff)
parenta5a346678a8211ea07f318de42e557ad3909f65e (diff)
downloadrneovim-08545bd45b80e3056fc8c6c4eb25e2ef1fddd897.tar.gz
rneovim-08545bd45b80e3056fc8c6c4eb25e2ef1fddd897.tar.bz2
rneovim-08545bd45b80e3056fc8c6c4eb25e2ef1fddd897.zip
Merge pull request #26407 from gpanders/default-tgc
feat(defaults): enable 'termguicolors' by default when supported by terminal
-rw-r--r--runtime/doc/news.txt3
-rw-r--r--runtime/doc/options.txt4
-rw-r--r--runtime/doc/vim_diff.txt2
-rw-r--r--runtime/lua/vim/_defaults.lua255
-rw-r--r--runtime/lua/vim/_meta.lua1
-rw-r--r--runtime/lua/vim/_meta/options.lua4
-rw-r--r--runtime/lua/vim/termcap.lua52
-rw-r--r--runtime/plugin/osc52.lua8
-rw-r--r--src/nvim/options.lua4
-rw-r--r--src/nvim/tui/tui.c47
-rw-r--r--src/nvim/ui_client.c9
-rw-r--r--test/functional/autocmd/focus_spec.lua11
-rw-r--r--test/functional/core/main_spec.lua2
-rw-r--r--test/functional/helpers.lua3
-rw-r--r--test/functional/terminal/api_spec.lua8
-rw-r--r--test/functional/terminal/buffer_spec.lua12
-rw-r--r--test/functional/terminal/cursor_spec.lua29
-rw-r--r--test/functional/terminal/helpers.lua24
-rw-r--r--test/functional/terminal/tui_spec.lua225
-rw-r--r--test/functional/ui/output_spec.lua8
20 files changed, 494 insertions, 217 deletions
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index e38707fa76..3006287e62 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -98,6 +98,9 @@ The following changes may require adaptations in user config or plugins.
• Default color scheme has been updated to be "Neovim branded" and accessible.
Use `:colorscheme vim` to revert to the old legacy color scheme.
+• 'termguicolors' is enabled by default when Nvim is able to determine that
+ the host terminal emulator supports 24-bit color.
+
==============================================================================
BREAKING CHANGES IN HEAD *news-breaking-dev*
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index f47093782c..355c8cc99a 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -6495,6 +6495,10 @@ A jump table for the options with a short description can be found at |Q_op|.
attributes instead of "cterm" attributes. |guifg|
Requires an ISO-8613-3 compatible terminal.
+ Nvim will automatically attempt to determine if the host terminal
+ supports 24-bit color and will enable this option if it does
+ (unless explicitly disabled by the user).
+
*'termpastefilter'* *'tpf'*
'termpastefilter' 'tpf' string (default "BS,HT,ESC,DEL")
global
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index f6dfe3b14a..220505f573 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -75,6 +75,8 @@ Defaults *nvim-defaults*
- 'switchbuf' defaults to "uselast"
- 'tabpagemax' defaults to 50
- 'tags' defaults to "./tags;,tags"
+- 'termguicolors' is enabled by default if Nvim can detect support from the
+ host terminal
- 'ttimeoutlen' defaults to 50
- 'ttyfast' is always set
- 'undodir' defaults to ~/.local/state/nvim/undo// (|xdg|), auto-created
diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index c3bb36fc36..b73681be04 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -165,91 +165,92 @@ do
})
end
---- Guess value of 'background' based on terminal color.
----
---- We write Operating System Command (OSC) 11 to the terminal to request the
---- terminal's background color. We then wait for a response. If the response
---- matches `rgba:RRRR/GGGG/BBBB/AAAA` where R, G, B, and A are hex digits, then
---- compute the luminance[1] of the RGB color and classify it as light/dark
---- accordingly. Note that the color components may have anywhere from one to
---- four hex digits, and require scaling accordingly as values out of 4, 8, 12,
---- or 16 bits. Also note the A(lpha) component is optional, and is parsed but
---- ignored in the calculations.
----
---- [1] https://en.wikipedia.org/wiki/Luma_%28video%29
-do
- --- Parse a string of hex characters as a color.
- ---
- --- The string can contain 1 to 4 hex characters. The returned value is
- --- between 0.0 and 1.0 (inclusive) representing the intensity of the color.
- ---
- --- For instance, if only a single hex char "a" is used, then this function
- --- returns 0.625 (10 / 16), while a value of "aa" would return 0.664 (170 /
- --- 256).
- ---
- --- @param c string Color as a string of hex chars
- --- @return number? Intensity of the color
- local function parsecolor(c)
- if #c == 0 or #c > 4 then
- return nil
- end
-
- local val = tonumber(c, 16)
- if not val then
- return nil
- end
-
- local max = tonumber(string.rep('f', #c), 16)
- return val / max
+-- Only do the following when the TUI is attached
+local tty = nil
+for _, ui in ipairs(vim.api.nvim_list_uis()) do
+ if ui.chan == 1 and ui.stdout_tty then
+ tty = ui
+ break
end
+end
- --- Parse an OSC 11 response
- ---
- --- Either of the two formats below are accepted:
- ---
- --- OSC 11 ; rgb:<red>/<green>/<blue>
- ---
- --- or
- ---
- --- OSC 11 ; rgba:<red>/<green>/<blue>/<alpha>
+if tty then
+ --- Guess value of 'background' based on terminal color.
---
- --- where
+ --- We write Operating System Command (OSC) 11 to the terminal to request the
+ --- terminal's background color. We then wait for a response. If the response
+ --- matches `rgba:RRRR/GGGG/BBBB/AAAA` where R, G, B, and A are hex digits, then
+ --- compute the luminance[1] of the RGB color and classify it as light/dark
+ --- accordingly. Note that the color components may have anywhere from one to
+ --- four hex digits, and require scaling accordingly as values out of 4, 8, 12,
+ --- or 16 bits. Also note the A(lpha) component is optional, and is parsed but
+ --- ignored in the calculations.
---
- --- <red>, <green>, <blue>, <alpha> := h | hh | hhh | hhhh
- ---
- --- The alpha component is ignored, if present.
- ---
- --- @param resp string OSC 11 response
- --- @return string? Red component
- --- @return string? Green component
- --- @return string? Blue component
- local function parseosc11(resp)
- local r, g, b
- r, g, b = resp:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
- if not r and not g and not b then
- local a
- r, g, b, a = resp:match('^\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$')
- if not a or #a > 4 then
- return nil, nil, nil
+ --- [1] https://en.wikipedia.org/wiki/Luma_%28video%29
+ do
+ --- Parse a string of hex characters as a color.
+ ---
+ --- The string can contain 1 to 4 hex characters. The returned value is
+ --- between 0.0 and 1.0 (inclusive) representing the intensity of the color.
+ ---
+ --- For instance, if only a single hex char "a" is used, then this function
+ --- returns 0.625 (10 / 16), while a value of "aa" would return 0.664 (170 /
+ --- 256).
+ ---
+ --- @param c string Color as a string of hex chars
+ --- @return number? Intensity of the color
+ local function parsecolor(c)
+ if #c == 0 or #c > 4 then
+ return nil
end
- end
- if r and g and b and #r <= 4 and #g <= 4 and #b <= 4 then
- return r, g, b
+ local val = tonumber(c, 16)
+ if not val then
+ return nil
+ end
+
+ local max = tonumber(string.rep('f', #c), 16)
+ return val / max
end
- return nil, nil, nil
- end
+ --- Parse an OSC 11 response
+ ---
+ --- Either of the two formats below are accepted:
+ ---
+ --- OSC 11 ; rgb:<red>/<green>/<blue>
+ ---
+ --- or
+ ---
+ --- OSC 11 ; rgba:<red>/<green>/<blue>/<alpha>
+ ---
+ --- where
+ ---
+ --- <red>, <green>, <blue>, <alpha> := h | hh | hhh | hhhh
+ ---
+ --- The alpha component is ignored, if present.
+ ---
+ --- @param resp string OSC 11 response
+ --- @return string? Red component
+ --- @return string? Green component
+ --- @return string? Blue component
+ local function parseosc11(resp)
+ local r, g, b
+ r, g, b = resp:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
+ if not r and not g and not b then
+ local a
+ r, g, b, a = resp:match('^\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$')
+ if not a or #a > 4 then
+ return nil, nil, nil
+ end
+ end
+
+ if r and g and b and #r <= 4 and #g <= 4 and #b <= 4 then
+ return r, g, b
+ end
- local tty = false
- for _, ui in ipairs(vim.api.nvim_list_uis()) do
- if ui.chan == 1 and ui.stdout_tty then
- tty = true
- break
+ return nil, nil, nil
end
- end
- if tty then
local timer = assert(vim.uv.new_timer())
---@param bg string New value of the 'background' option
@@ -300,7 +301,7 @@ do
io.stdout:write('\027]11;?\007')
timer:start(1000, 0, function()
- -- No response received. Delete the autocommand
+ -- Delete the autocommand if no response was received
vim.schedule(function()
-- Suppress error if autocommand has already been deleted
pcall(vim.api.nvim_del_autocmd, id)
@@ -311,4 +312,108 @@ do
end
end)
end
+
+ --- If the TUI (term_has_truecolor) was able to determine that the host
+ --- terminal supports truecolor, enable 'termguicolors'. Otherwise, query the
+ --- terminal (using both XTGETTCAP and SGR + DECRQSS). If the terminal's
+ --- response indicates that it does support truecolor enable 'termguicolors',
+ --- but only if the user has not already disabled it.
+ do
+ if tty.rgb then
+ -- The TUI was able to determine truecolor support
+ vim.o.termguicolors = true
+ else
+ --- Enable 'termguicolors', but only if it was not already set by the user.
+ local function settgc()
+ if not vim.api.nvim_get_option_info2('termguicolors', {}).was_set then
+ vim.o.termguicolors = true
+ end
+ end
+
+ local caps = {} ---@type table<string, boolean>
+ require('vim.termcap').query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found)
+ if not found then
+ return
+ end
+
+ caps[cap] = true
+ if caps.Tc or caps.RGB or (caps.setrgbf and caps.setrgbb) then
+ settgc()
+ end
+ end)
+
+ local timer = assert(vim.uv.new_timer())
+
+ -- Arbitrary colors to set in the SGR sequence
+ local r = 1
+ local g = 2
+ local b = 3
+
+ local id = vim.api.nvim_create_autocmd('TermResponse', {
+ nested = true,
+ callback = function(args)
+ local resp = args.data ---@type string
+ local decrqss = resp:match('^\027P1%$r([%d;:]+)m$')
+
+ if decrqss then
+ -- The DECRQSS SGR response first contains attributes separated by
+ -- semicolons, followed by the SGR itself with parameters separated
+ -- by colons. Some terminals include "0" in the attribute list
+ -- unconditionally; others do not. Our SGR sequence did not set any
+ -- attributes, so there should be no attributes in the list.
+ local attrs = vim.split(decrqss, ';')
+ if #attrs ~= 1 and (#attrs ~= 2 or attrs[1] ~= '0') then
+ return true
+ end
+
+ -- The returned SGR sequence should begin with 48:2
+ local sgr = attrs[#attrs]:match('^48:2:([%d:]+)$')
+ if not sgr then
+ return true
+ end
+
+ -- The remaining elements of the SGR sequence should be the 3 colors
+ -- we set. Some terminals also include an additional parameter
+ -- (which can even be empty!), so handle those cases as well
+ local params = vim.split(sgr, ':')
+ if #params ~= 3 and (#params ~= 4 or (params[1] ~= '' and params[1] ~= '1')) then
+ return true
+ end
+
+ if
+ tonumber(params[#params - 2]) == r
+ and tonumber(params[#params - 1]) == g
+ and tonumber(params[#params]) == b
+ then
+ settgc()
+ end
+
+ return true
+ end
+ end,
+ })
+
+ -- Write SGR followed by DECRQSS. This sets the background color then
+ -- immediately asks the terminal what the background color is. If the
+ -- terminal responds to the DECRQSS with the same SGR sequence that we
+ -- sent then the terminal supports truecolor.
+ local decrqss = '\027P$qm\027\\'
+ if os.getenv('TMUX') then
+ decrqss = string.format('\027Ptmux;%s\027\\', decrqss:gsub('\027', '\027\027'))
+ end
+ io.stdout:write(string.format('\027[48;2;%d;%d;%dm%s', r, g, b, decrqss))
+
+ timer:start(1000, 0, function()
+ -- Delete the autocommand if no response was received
+ vim.schedule(function()
+ -- Suppress error if autocommand has already been deleted
+ pcall(vim.api.nvim_del_autocmd, id)
+ end)
+
+ if not timer:is_closing() then
+ timer:close()
+ end
+ end)
+ end
+ end
end
diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua
index e3b99f6b3d..bb9ed722e2 100644
--- a/runtime/lua/vim/_meta.lua
+++ b/runtime/lua/vim/_meta.lua
@@ -20,6 +20,7 @@ vim.lsp = require('vim.lsp')
vim.re = require('vim.re')
vim.secure = require('vim.secure')
vim.snippet = require('vim.snippet')
+vim.text = require('vim.text')
vim.treesitter = require('vim.treesitter')
vim.ui = require('vim.ui')
vim.version = require('vim.version')
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index d2bdab4d28..5e65ca6b1b 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -6941,6 +6941,10 @@ vim.go.tbidi = vim.go.termbidi
--- attributes instead of "cterm" attributes. `guifg`
--- Requires an ISO-8613-3 compatible terminal.
---
+--- Nvim will automatically attempt to determine if the host terminal
+--- supports 24-bit color and will enable this option if it does
+--- (unless explicitly disabled by the user).
+---
--- @type boolean
vim.o.termguicolors = false
vim.o.tgc = vim.o.termguicolors
diff --git a/runtime/lua/vim/termcap.lua b/runtime/lua/vim/termcap.lua
index 862cc52149..b88d9ac9ba 100644
--- a/runtime/lua/vim/termcap.lua
+++ b/runtime/lua/vim/termcap.lua
@@ -12,7 +12,10 @@ local M = {}
--- emulator supports the XTGETTCAP sequence.
---
--- @param caps string|table A terminal capability or list of capabilities to query
---- @param cb function(cap:string, seq:string) Function to call when a response is received
+--- @param cb function(cap:string, found:bool, seq:string?) Callback function which is called for
+--- each capability in {caps}. {found} is set to true if the capability was found or false
+--- otherwise. {seq} is the control sequence for the capability if found, or nil for
+--- boolean capabilities.
function M.query(caps, cb)
vim.validate({
caps = { caps, { 'string', 'table' } },
@@ -23,21 +26,33 @@ function M.query(caps, cb)
caps = { caps }
end
- local count = #caps
+ local pending = {} ---@type table<string, boolean>
+ for _, v in ipairs(caps) do
+ pending[v] = true
+ end
+
+ local timer = assert(vim.uv.new_timer())
- vim.api.nvim_create_autocmd('TermResponse', {
+ local id = vim.api.nvim_create_autocmd('TermResponse', {
callback = function(args)
local resp = args.data ---@type string
- local k, v = resp:match('^\027P1%+r(%x+)=(%x+)$')
- if k and v then
+ local k, rest = resp:match('^\027P1%+r(%x+)(.*)$')
+ if k and rest then
local cap = vim.text.hexdecode(k)
- local seq =
- vim.text.hexdecode(v):gsub('\\E', '\027'):gsub('%%p%d', ''):gsub('\\(%d+)', string.char)
+ local seq ---@type string?
+ if rest:match('^=%x+$') then
+ seq = vim.text
+ .hexdecode(rest:sub(2))
+ :gsub('\\E', '\027')
+ :gsub('%%p%d', '')
+ :gsub('\\(%d+)', string.char)
+ end
+
+ cb(cap, true, seq)
- cb(cap, seq)
+ pending[cap] = nil
- count = count - 1
- if count == 0 then
+ if next(pending) == nil then
return true
end
end
@@ -57,6 +72,23 @@ function M.query(caps, cb)
end
io.stdout:write(query)
+
+ timer:start(1000, 0, function()
+ -- Delete the autocommand if no response was received
+ vim.schedule(function()
+ -- Suppress error if autocommand has already been deleted
+ pcall(vim.api.nvim_del_autocmd, id)
+
+ -- Call the callback for all capabilities that were not found
+ for k in pairs(pending) do
+ cb(k, false, nil)
+ end
+ end)
+
+ if not timer:is_closing() then
+ timer:close()
+ end
+ end)
end
return M
diff --git a/runtime/plugin/osc52.lua b/runtime/plugin/osc52.lua
index 374b70066f..7a90518966 100644
--- a/runtime/plugin/osc52.lua
+++ b/runtime/plugin/osc52.lua
@@ -6,7 +6,11 @@ if not tty or vim.g.clipboard ~= nil or vim.o.clipboard ~= '' or not os.getenv('
return
end
-require('vim.termcap').query('Ms', function(cap, seq)
+require('vim.termcap').query('Ms', function(cap, found, seq)
+ if not found then
+ return
+ end
+
assert(cap == 'Ms')
-- Check 'clipboard' and g:clipboard again to avoid a race condition
@@ -16,7 +20,7 @@ require('vim.termcap').query('Ms', function(cap, seq)
-- If the terminal reports a sequence other than OSC 52 for the Ms capability
-- then ignore it. We only support OSC 52 (for now)
- if not seq:match('^\027%]52') then
+ if not seq or not seq:match('^\027%]52') then
return
end
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index daaf73d241..50371b8bf3 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -8764,6 +8764,10 @@ return {
Enables 24-bit RGB color in the |TUI|. Uses "gui" |:highlight|
attributes instead of "cterm" attributes. |guifg|
Requires an ISO-8613-3 compatible terminal.
+
+ Nvim will automatically attempt to determine if the host terminal
+ supports 24-bit color and will enable this option if it does
+ (unless explicitly disabled by the user).
]=],
full_name = 'termguicolors',
redraw = { 'ui_option' },
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index c71eb633e9..d625c22c76 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -148,7 +148,8 @@ static bool cursor_style_enabled = false;
# include "tui/tui.c.generated.h"
#endif
-void tui_start(TUIData **tui_p, int *width, int *height, char **term)
+void tui_start(TUIData **tui_p, int *width, int *height, char **term, bool *rgb)
+ FUNC_ATTR_NONNULL_ALL
{
TUIData *tui = xcalloc(1, sizeof(TUIData));
tui->is_starting = true;
@@ -177,6 +178,7 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term)
*width = tui->width;
*height = tui->height;
*term = tui->term;
+ *rgb = tui->rgb;
}
void tui_set_key_encoding(TUIData *tui)
@@ -334,6 +336,9 @@ static void terminfo_start(TUIData *tui)
int konsolev = konsolev_env ? (int)strtol(konsolev_env, NULL, 10)
: (konsole ? 1 : 0);
+ // truecolor support must be checked before patching/augmenting terminfo
+ tui->rgb = term_has_truecolor(tui, colorterm);
+
patch_terminfo_bugs(tui, term, colorterm, vtev, konsolev, iterm_env, nsterm);
augment_terminfo(tui, term, vtev, konsolev, iterm_env, nsterm);
tui->can_change_scroll_region =
@@ -1439,7 +1444,7 @@ void tui_suspend(TUIData *tui)
tui_mouse_on(tui);
}
stream_set_blocking(tui->input.in_fd, false); // libuv expects this
- ui_client_attach(tui->width, tui->height, tui->term);
+ ui_client_attach(tui->width, tui->height, tui->term, tui->rgb);
#endif
}
@@ -1752,6 +1757,44 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name)
return -1;
}
+/// Determine if the terminal supports truecolor or not:
+///
+/// 1. If $COLORTERM is "24bit" or "truecolor", return true
+/// 2. Else, check terminfo for Tc, RGB, setrgbf, or setrgbb capabilities. If
+/// found, return true
+/// 3. Else, return false
+static bool term_has_truecolor(TUIData *tui, const char *colorterm)
+{
+ // Check $COLORTERM
+ if (strequal(colorterm, "truecolor") || strequal(colorterm, "24bit")) {
+ return true;
+ }
+
+ // Check for Tc and RGB
+ for (size_t i = 0; i < unibi_count_ext_bool(tui->ut); i++) {
+ const char *n = unibi_get_ext_bool_name(tui->ut, i);
+ if (n && (!strcmp(n, "Tc") || !strcmp(n, "RGB"))) {
+ return true;
+ }
+ }
+
+ // Check for setrgbf and setrgbb
+ bool setrgbf = false;
+ bool setrgbb = false;
+ for (size_t i = 0; i < unibi_count_ext_str(tui->ut) && (!setrgbf || !setrgbb); i++) {
+ const char *n = unibi_get_ext_str_name(tui->ut, i);
+ if (n) {
+ if (!setrgbf && !strcmp(n, "setrgbf")) {
+ setrgbf = true;
+ } else if (!setrgbb && !strcmp(n, "setrgbb")) {
+ setrgbb = true;
+ }
+ }
+ }
+
+ return setrgbf && setrgbb;
+}
+
/// Patches the terminfo records after loading from system or built-in db.
/// Several entries in terminfo are known to be deficient or outright wrong;
/// and several terminal emulators falsely announce incorrect terminal types.
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index eb32c16881..d744560a86 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -70,14 +70,14 @@ uint64_t ui_client_start_server(int argc, char **argv)
return channel->id;
}
-void ui_client_attach(int width, int height, char *term)
+void ui_client_attach(int width, int height, char *term, bool rgb)
{
MAXSIZE_TEMP_ARRAY(args, 3);
ADD_C(args, INTEGER_OBJ(width));
ADD_C(args, INTEGER_OBJ(height));
MAXSIZE_TEMP_DICT(opts, 9);
- PUT_C(opts, "rgb", BOOLEAN_OBJ(true));
+ PUT_C(opts, "rgb", BOOLEAN_OBJ(rgb));
PUT_C(opts, "ext_linegrid", BOOLEAN_OBJ(true));
PUT_C(opts, "ext_termcolors", BOOLEAN_OBJ(true));
if (term) {
@@ -111,9 +111,10 @@ void ui_client_run(bool remote_ui)
ui_client_is_remote = remote_ui;
int width, height;
char *term;
- tui_start(&tui, &width, &height, &term);
+ bool rgb;
+ tui_start(&tui, &width, &height, &term, &rgb);
- ui_client_attach(width, height, term);
+ ui_client_attach(width, height, term, rgb);
// os_exit() will be invoked when the client channel detaches
while (true) {
diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua
index c72842f14b..204bfcaa12 100644
--- a/test/functional/autocmd/focus_spec.lua
+++ b/test/functional/autocmd/focus_spec.lua
@@ -2,7 +2,6 @@ local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local luv = require('luv')
local clear = helpers.clear
-local nvim_prog = helpers.nvim_prog
local feed_command = helpers.feed_command
local feed_data = thelpers.feed_data
@@ -14,10 +13,12 @@ describe('autoread TUI FocusGained/FocusLost', function()
before_each(function()
clear()
- screen = thelpers.screen_setup(
- 0,
- '["'..nvim_prog..'", "-u", "NONE", "-i", "NONE", "--cmd", "colorscheme vim", "--cmd", "set noswapfile noshowcmd noruler"]'
- )
+ screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', 'set noswapfile noshowcmd noruler notermguicolors',
+ })
end)
teardown(function()
diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua
index d705d56575..c8d800f89a 100644
--- a/test/functional/core/main_spec.lua
+++ b/test/functional/core/main_spec.lua
@@ -62,7 +62,7 @@ describe('command-line option', function()
screen:attach()
local args = {
nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE',
- '--cmd', '"set noswapfile shortmess+=IFW fileformats=unix"',
+ '--cmd', '"set noswapfile shortmess+=IFW fileformats=unix notermguicolors"',
'-s', '-'
}
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index b50df4c677..5780d0a978 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -30,7 +30,8 @@ module.nvim_prog = (
module.nvim_set = (
'set shortmess+=IS background=light noswapfile noautoindent startofline'
..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
- ..' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid')
+ ..' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid'
+ ..' notermguicolors')
module.nvim_argv = {
module.nvim_prog, '-u', 'NONE', '-i', 'NONE',
-- XXX: find treesitter parsers.
diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua
index c278b2ad0e..68082ba4fa 100644
--- a/test/functional/terminal/api_spec.lua
+++ b/test/functional/terminal/api_spec.lua
@@ -11,8 +11,12 @@ describe('api', function()
before_each(function()
helpers.clear()
os.remove(socket_name)
- screen = child_session.screen_setup(0, '["'..helpers.nvim_prog
- ..'", "-u", "NONE", "-i", "NONE", "--cmd", "colorscheme vim", "--cmd", "'..helpers.nvim_set..'"]')
+ screen = child_session.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', helpers.nvim_set,
+ })
end)
after_each(function()
os.remove(socket_name)
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 423e7bdf21..b92f1b1592 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -17,7 +17,6 @@ local sleep = helpers.sleep
local funcs = helpers.funcs
local is_os = helpers.is_os
local skip = helpers.skip
-local nvim_prog = helpers.nvim_prog
describe(':terminal buffer', function()
local screen
@@ -446,10 +445,13 @@ end)
describe('terminal input', function()
it('sends various special keys with modifiers', function()
clear()
- local screen = thelpers.screen_setup(
- 0,
- string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--cmd", 'colorscheme vim', "--cmd", "startinsert"]]=], nvim_prog)
- )
+ local screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', 'set notermguicolors',
+ '--cmd', 'startinsert',
+ })
screen:expect{grid=[[
{1: } |
{4:~ }|
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index 95081b7189..37bb0ee817 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -3,7 +3,6 @@ local Screen = require('test.functional.ui.screen')
local thelpers = require('test.functional.terminal.helpers')
local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim
local testprg, command = helpers.testprg, helpers.command
-local nvim_prog = helpers.nvim_prog
local eq, eval = helpers.eq, helpers.eval
local matches = helpers.matches
local poke_eventloop = helpers.poke_eventloop
@@ -184,10 +183,18 @@ describe('buffer cursor position is correct in terminal without number column',
local screen
local function setup_ex_register(str)
- screen = thelpers.screen_setup(0, '["'..nvim_prog
- ..[[", "-u", "NONE", "-i", "NONE", "-E", "--cmd", "let @r = ']]..str..[['", ]]
+ screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '-E',
+ '--cmd', string.format('let @r = "%s"', str),
-- <Left> and <Right> don't always work
- ..[["--cmd", "cnoremap <C-X> <Left>", "--cmd", "cnoremap <C-O> <Right>"]]..']', 70)
+ '--cmd', 'cnoremap <C-X> <Left>',
+ '--cmd', 'cnoremap <C-O> <Right>',
+ '--cmd', 'set notermguicolors',
+ }, {
+ cols = 70,
+ })
screen:set_default_attr_ids({
[1] = {foreground = 253, background = 11};
[3] = {bold = true},
@@ -570,10 +577,18 @@ describe('buffer cursor position is correct in terminal with number column', fun
local screen
local function setup_ex_register(str)
- screen = thelpers.screen_setup(0, '["'..nvim_prog
- ..[[", "-u", "NONE", "-i", "NONE", "-E", "--cmd", "let @r = ']]..str..[['", ]]
+ screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '-E',
+ '--cmd', string.format('let @r = "%s"', str),
-- <Left> and <Right> don't always work
- ..[["--cmd", "cnoremap <C-X> <Left>", "--cmd", "cnoremap <C-O> <Right>"]]..']', 70)
+ '--cmd', 'cnoremap <C-X> <Left>',
+ '--cmd', 'cnoremap <C-O> <Right>',
+ '--cmd', 'set notermguicolors',
+ }, {
+ cols = 70,
+ })
screen:set_default_attr_ids({
[1] = {foreground = 253, background = 11};
[3] = {bold = true},
diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua
index 62d3dd67a3..4ae054daa8 100644
--- a/test/functional/terminal/helpers.lua
+++ b/test/functional/terminal/helpers.lua
@@ -6,6 +6,7 @@ local Screen = require('test.functional.ui.screen')
local testprg = helpers.testprg
local exec_lua = helpers.exec_lua
local nvim = helpers.nvim
+local nvim_prog = helpers.nvim_prog
local function feed_data(data)
if type(data) == 'table' then
@@ -122,6 +123,26 @@ local function screen_setup(extra_rows, command, cols, opts)
return screen
end
+local function setup_child_nvim(args, opts)
+ opts = opts or {}
+
+ local argv = { nvim_prog, unpack(args) }
+ local cmd = string.format('[%s]', vim.iter(argv):map(function(s)
+ return string.format('\'%s\'', s)
+ end):join(', '))
+
+ if opts.env then
+ local s = {}
+ for k, v in pairs(opts.env) do
+ table.insert(s, string.format('%s: \'%s\'', k, v))
+ end
+
+ cmd = string.format('%s, #{env: #{%s}}', cmd, table.concat(s, ', '))
+ end
+
+ return screen_setup(0, cmd, opts.cols)
+end
+
return {
feed_data = feed_data,
feed_termcode = feed_termcode,
@@ -141,5 +162,6 @@ return {
clear_attrs = clear_attrs,
enable_mouse = enable_mouse,
disable_mouse = disable_mouse,
- screen_setup = screen_setup
+ screen_setup = screen_setup,
+ setup_child_nvim = setup_child_nvim,
}
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 3748f820d4..0c984069b3 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -39,13 +39,13 @@ describe('TUI', function()
before_each(function()
clear()
local child_server = new_pipename()
- screen = thelpers.screen_setup(0,
- string.format(
- [=[["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "%s laststatus=2 background=dark", "--cmd", "colorscheme vim"]]=],
- nvim_prog,
- child_server,
- nvim_set
- ))
+ screen = thelpers.setup_child_nvim({
+ '--listen', child_server,
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', string.format('%s laststatus=2 background=dark', nvim_set),
+ '--cmd', 'colorscheme vim'
+ })
screen:expect([[
{1: } |
{4:~ }|
@@ -1830,7 +1830,7 @@ describe('TUI', function()
})
screen:attach()
exec([[
- call termopen([v:progpath, '--clean', '--cmd', 'colorscheme vim', '--cmd', 'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile'])
+ call termopen([v:progpath, '--clean', '--cmd', 'set notermguicolors', '--cmd', 'colorscheme vim', '--cmd', 'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile'])
sleep 500m
vs new
]])
@@ -1856,30 +1856,29 @@ describe('TUI', function()
write_file(script_file, [=[
local ffi = require('ffi')
ffi.cdef([[int execl(const char *, const char *, ...);]])
- ffi.C.execl(vim.v.progpath, 'Xargv0nvim', '--clean', '--cmd', 'colorscheme vim')
+ ffi.C.execl(vim.v.progpath, 'Xargv0nvim', '--clean')
]=])
finally(function()
os.remove(script_file)
end)
- local screen = thelpers.screen_setup(0, string.format([=[["%s", "--clean", "-l", "%s"]]=],
- nvim_prog, script_file))
+ local screen = thelpers.setup_child_nvim({'--clean', '-l', script_file})
screen:expect{grid=[[
{1: } |
- {4:~ }|
- {4:~ }|
- {4:~ }|
- {5:[No Name] 0,0-1 All}|
+ ~ |
+ ~ |
+ ~ |
+ [No Name] 0,0-1 All|
|
{3:-- TERMINAL --} |
]]}
feed_data(':put =v:argv + [v:progname]\n')
screen:expect{grid=[[
+ Xargv0nvim |
+ --embed |
--clean |
- --cmd |
- colorscheme vim |
{1:X}argv0nvim |
- {5:[No Name] [+] 7,1 Bot}|
- 6 more lines |
+ [No Name] [+] 5,1 Bot|
+ 4 more lines |
{3:-- TERMINAL --} |
]]}
end)
@@ -1903,11 +1902,13 @@ describe('TUI', function()
end)
it('<C-h> #10134', function()
- local screen = thelpers.screen_setup(
- 0,
- '["'..nvim_prog..[[", "-u", "NONE", "-i", "NONE", "--cmd", "colorscheme vim", ]]
- ..[["--cmd", "set noruler", "--cmd", ':nnoremap <C-h> :echomsg "\<C-h\>"<CR>']]..']'
- )
+ local screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', 'set noruler notermguicolors',
+ '--cmd', ':nnoremap <C-h> :echomsg "\\<C-h\\>"<CR>',
+ })
screen:expect{grid=[[
{1: } |
{4:~ }|
@@ -1931,12 +1932,13 @@ describe('TUI', function()
end)
it('draws line with many trailing spaces correctly #24955', function()
- local screen = thelpers.screen_setup(
- 0,
- '["'..nvim_prog..[[", "-u", "NONE", "-i", "NONE", "--cmd", "colorscheme vim"]]
- ..[[, "--cmd", "call setline(1, ['1st line' .. repeat(' ', 153), '2nd line'])"]]..']',
- 80
- )
+ local screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'set notermguicolors',
+ '--cmd', 'colorscheme vim',
+ '--cmd', 'call setline(1, ["1st line" .. repeat(" ", 153), "2nd line"])',
+ }, { cols = 80 })
screen:expect{grid=[[
{1:1}st line |
|
@@ -1962,16 +1964,16 @@ end)
describe('TUI UIEnter/UILeave', function()
it('fires exactly once, after VimEnter', function()
clear()
- local screen = thelpers.screen_setup(0,
- '["'..nvim_prog..'", "-u", "NONE", "-i", "NONE"'
- ..[[, "--cmd", "colorscheme vim"]]
- ..[[, "--cmd", "set noswapfile noshowcmd noruler"]]
- ..[[, "--cmd", "let g:evs = []"]]
- ..[[, "--cmd", "autocmd UIEnter * :call add(g:evs, 'UIEnter')"]]
- ..[[, "--cmd", "autocmd UILeave * :call add(g:evs, 'UILeave')"]]
- ..[[, "--cmd", "autocmd VimEnter * :call add(g:evs, 'VimEnter')"]]
- ..']'
- )
+ local screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', 'set noswapfile noshowcmd noruler notermguicolors',
+ '--cmd', 'let g:evs = []',
+ '--cmd', 'autocmd UIEnter * :call add(g:evs, "UIEnter")',
+ '--cmd', 'autocmd UILeave * :call add(g:evs, "UILeave")',
+ '--cmd', 'autocmd VimEnter * :call add(g:evs, "VimEnter")',
+ })
screen:expect{grid=[[
{1: } |
{4:~ }|
@@ -2001,11 +2003,14 @@ describe('TUI FocusGained/FocusLost', function()
before_each(function()
clear()
local child_server = new_pipename()
- screen = thelpers.screen_setup(0,
- string.format(
- '["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "colorscheme vim", '
- ..'"--cmd", "set noswapfile noshowcmd noruler"]',
- nvim_prog, child_server))
+ screen = thelpers.setup_child_nvim({
+ '--listen', child_server,
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', 'set noswapfile noshowcmd noruler notermguicolors',
+ })
+
screen:expect([[
{1: } |
{4:~ }|
@@ -2208,14 +2213,18 @@ describe("TUI 't_Co' (terminal colors)", function()
local function assert_term_colors(term, colorterm, maxcolors)
clear({env={TERM=term}, args={}})
- -- This is ugly because :term/termopen() forces TERM=xterm-256color.
- -- TODO: Revisit this after jobstart/termopen accept `env` dict.
- screen = thelpers.screen_setup(0, string.format(
- [=[['sh', '-c', 'LANG=C TERM=%s %s %s -u NONE -i NONE --cmd "colorscheme vim" --cmd "%s"']]=],
- term or "",
- (colorterm ~= nil and "COLORTERM="..colorterm or ""),
- nvim_prog,
- nvim_set))
+ screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', nvim_set,
+ }, {
+ env = {
+ LANG = 'C',
+ TERM = term or '',
+ COLORTERM = colorterm or '',
+ },
+ })
local tline
if maxcolors == 8 then
@@ -2483,14 +2492,16 @@ describe("TUI 'term' option", function()
local function assert_term(term_envvar, term_expected)
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 TERM=%s %s -u NONE -i NONE --cmd "%s"']]=],
- term_envvar or "",
- nvim_prog,
- nvim_set)
- screen = thelpers.screen_setup(0, cmd)
+ screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', nvim_set,
+ }, {
+ env = {
+ LANG = 'C',
+ TERM = term_envvar or '',
+ },
+ })
local full_timeout = screen.timeout
screen.timeout = 250 -- We want screen:expect() to fail quickly.
@@ -2540,14 +2551,17 @@ describe("TUI", function()
-- 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 "colorscheme vim" --cmd "%s"']]=],
- nvim_prog,
- extra_args or "",
- nvim_set)
- screen = thelpers.screen_setup(0, cmd)
+ screen = thelpers.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', nvim_set,
+ extra_args,
+ }, {
+ env = {
+ LANG = 'C',
+ },
+ })
end
it('-V3log logs terminfo values', function()
@@ -2604,9 +2618,18 @@ describe('TUI bg color', function()
local function setup_bg_test()
clear()
- screen = thelpers.screen_setup(0, '["'..nvim_prog
- ..'", "-u", "NONE", "-i", "NONE", "--cmd", "colorscheme vim", "--cmd", "set noswapfile", '
- ..'"-c", "autocmd OptionSet background echo \\"did OptionSet, yay!\\""]')
+ screen = thelpers.setup_child_nvim({
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--cmd',
+ 'colorscheme vim',
+ '--cmd',
+ 'set noswapfile notermguicolors',
+ '-c',
+ 'autocmd OptionSet background echo "did OptionSet, yay!"',
+ })
end
before_each(setup_bg_test)
@@ -2725,14 +2748,13 @@ describe("TUI as a client", function()
set_session(server_super)
local server_pipe = new_pipename()
- local screen_server = thelpers.screen_setup(0,
- string.format(
- '["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "colorscheme vim", '
- ..'"--cmd", "%s laststatus=2 background=dark"]',
- nvim_prog,
- server_pipe,
- nvim_set
- ))
+ local screen_server = thelpers.setup_child_nvim({
+ '--listen', server_pipe,
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', string.format('%s laststatus=2 background=dark', nvim_set),
+ })
feed_data("iHello, World")
screen_server:expect{grid=[[
@@ -2756,9 +2778,10 @@ describe("TUI as a client", function()
]]}
set_session(client_super)
- local screen_client = thelpers.screen_setup(0,
- string.format([=[["%s", "--server", "%s", "--remote-ui"]]=],
- nvim_prog, server_pipe))
+ local screen_client = thelpers.setup_child_nvim({
+ '--server', server_pipe,
+ '--remote-ui',
+ })
screen_client:expect{grid=[[
Hello, Worl{1:d} |
@@ -2798,9 +2821,10 @@ describe("TUI as a client", function()
server:request('nvim_input', 'iHalloj!<Esc>')
set_session(client_super)
- local screen_client = thelpers.screen_setup(0,
- string.format([=[["%s", "--server", "%s", "--remote-ui"]]=],
- nvim_prog, server_pipe))
+ local screen_client = thelpers.setup_child_nvim({
+ '--server', server_pipe,
+ '--remote-ui',
+ })
screen_client:expect{grid=[[
Halloj{1:!} |
@@ -2836,9 +2860,10 @@ describe("TUI as a client", function()
it("throws error when no server exists", function()
clear()
- local screen = thelpers.screen_setup(0,
- string.format([=[["%s", "--server", "127.0.0.1:2436546", "--remote-ui"]]=],
- nvim_prog), 60)
+ local screen = thelpers.setup_child_nvim({
+ '--server', '127.0.0.1:2436546',
+ '--remote-ui',
+ }, { cols = 60 })
screen:expect([[
Remote ui failed to start: {MATCH:.*}|
@@ -2857,14 +2882,13 @@ describe("TUI as a client", function()
set_session(server_super)
local server_pipe = new_pipename()
- local screen_server = thelpers.screen_setup(0,
- string.format(
- '["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "colorscheme vim", '
- ..'"--cmd", "%s laststatus=2 background=dark"]',
- nvim_prog,
- server_pipe,
- nvim_set
- ))
+ local screen_server = thelpers.setup_child_nvim({
+ '--listen', server_pipe,
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', string.format('%s laststatus=2 background=dark', nvim_set),
+ })
screen_server:expect{grid=[[
{1: } |
{4:~ }|
@@ -2897,9 +2921,10 @@ describe("TUI as a client", function()
]]}
set_session(client_super)
- local screen_client = thelpers.screen_setup(0,
- string.format([=[["%s", "--server", "%s", "--remote-ui"]]=],
- nvim_prog, server_pipe))
+ local screen_client = thelpers.setup_child_nvim({
+ '--server', server_pipe,
+ '--remote-ui',
+ })
screen_client:expect{grid=[[
Hello, Worl{1:d} |
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 1dbbe76bac..719634aa2f 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -21,8 +21,12 @@ describe("shell command :!", function()
local screen
before_each(function()
clear()
- screen = child_session.screen_setup(0, '["'..helpers.nvim_prog..
- '", "-u", "NONE", "-i", "NONE", "--cmd", "colorscheme vim", "--cmd", "'..helpers.nvim_set..'"]')
+ screen = child_session.setup_child_nvim({
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', 'colorscheme vim',
+ '--cmd', helpers.nvim_set,
+ })
screen:expect([[
{1: } |
{4:~ }|