mirror of
https://github.com/neovim/neovim.git
synced 2026-07-13 12:50:31 +00:00
refactor(tty): tty.request() #39489
Problem: - Various `TermRequest` handlers which all do similar things. - `tty.query` is specific to `XTGETTCAP DCS`, can't be reused for other kinds of terminal queries. Solution: Provide `tty.request()`.
This commit is contained in:
@@ -914,57 +914,55 @@ do
|
||||
return nil, nil, nil
|
||||
end
|
||||
|
||||
-- This autocommand updates the value of 'background' anytime we receive
|
||||
-- an OSC 11 response from the terminal emulator. If the user has set
|
||||
-- 'background' explicitly then we will delete this autocommand,
|
||||
-- effectively disabling automatic background setting.
|
||||
-- Send OSC 11 query along with DSR sequence to determine whether terminal supports the query.
|
||||
-- If the DSR response comes first, the terminal most likely doesn't support the bg color
|
||||
-- query, and we don't have to keep waiting for a bg color response. #32109
|
||||
local osc11 = '\027]11;?\007'
|
||||
local dsr = '\027[5n'
|
||||
|
||||
-- This handler updates the value of 'background' anytime we receive an OSC 11 response from
|
||||
-- the terminal emulator. If the user has set 'background' explicitly then we will delete the
|
||||
-- autocommand below, effectively disabling automatic background setting.
|
||||
local did_dsr_response = 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(ev)
|
||||
local resp = ev.data.sequence ---@type string
|
||||
-- VimEnter handles cleanup; no built-in timeout.
|
||||
local id = vim.tty.request(osc11 .. dsr, { group = group, timeout = 0 }, function(resp)
|
||||
-- DSR response that should come after the OSC 11 response if the
|
||||
-- terminal supports it.
|
||||
if string.match(resp, '^\027%[0n$') then
|
||||
did_dsr_response = true
|
||||
-- Don't stop listening: the bg response may come after the DSR response if the terminal
|
||||
-- handles requests out of sequence. In that case, the bg will simply be set later in the
|
||||
-- startup sequence.
|
||||
return
|
||||
end
|
||||
|
||||
-- DSR response that should come after the OSC 11 response if the
|
||||
-- terminal supports it.
|
||||
if string.match(resp, '^\027%[0n$') then
|
||||
did_dsr_response = true
|
||||
-- Don't delete the autocmd because the bg response may come
|
||||
-- after the DSR response if the terminal handles requests out
|
||||
-- of sequence. In that case, the background will simply be set
|
||||
-- later in the startup sequence.
|
||||
return false
|
||||
end
|
||||
local r, g, b = parseosc11(resp)
|
||||
if r and g and b then
|
||||
local rr = parsecolor(r)
|
||||
local gg = parsecolor(g)
|
||||
local bb = parsecolor(b)
|
||||
|
||||
local r, g, b = parseosc11(resp)
|
||||
if r and g and b then
|
||||
local rr = parsecolor(r)
|
||||
local gg = parsecolor(g)
|
||||
local bb = parsecolor(b)
|
||||
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'
|
||||
vim.api.nvim_set_option_value('background', bg, {})
|
||||
|
||||
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'
|
||||
vim.api.nvim_set_option_value('background', bg, {})
|
||||
|
||||
-- Ensure OptionSet still triggers when we set the background during startup
|
||||
if vim.v.vim_did_enter == 0 then
|
||||
vim.api.nvim_create_autocmd('VimEnter', {
|
||||
group = group,
|
||||
once = true,
|
||||
nested = true,
|
||||
callback = function()
|
||||
vim.api.nvim_exec_autocmds('OptionSet', {
|
||||
pattern = 'background',
|
||||
})
|
||||
end,
|
||||
})
|
||||
end
|
||||
-- Ensure OptionSet still triggers when we set the background during startup
|
||||
if vim.v.vim_did_enter == 0 then
|
||||
vim.api.nvim_create_autocmd('VimEnter', {
|
||||
group = group,
|
||||
once = true,
|
||||
nested = true,
|
||||
callback = function()
|
||||
vim.api.nvim_exec_autocmds('OptionSet', {
|
||||
pattern = 'background',
|
||||
})
|
||||
end,
|
||||
})
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
||||
vim.api.nvim_create_autocmd('VimEnter', {
|
||||
group = group,
|
||||
@@ -983,15 +981,6 @@ do
|
||||
end,
|
||||
})
|
||||
|
||||
-- Send OSC 11 query along with DSR sequence to determine whether
|
||||
-- terminal supports the query. If the DSR response comes first,
|
||||
-- the terminal most likely doesn't support the bg color query,
|
||||
-- and we don't have to keep waiting for a bg color response.
|
||||
-- #32109
|
||||
local osc11 = '\027]11;?\007'
|
||||
local dsr = '\027[5n'
|
||||
vim.api.nvim_ui_send(osc11 .. dsr)
|
||||
|
||||
-- Wait until detection of OSC 11 capabilities is complete to
|
||||
-- ensure background is automatically set before user config.
|
||||
if
|
||||
@@ -1024,7 +1013,7 @@ do
|
||||
-- Neither the TUI nor $COLORTERM indicate that truecolor is supported, so query the
|
||||
-- terminal
|
||||
local caps = {} ---@type table<string, boolean>
|
||||
require('vim.tty').query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found)
|
||||
vim.tty.query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found)
|
||||
if not found then
|
||||
return
|
||||
end
|
||||
@@ -1035,77 +1024,57 @@ do
|
||||
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', {
|
||||
group = group,
|
||||
nested = true,
|
||||
callback = function(ev)
|
||||
local resp = ev.data.sequence ---@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 false
|
||||
end
|
||||
|
||||
-- The returned SGR sequence should begin with 48:2
|
||||
local sgr = assert(attrs[#attrs]):match('^48:2:([%d:]+)$')
|
||||
if not sgr then
|
||||
return false
|
||||
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
|
||||
vim._tointeger(params[#params - 2]) == r
|
||||
and vim._tointeger(params[#params - 1]) == g
|
||||
and vim._tointeger(params[#params]) == b
|
||||
then
|
||||
setoption('termguicolors', true)
|
||||
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\\'
|
||||
|
||||
--
|
||||
-- Reset attributes first, as other code may have set attributes.
|
||||
vim.api.nvim_ui_send(string.format('\027[0m\027[48;2;%d;%d;%dm%s', r, g, b, decrqss))
|
||||
local payload = ('\027[0m\027[48;2;%d;%d;%dm%s'):format(r, g, b, '\027P$qm\027\\')
|
||||
|
||||
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()
|
||||
vim.tty.request(payload, { group = group }, function(resp)
|
||||
local decrqss = resp:match('^\027P1%$r([%d;:]+)m$')
|
||||
if not decrqss then
|
||||
return
|
||||
end
|
||||
|
||||
-- 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
|
||||
end
|
||||
|
||||
-- The returned SGR sequence should begin with 48:2
|
||||
local sgr = assert(attrs[#attrs]):match('^48:2:([%d:]+)$')
|
||||
if not sgr then
|
||||
return
|
||||
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
|
||||
vim._tointeger(params[#params - 2]) == r
|
||||
and vim._tointeger(params[#params - 1]) == g
|
||||
and vim._tointeger(params[#params]) == b
|
||||
then
|
||||
setoption('termguicolors', true)
|
||||
end
|
||||
|
||||
return true
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -60,6 +60,7 @@ vim._submodules = {
|
||||
iter = true,
|
||||
re = true,
|
||||
text = true,
|
||||
tty = true,
|
||||
provider = true,
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ vim.secure = require('vim.secure')
|
||||
vim.snippet = require('vim.snippet')
|
||||
vim.text = require('vim.text')
|
||||
vim.treesitter = require('vim.treesitter')
|
||||
vim.tty = require('vim.tty')
|
||||
vim.ui = require('vim.ui')
|
||||
vim.version = require('vim.version')
|
||||
|
||||
|
||||
@@ -1,5 +1,67 @@
|
||||
local M = {}
|
||||
|
||||
--- Send `payload` to the host terminal and listen for `TermResponse`, calling `on_response` for
|
||||
--- each response. Cleans up after `opts.timeout` ms if the callback never returns `true`.
|
||||
---
|
||||
--- The autocommand is removed when:
|
||||
--- - `on_response()` returns `true`
|
||||
--- - the timeout fires (and `opts.on_timeout` is called, if given)
|
||||
--- - the caller explicitly deletes the returned autocmd id
|
||||
---
|
||||
---@param payload string Sequence to send via nvim_ui_send(). Use empty string ('') to just register
|
||||
--- a listener (no sending).
|
||||
---@param opts? { timeout?: integer, on_timeout?: fun(), group?: integer|string }
|
||||
--- - `timeout` (default: 1000) ms to wait before giving up, or 0 for never (caller must remove the autocmd).
|
||||
--- - `on_timeout` optional fn called when the timeout fires.
|
||||
--- - `group`: augroup for the TermResponse autocmd.
|
||||
---@param on_response fun(resp:string):boolean? Called for each TermResponse. Return `true` to stop listening.
|
||||
---@return integer # autocmd id of the TermResponse handler.
|
||||
function M.request(payload, opts, on_response)
|
||||
vim.validate('payload', payload, 'string')
|
||||
vim.validate('opts', opts, 'table', true)
|
||||
vim.validate('on_response', on_response, 'function')
|
||||
|
||||
opts = opts or {}
|
||||
local timeout = opts.timeout or 1000
|
||||
local timer ---@type uv.uv_timer_t?
|
||||
if timeout > 0 then
|
||||
timer = assert(vim.uv.new_timer())
|
||||
end
|
||||
|
||||
local id = vim.api.nvim_create_autocmd('TermResponse', {
|
||||
group = opts.group,
|
||||
nested = true,
|
||||
callback = function(ev)
|
||||
local stop = on_response(ev.data.sequence)
|
||||
-- If on_response is done, cancel the timeout so on_timeout doesn't fire spuriously.
|
||||
if stop and timer and not timer:is_closing() then
|
||||
timer:close()
|
||||
end
|
||||
return stop
|
||||
end,
|
||||
})
|
||||
|
||||
if payload ~= '' then
|
||||
vim.api.nvim_ui_send(payload)
|
||||
end
|
||||
|
||||
if timer then
|
||||
timer:start(timeout, 0, function()
|
||||
vim.schedule(function()
|
||||
pcall(vim.api.nvim_del_autocmd, id)
|
||||
if opts.on_timeout then
|
||||
opts.on_timeout()
|
||||
end
|
||||
end)
|
||||
if not timer:is_closing() then
|
||||
timer:close()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return id
|
||||
end
|
||||
|
||||
--- Query the host terminal emulator for terminfo capabilities.
|
||||
---
|
||||
--- This function sends the XTGETTCAP DCS sequence to the host terminal emulator asking the terminal
|
||||
@@ -12,13 +74,12 @@ local M = {}
|
||||
--- emulator supports the XTGETTCAP sequence.
|
||||
---
|
||||
--- @param caps string|table A terminal capability or list of capabilities to query
|
||||
--- @param cb fun(cap:string, found:boolean, 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)
|
||||
--- @param on_response fun(cap:string, found:boolean, seq:string?) Called for each capability in
|
||||
--- `caps`. `found` is true if the capability was found, else false. `seq` is the control
|
||||
--- sequence if found, or nil for boolean capabilities.
|
||||
function M.query(caps, on_response)
|
||||
vim.validate('caps', caps, { 'string', 'table' })
|
||||
vim.validate('cb', cb, 'function')
|
||||
vim.validate('on_response', on_response, 'function')
|
||||
|
||||
if type(caps) ~= 'table' then
|
||||
caps = { caps }
|
||||
@@ -29,112 +90,70 @@ function M.query(caps, cb)
|
||||
pending[v] = true
|
||||
end
|
||||
|
||||
local timer = assert(vim.uv.new_timer())
|
||||
|
||||
local id = vim.api.nvim_create_autocmd('TermResponse', {
|
||||
nested = true,
|
||||
callback = function(ev)
|
||||
local resp = ev.data.sequence ---@type string
|
||||
local k, rest = resp:match('^\027P1%+r(%x+)(.*)$')
|
||||
if k and rest then
|
||||
local cap = vim.text.hexdecode(k)
|
||||
if not cap or not pending[cap] then
|
||||
-- Received a response for a capability we didn't request. This can happen if there are
|
||||
-- multiple concurrent XTGETTCAP requests
|
||||
return
|
||||
end
|
||||
|
||||
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)
|
||||
|
||||
pending[cap] = nil
|
||||
|
||||
if next(pending) == nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
local encoded = {} ---@type string[]
|
||||
for i = 1, #caps do
|
||||
encoded[i] = vim.text.hexencode(caps[i])
|
||||
end
|
||||
local payload = ('\027P+q%s\027\\'):format(table.concat(encoded, ';'))
|
||||
|
||||
local query = string.format('\027P+q%s\027\\', table.concat(encoded, ';'))
|
||||
|
||||
vim.api.nvim_ui_send(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
|
||||
M.request(payload, {
|
||||
on_timeout = function()
|
||||
-- Call the callback for all capabilities that were not found.
|
||||
for k in pairs(pending) do
|
||||
cb(k, false, nil)
|
||||
on_response(k, false, nil)
|
||||
end
|
||||
end)
|
||||
|
||||
if not timer:is_closing() then
|
||||
timer:close()
|
||||
end,
|
||||
}, function(resp)
|
||||
local k, rest = resp:match('^\027P1%+r(%x+)(.*)$')
|
||||
if not k or not rest then
|
||||
return
|
||||
end
|
||||
local cap = vim.text.hexdecode(k)
|
||||
if not cap or not pending[cap] then
|
||||
-- Received a response for a capability we didn't request. This can happen if there are
|
||||
-- multiple concurrent XTGETTCAP requests
|
||||
return
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
on_response(cap, true, seq)
|
||||
pending[cap] = nil
|
||||
|
||||
return next(pending) == nil
|
||||
end)
|
||||
end
|
||||
|
||||
--- Send an APC sequence to the terminal and call {cb} for each APC response received.
|
||||
--- Send an APC sequence to the terminal and call `on_response` for each APC response received.
|
||||
--- Cleans up after {timeout} milliseconds if no response is received.
|
||||
---
|
||||
--- {cb} receives the full APC sequence including the `\027_` prefix.
|
||||
--- Return `true` from {cb} to stop listening.
|
||||
--- `on_response` receives the full APC sequence including the `\027_` prefix.
|
||||
--- Return `true` from `on_response` to stop listening.
|
||||
---
|
||||
---@param payload string APC sequence to send (full escape sequence including prefix/suffix)
|
||||
---@param opts {timeout?:integer} Options table (timeout in milliseconds, default 1000)
|
||||
---@param cb fun(resp:string):boolean? Callback invoked for each APC TermResponse
|
||||
---@overload fun(payload:string, cb:fun(resp:string):boolean?)
|
||||
function M.query_apc(payload, opts, cb)
|
||||
---@param on_response fun(resp:string):boolean? Callback invoked for each APC TermResponse
|
||||
---@overload fun(payload:string, on_response:fun(resp:string):boolean?)
|
||||
function M.query_apc(payload, opts, on_response)
|
||||
if type(opts) == 'function' then
|
||||
cb = opts
|
||||
on_response = opts
|
||||
opts = {}
|
||||
end
|
||||
|
||||
vim.validate('payload', payload, 'string')
|
||||
vim.validate('opts', opts, 'table')
|
||||
vim.validate('cb', cb, 'function')
|
||||
vim.validate('on_response', on_response, 'function')
|
||||
|
||||
local timeout = opts and opts.timeout or 1000
|
||||
local timer = assert(vim.uv.new_timer())
|
||||
|
||||
local id = vim.api.nvim_create_autocmd('TermResponse', {
|
||||
nested = true,
|
||||
callback = function(ev)
|
||||
local resp = ev.data.sequence ---@type string
|
||||
if resp:match('^\027_') then
|
||||
if not timer:is_closing() then
|
||||
timer:close()
|
||||
end
|
||||
return cb(resp)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_ui_send(payload)
|
||||
|
||||
timer:start(timeout, 0, function()
|
||||
vim.schedule(function()
|
||||
pcall(vim.api.nvim_del_autocmd, id)
|
||||
end)
|
||||
if not timer:is_closing() then
|
||||
timer:close()
|
||||
M.request(payload, opts, function(resp)
|
||||
if resp:match('^\027_') then
|
||||
return on_response(resp)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -22,23 +22,17 @@ function M.paste(reg)
|
||||
local clipboard = reg == '+' and 'c' or 'p'
|
||||
return function()
|
||||
local contents = nil --- @type string?
|
||||
local id = vim.api.nvim_create_autocmd('TermResponse', {
|
||||
callback = function(ev)
|
||||
local resp = ev.data.sequence ---@type string
|
||||
local encoded = resp:match('\027%]52;%w?;([A-Za-z0-9+/=]*)')
|
||||
if encoded then
|
||||
contents = vim.base64.decode(encoded)
|
||||
return true
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_ui_send(osc52(clipboard, '?'))
|
||||
|
||||
local ok, res
|
||||
-- timeout=0: we manage the staged 1s/9s timeout via vim.wait below.
|
||||
local id = vim.tty.request(osc52(clipboard, '?'), { timeout = 0 }, function(resp)
|
||||
local encoded = resp:match('\027%]52;%w?;([A-Za-z0-9+/=]*)')
|
||||
if encoded then
|
||||
contents = vim.base64.decode(encoded)
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
-- Wait 1s first for terminals that respond quickly
|
||||
ok, res = vim.wait(1000, function()
|
||||
local ok, res = vim.wait(1000, function()
|
||||
return contents ~= nil
|
||||
end)
|
||||
|
||||
@@ -55,7 +49,7 @@ function M.paste(reg)
|
||||
end
|
||||
|
||||
if not ok then
|
||||
vim.api.nvim_del_autocmd(id)
|
||||
pcall(vim.api.nvim_del_autocmd, id)
|
||||
if res == -1 then
|
||||
vim.notify(
|
||||
'Timed out waiting for a clipboard response from the terminal',
|
||||
|
||||
@@ -178,7 +178,7 @@ function M.supported(opts)
|
||||
---@type string?
|
||||
local msg
|
||||
|
||||
require('vim.tty').query_apc(
|
||||
vim.tty.query_apc(
|
||||
seq({ a = 'q', i = query_id, s = 1, v = 1 }),
|
||||
{ timeout = timeout },
|
||||
function(resp)
|
||||
|
||||
36
runtime/pack/dist/opt/nvim.tohtml/lua/tohtml.lua
vendored
36
runtime/pack/dist/opt/nvim.tohtml/lua/tohtml.lua
vendored
@@ -197,32 +197,22 @@ local len = vim.api.nvim_strwidth
|
||||
--- @param color "background"|"foreground"|integer
|
||||
--- @return string?
|
||||
local function try_query_terminal_color(color)
|
||||
local parameter = 4
|
||||
if color == 'foreground' then
|
||||
parameter = 10
|
||||
elseif color == 'background' then
|
||||
parameter = 11
|
||||
end
|
||||
local parameter = (color == 'foreground' and 10) or (color == 'background' and 11) or 4
|
||||
local payload = type(color) == 'number' and ('\027]%s;%s;?\027\\'):format(parameter, color)
|
||||
or ('\027]%s;?\027\\'):format(parameter)
|
||||
|
||||
--- @type string?
|
||||
local hex = nil
|
||||
local au = vim.api.nvim_create_autocmd('TermResponse', {
|
||||
once = true,
|
||||
callback = function(ev)
|
||||
hex = '#'
|
||||
.. table.concat({
|
||||
ev.data.sequence:match('\027%]%d+;%d*;?rgb:(%w%w)%w%w/(%w%w)%w%w/(%w%w)%w%w'),
|
||||
})
|
||||
end,
|
||||
})
|
||||
if type(color) == 'number' then
|
||||
vim.api.nvim_ui_send(('\027]%s;%s;?\027\\'):format(parameter, color))
|
||||
else
|
||||
vim.api.nvim_ui_send(('\027]%s;?\027\\'):format(parameter))
|
||||
end
|
||||
vim.wait(100, function()
|
||||
return hex and true or false
|
||||
vim.tty.request(payload, { timeout = 100 }, function(resp)
|
||||
local r, g, b = resp:match('\027%]%d+;%d*;?rgb:(%w%w)%w%w/(%w%w)%w%w/(%w%w)%w%w') ---@type string?, string?, string?
|
||||
if r and g and b then
|
||||
hex = '#' .. r .. g .. b
|
||||
return true
|
||||
end
|
||||
end)
|
||||
vim.wait(100, function()
|
||||
return hex ~= nil
|
||||
end)
|
||||
pcall(vim.api.nvim_del_autocmd, au)
|
||||
return hex
|
||||
end
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ vim.api.nvim_create_autocmd('UIEnter', {
|
||||
end
|
||||
|
||||
-- Fallback to XTGETTCAP
|
||||
require('vim.tty').query('Ms', function(cap, found, seq)
|
||||
vim.tty.query('Ms', function(cap, found, seq)
|
||||
if not found then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -78,6 +78,7 @@ pub fn nvim_gen_sources(
|
||||
"keymap",
|
||||
"loader",
|
||||
"text",
|
||||
"tty",
|
||||
};
|
||||
for (names) |n| {
|
||||
gen_step.addFileArg(b.path(b.fmt("runtime/lua/vim/{s}.lua", .{n})));
|
||||
|
||||
@@ -353,6 +353,7 @@ set(LUA_INSPECT_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/inspect.lua)
|
||||
set(LUA_KEYMAP_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/keymap.lua)
|
||||
set(LUA_LOADER_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/loader.lua)
|
||||
set(LUA_TEXT_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/text.lua)
|
||||
set(LUA_TTY_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/tty.lua)
|
||||
|
||||
# Find all Lua modules in the _core/ directory.
|
||||
file(GLOB LUA_CORE_MODULE_SOURCES ${NVIM_RUNTIME_DIR}/lua/vim/_core/*.lua)
|
||||
@@ -652,6 +653,7 @@ add_custom_command(
|
||||
${LUA_KEYMAP_MODULE_SOURCE} "vim.keymap"
|
||||
${LUA_LOADER_MODULE_SOURCE} "vim.loader"
|
||||
${LUA_TEXT_MODULE_SOURCE} "vim.text"
|
||||
${LUA_TTY_MODULE_SOURCE} "vim.tty"
|
||||
${LUA_CORE_COMMAND_ARGS}
|
||||
DEPENDS
|
||||
${CHAR_BLOB_GENERATOR}
|
||||
@@ -663,6 +665,7 @@ add_custom_command(
|
||||
${LUA_KEYMAP_MODULE_SOURCE}
|
||||
${LUA_LOADER_MODULE_SOURCE}
|
||||
${LUA_TEXT_MODULE_SOURCE}
|
||||
${LUA_TTY_MODULE_SOURCE}
|
||||
${LUA_CORE_MODULE_SOURCES}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
@@ -247,6 +247,7 @@ describe('vim._core', function()
|
||||
'vim.keymap',
|
||||
'vim.loader',
|
||||
'vim.text',
|
||||
'vim.tty',
|
||||
}
|
||||
if n.exec_lua [[return not not _G.jit]] then
|
||||
expected = vim.list_extend({
|
||||
|
||||
Reference in New Issue
Block a user