aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Steinberg <dstein64@users.noreply.github.com>2024-01-15 11:12:07 -0500
committerGitHub <noreply@github.com>2024-01-15 10:12:07 -0600
commit7589336120a258cf75134a5243b2f6b1926ac85b (patch)
treeec4ee3d859c0686913e552e84bb6c857ee8f1e85
parent9c202b9392f3d42618cc576aab00a50ed2f7bdeb (diff)
downloadrneovim-7589336120a258cf75134a5243b2f6b1926ac85b.tar.gz
rneovim-7589336120a258cf75134a5243b2f6b1926ac85b.tar.bz2
rneovim-7589336120a258cf75134a5243b2f6b1926ac85b.zip
feat(terminal): respond to OSC background and foreground request (#17197)
The motivation for this update is Issue #15365, where background=light is not properly set for Nvim running from an Nvim :terminal. This can be encountered when e.g., opening a terminal to make git commits, which opens EDITOR=nvim in the nested terminal. Under the implementation of this commit, the OSC response always indicates a black or white foreground/background. While this may not reflect the actual foreground/background color, it permits 'background' to be retained for a nested Nvim instance running in the terminal emulator. The behaviour matches Vim.
-rw-r--r--runtime/doc/news.txt2
-rw-r--r--runtime/doc/vim_diff.txt6
-rw-r--r--runtime/lua/vim/_defaults.lua24
-rw-r--r--test/functional/core/startup_spec.lua19
-rw-r--r--test/functional/terminal/tui_spec.lua192
5 files changed, 137 insertions, 106 deletions
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index cb70c81191..7743f5981a 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -287,6 +287,8 @@ The following new APIs and features were added.
• Terminal buffers emit a |TermRequest| autocommand event when the child
process emits an OSC or DCS control sequence.
+• Terminal buffers respond to OSC background and foreground requests. |default-autocmds|
+
==============================================================================
CHANGED FEATURES *news-changed*
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 279fdd646f..46550f42b7 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -145,6 +145,12 @@ nvim_terminal:
- BufReadCmd: Treats "term://" buffers as |terminal| buffers. |terminal-start|
- TermClose: A |terminal| buffer started with no arguments (which thus uses
'shell') and which exits with no error is closed automatically.
+- TermRequest: The terminal emulator responds to OSC background and foreground
+ requests, indicating (1) a black background and white foreground when Nvim
+ option 'background' is "dark" or (2) a white background and black foreground
+ when 'background' is "light". While this may not reflect the actual
+ foreground/background color, it permits 'background' to be retained for a
+ nested Nvim instance running in the terminal emulator.
nvim_cmdwin:
- CmdwinEnter: Limits syntax sync to maxlines=1 in the |cmdwin|.
diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index 64eb638fd7..07850a5a47 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -155,6 +155,30 @@ do
end,
})
+ vim.api.nvim_create_autocmd('TermRequest', {
+ group = nvim_terminal_augroup,
+ desc = 'Respond to OSC foreground/background color requests',
+ callback = function(args)
+ local fg_request = args.data == '\027]10;?'
+ local bg_request = args.data == '\027]11;?'
+ if fg_request or bg_request then
+ -- WARN: This does not return the actual foreground/background color,
+ -- but rather returns:
+ -- - fg=white/bg=black when Nvim option 'background' is 'dark'
+ -- - fg=black/bg=white when Nvim option 'background' is 'light'
+ local red, green, blue = 0, 0, 0
+ local bg_option_dark = vim.o.background == 'dark'
+ if (fg_request and bg_option_dark) or (bg_request and not bg_option_dark) then
+ red, green, blue = 65535, 65535, 65535
+ end
+ local command = fg_request and 10 or 11
+ local data = string.format('\027]%d;rgb:%04x/%04x/%04x\007', command, red, green, blue)
+ local channel = vim.bo[args.buf].channel
+ vim.api.nvim_chan_send(channel, data)
+ end
+ end,
+ })
+
vim.api.nvim_create_autocmd('CmdwinEnter', {
pattern = '[:>]',
desc = 'Limit syntax sync to maxlines=1 in the command window',
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index fd3748a985..f4a9c0c8d7 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -1369,12 +1369,19 @@ describe('inccommand on ex mode', function()
local screen
screen = Screen.new(60, 10)
screen:attach()
- local id = fn.termopen(
- { nvim_prog, '-u', 'NONE', '-c', 'set termguicolors', '-E', 'test/README.md' },
- {
- env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
- }
- )
+ local id = fn.termopen({
+ nvim_prog,
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '-c',
+ 'set termguicolors background=dark',
+ '-E',
+ 'test/README.md',
+ }, {
+ env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
+ })
fn.chansend(id, '%s/N')
screen:expect {
grid = [[
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 54fbfd191a..46d3c98e07 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -8,6 +8,7 @@ local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local Screen = require('test.functional.ui.screen')
local eq = helpers.eq
+local feed_command = helpers.feed_command
local feed_data = thelpers.feed_data
local clear = helpers.clear
local command = helpers.command
@@ -2126,7 +2127,7 @@ describe('TUI FocusGained/FocusLost', function()
'--cmd',
'colorscheme vim',
'--cmd',
- 'set noswapfile noshowcmd noruler notermguicolors',
+ 'set noswapfile noshowcmd noruler notermguicolors background=dark',
})
screen:expect([[
@@ -2776,10 +2777,73 @@ describe('TUI', function()
end)
describe('TUI bg color', function()
- local screen
+ before_each(clear)
- local function setup_bg_test()
- clear()
+ local attr_ids = {
+ [1] = { reverse = true },
+ [2] = { bold = true },
+ [3] = { reverse = true, bold = true },
+ [4] = { foreground = tonumber('0x00000a') },
+ }
+
+ it('is properly set in a nested Nvim instance when background=dark', function()
+ command('highlight clear Normal')
+ command('set background=dark') -- set outer Nvim background
+ local screen = thelpers.setup_child_nvim({
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--cmd',
+ 'colorscheme vim',
+ '--cmd',
+ 'set noswapfile',
+ })
+ screen:set_default_attr_ids(attr_ids)
+ retry(nil, 30000, function() -- wait for automatic background processing
+ screen:sleep(20)
+ feed_command('set background?') -- check nested Nvim background
+ screen:expect([[
+ {1: } |
+ {2:~} |
+ {2:~} |
+ {2:~} |
+ {3:[No Name] 0,0-1 All}|
+ background=dark |
+ {4:-- TERMINAL --} |
+ ]])
+ end)
+ end)
+
+ it('is properly set in a nested Nvim instance when background=light', function()
+ command('highlight clear Normal')
+ command('set background=light') -- set outer Nvim background
+ local screen = thelpers.setup_child_nvim({
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--cmd',
+ 'colorscheme vim',
+ '--cmd',
+ 'set noswapfile',
+ })
+ retry(nil, 30000, function() -- wait for automatic background processing
+ screen:sleep(20)
+ feed_command('set background?') -- check nested Nvim background
+ screen:expect([[
+ {1: } |
+ {3:~} |
+ {3:~} |
+ {3:~} |
+ {5:[No Name] 0,0-1 All}|
+ background=light |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+ end)
+
+ it('queries the terminal for background color', function()
exec_lua([[
vim.api.nvim_create_autocmd('TermRequest', {
callback = function(args)
@@ -2791,8 +2855,7 @@ describe('TUI bg color', function()
end,
})
]])
-
- screen = thelpers.setup_child_nvim({
+ thelpers.setup_child_nvim({
'-u',
'NONE',
'-i',
@@ -2800,109 +2863,38 @@ describe('TUI bg color', function()
'--cmd',
'colorscheme vim',
'--cmd',
- 'set noswapfile notermguicolors',
- '-c',
- 'autocmd OptionSet background echo "did OptionSet, yay!"',
+ 'set noswapfile',
})
- end
-
- before_each(setup_bg_test)
-
- it('queries the terminal for background color', function()
retry(nil, 1000, function()
eq(true, eval("get(g:, 'oscrequest', v:false)"))
end)
end)
- it('triggers OptionSet event on unsplit terminal-response', function()
- screen:expect([[
- {1: } |
- {4:~ }|*3
- {5:[No Name] 0,0-1 All}|
- |
- {3:-- TERMINAL --} |
- ]])
- feed_data('\027]11;rgb:ffff/ffff/ffff\027\\')
- screen:expect { any = 'did OptionSet, yay!' }
-
- feed_data(':echo "new_bg=".&background\n')
- screen:expect { any = 'new_bg=light' }
-
- setup_bg_test()
- screen:expect([[
- {1: } |
- {4:~ }|*3
- {5:[No Name] 0,0-1 All}|
- |
- {3:-- TERMINAL --} |
- ]])
- feed_data('\027]11;rgba:ffff/ffff/ffff/8000\027\\')
- screen:expect { any = 'did OptionSet, yay!' }
-
- feed_data(':echo "new_bg=".&background\n')
- screen:expect { any = 'new_bg=light' }
- end)
-
- it('triggers OptionSet event with split terminal-response', function()
- screen:expect([[
- {1: } |
- {4:~ }|*3
- {5:[No Name] 0,0-1 All}|
- |
- {3:-- TERMINAL --} |
- ]])
- -- Send a background response with the OSC command part split.
- feed_data('\027]11;rgb')
- feed_data(':ffff/ffff/ffff\027\\')
- screen:expect { any = 'did OptionSet, yay!' }
-
- feed_data(':echo "new_bg=".&background\n')
- screen:expect { any = 'new_bg=light' }
-
- setup_bg_test()
- screen:expect([[
- {1: } |
- {4:~ }|*3
- {5:[No Name] 0,0-1 All}|
- |
- {3:-- TERMINAL --} |
- ]])
- -- Send a background response with the Pt portion split.
- feed_data('\027]11;rgba:ffff/fff')
- feed_data('f/ffff/8000\027\\')
- screen:expect { any = 'did OptionSet, yay!' }
-
- feed_data(':echo "new_bg=".&background\n')
- screen:expect { any = 'new_bg=light' }
- end)
-
- it('not triggers OptionSet event with invalid terminal-response', function()
- screen:expect([[
- {1: } |
- {4:~ }|*3
- {5:[No Name] 0,0-1 All}|
- |
- {3:-- TERMINAL --} |
- ]])
- feed_data('\027]11;rgb:ffff/ffff/ffff/8000\027\\')
- screen:expect_unchanged()
-
- feed_data(':echo "new_bg=".&background\n')
- screen:expect { any = 'new_bg=dark' }
-
- setup_bg_test()
- screen:expect([[
+ it('triggers OptionSet from automatic background processing', function()
+ local screen = thelpers.setup_child_nvim({
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--cmd',
+ 'colorscheme vim',
+ '--cmd',
+ 'set noswapfile',
+ '-c',
+ 'autocmd OptionSet background echo "did OptionSet, yay!"',
+ })
+ retry(nil, 30000, function() -- wait for automatic background processing
+ screen:sleep(20)
+ screen:expect([[
{1: } |
- {4:~ }|*3
+ {3:~} |
+ {3:~} |
+ {3:~} |
{5:[No Name] 0,0-1 All}|
- |
+ did OptionSet, yay! |
{3:-- TERMINAL --} |
- ]])
- feed_data('\027]11;rgba:ffff/foo/ffff/8000\027\\')
- screen:expect_unchanged()
-
- feed_data(':echo "new_bg=".&background\n')
- screen:expect { any = 'new_bg=dark' }
+ ]])
+ end)
end)
end)