feat(tui): update 'background' on theme change events (#31350)

Enabling private DEC mode 2031 tells the terminal to notify Nvim
whenever the OS theme changes (i.e. light mode to dark mode or vice
versa) or the terminal emulator's palette changes. When we receive one
of these notifications we query the terminal color's background color
again to see if it has changed and update the value of 'background' if
it has.

We only do this though if the user has not explicitly set the value of
'bg' themselves. The help text is updated slightly to hint to users that
they probably shouldn't set this value: on modern terminal emulators
Nvim is able to completely determine this automatically.
This commit is contained in:
Gregory Anders
2024-11-26 14:22:01 -06:00
committed by GitHub
parent 99b5ffd688
commit d460928263
6 changed files with 101 additions and 28 deletions

View File

@@ -546,8 +546,9 @@ do
---
--- @param option string Option name
--- @param value any Option value
local function setoption(option, value)
if vim.api.nvim_get_option_info2(option, {}).was_set then
--- @param force boolean? Always set the value, even if already set
local function setoption(option, value, force)
if not force and vim.api.nvim_get_option_info2(option, {}).was_set then
-- Don't do anything if option is already set
return
end
@@ -563,7 +564,7 @@ do
once = true,
nested = true,
callback = function()
setoption(option, value)
setoption(option, value, force)
end,
})
end
@@ -645,11 +646,15 @@ do
return nil, nil, nil
end
local timer = assert(vim.uv.new_timer())
-- This autocommand updates the value of 'background' anytime we receive
-- an OSC 11 response from the terminal emulator. If the user has set
-- 'background' explictly then we will delete this autocommand,
-- effectively disabling automatic background setting.
local force = false
local id = vim.api.nvim_create_autocmd('TermResponse', {
group = group,
nested = true,
desc = "Update the value of 'background' automatically based on the terminal emulator's background color",
callback = function(args)
local resp = args.data ---@type string
local r, g, b = parseosc11(resp)
@@ -661,27 +666,33 @@ do
if rr and gg and bb then
local luminance = (0.299 * rr) + (0.587 * gg) + (0.114 * bb)
local bg = luminance < 0.5 and 'dark' or 'light'
setoption('background', bg)
end
setoption('background', bg, force)
return true
-- On the first query response, don't force setting the option in
-- case the user has already set it manually. If they have, then
-- this autocommand will be deleted. If they haven't, then we do
-- want to force setting the option to override the value set by
-- this autocommand.
if not force then
force = true
end
end
end
end,
})
vim.api.nvim_create_autocmd('VimEnter', {
group = group,
nested = true,
once = true,
callback = function()
if vim.api.nvim_get_option_info2('background', {}).was_set then
vim.api.nvim_del_autocmd(id)
end
end,
})
io.stdout:write('\027]11;?\007')
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
--- If the TUI (term_has_truecolor) was able to determine that the host