mirror of
https://github.com/neovim/neovim.git
synced 2026-05-24 05:40:08 +00:00
feat(vim.hl): vim.hl.hl_op() #39777
Problem: vim.hl.on_yank() only works for TextYankPost, not TextPutPost. Solution: Introduce hl_op(). Deprecate on_yank().
This commit is contained in:
@@ -27,6 +27,10 @@ API
|
||||
EVENTS
|
||||
• *BufModifiedSet* Use |OptionSet| with pattern "modified" instead.
|
||||
|
||||
HIGHLIGHTS
|
||||
|
||||
• vim.hl.on_yank() Use |vim.hl.hl_op()| instead.
|
||||
|
||||
LUA
|
||||
|
||||
• vim.F.if_nil() Renamed to |vim.nonnil()|
|
||||
|
||||
@@ -2954,21 +2954,23 @@ vim.glob.to_lpeg({pattern}) *vim.glob.to_lpeg()*
|
||||
==============================================================================
|
||||
Lua module: vim.hl *vim.hl*
|
||||
|
||||
vim.hl.on_yank({opts}) *vim.hl.on_yank()*
|
||||
Highlight the yanked text during a |TextYankPost| event.
|
||||
vim.hl.hl_op({opts}) *vim.hl.hl_op()*
|
||||
Highlight the related text region during a |TextYankPost| or |TextPutPost|
|
||||
event.
|
||||
|
||||
Add the following to your `init.vim`: >vim
|
||||
autocmd TextYankPost * silent! lua vim.hl.on_yank {higroup='Visual', timeout=300}
|
||||
autocmd TextYankPost * silent! lua vim.hl.hl_op {higroup='Visual', timeout=300}
|
||||
autocmd TextPutPost * silent! lua vim.hl.hl_op {higroup='Visual', timeout=300}
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {opts} (`table?`) Optional parameters
|
||||
• event event structure (default vim.v.event)
|
||||
• higroup highlight group for yanked region (default
|
||||
• higroup highlight group for the text region (default
|
||||
"IncSearch")
|
||||
• on_macro highlight when executing macro (default false)
|
||||
• on_visual highlight when yanking visual selection (default
|
||||
true)
|
||||
• on_visual highlight when the event is in |Visual| mode
|
||||
(default true)
|
||||
• priority integer priority (default
|
||||
|vim.hl.priorities|`.user`)
|
||||
• timeout time in ms before highlight is cleared (default 150)
|
||||
@@ -2980,7 +2982,7 @@ vim.hl.priorities *vim.hl.priorities*
|
||||
• `semantic_tokens`: `125`, used for LSP semantic token highlighting
|
||||
• `diagnostics`: `150`, used for code analysis such as diagnostics
|
||||
• `user`: `200`, used for user-triggered highlights such as LSP document
|
||||
symbols or `on_yank` autocommands
|
||||
symbols or `hl_op` autocommands
|
||||
|
||||
*vim.hl.range()*
|
||||
vim.hl.range({buf}, {ns}, {higroup}, {start}, {finish}, {opts})
|
||||
|
||||
@@ -153,6 +153,8 @@ EVENTS
|
||||
HIGHLIGHTS
|
||||
|
||||
• `Dimmed` for text that should be de-emphasized.
|
||||
• |vim.hl.hl_op()| highlights text regions for |TextYankPost| and
|
||||
|TextPutPost| events. It replaces the now deprecated `vim.hl.on_yank()`.
|
||||
|
||||
LSP
|
||||
|
||||
|
||||
@@ -60,11 +60,11 @@ vim.keymap.set({ 'n' }, '<A-l>', '<C-w>l')
|
||||
-- See `:h lua-guide-autocommands`, `:h autocmd`, `:h nvim_create_autocmd()`
|
||||
|
||||
-- Highlight when yanking (copying) text.
|
||||
-- Try it with `yap` in normal mode. See `:h vim.hl.on_yank()`
|
||||
-- Try it with `yap` in normal mode. See `:h vim.hl.hl_op()`
|
||||
vim.api.nvim_create_autocmd('TextYankPost', {
|
||||
desc = 'Highlight when yanking (copying) text',
|
||||
callback = function()
|
||||
vim.hl.on_yank()
|
||||
vim.hl.hl_op()
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ local M = {}
|
||||
--- - `semantic_tokens`: `125`, used for LSP semantic token highlighting
|
||||
--- - `diagnostics`: `150`, used for code analysis such as diagnostics
|
||||
--- - `user`: `200`, used for user-triggered highlights such as LSP document
|
||||
--- symbols or `on_yank` autocommands
|
||||
--- symbols or `hl_op` autocommands
|
||||
M.priorities = {
|
||||
syntax = 50,
|
||||
treesitter = 100,
|
||||
@@ -144,26 +144,34 @@ function M.range(buf, ns, higroup, start, finish, opts)
|
||||
end
|
||||
end
|
||||
|
||||
local yank_timer --- @type uv.uv_timer_t?
|
||||
local yank_hl_clear --- @type fun()?
|
||||
local yank_ns = api.nvim_create_namespace('nvim.hlyank')
|
||||
---@private
|
||||
---@class (private) vim.hl.OnEventState
|
||||
---@field timer? uv.uv_timer_t Timer to clear the highlight.
|
||||
---@field clear? fun() Function to clear the highlight immediately.
|
||||
|
||||
--- Highlight the yanked text during a |TextYankPost| event.
|
||||
--- @type { [string]: vim.hl.OnEventState }
|
||||
local hl_op_state = {}
|
||||
|
||||
local events_ns = api.nvim_create_namespace('nvim.hl.events')
|
||||
|
||||
--- Highlight the related text region during a |TextYankPost| or |TextPutPost|
|
||||
--- event.
|
||||
---
|
||||
--- Add the following to your `init.vim`:
|
||||
---
|
||||
--- ```vim
|
||||
--- autocmd TextYankPost * silent! lua vim.hl.on_yank {higroup='Visual', timeout=300}
|
||||
--- autocmd TextYankPost * silent! lua vim.hl.hl_op {higroup='Visual', timeout=300}
|
||||
--- autocmd TextPutPost * silent! lua vim.hl.hl_op {higroup='Visual', timeout=300}
|
||||
--- ```
|
||||
---
|
||||
--- @param opts table|nil Optional parameters
|
||||
--- - event event structure (default vim.v.event)
|
||||
--- - higroup highlight group for yanked region (default "IncSearch")
|
||||
--- - higroup highlight group for the text region (default "IncSearch")
|
||||
--- - on_macro highlight when executing macro (default false)
|
||||
--- - on_visual highlight when yanking visual selection (default true)
|
||||
--- - on_visual highlight when the event is in |Visual| mode (default true)
|
||||
--- - priority integer priority (default |vim.hl.priorities|`.user`)
|
||||
--- - timeout time in ms before highlight is cleared (default 150)
|
||||
function M.on_yank(opts)
|
||||
function M.hl_op(opts)
|
||||
vim.validate('opts', opts, 'table', true)
|
||||
opts = opts or {}
|
||||
local event = opts.event or vim.v.event
|
||||
@@ -173,31 +181,52 @@ function M.on_yank(opts)
|
||||
if not on_macro and vim.fn.reg_executing() ~= '' then
|
||||
return
|
||||
end
|
||||
if event.operator ~= 'y' or event.regtype == '' then
|
||||
if event.regtype == '' then
|
||||
return
|
||||
end
|
||||
if not on_visual and event.visual then
|
||||
return
|
||||
end
|
||||
|
||||
local state_key --- @type string
|
||||
if event.operator == 'y' then
|
||||
state_key = 'yank'
|
||||
elseif event.operator == 'p' or event.operator == 'P' then
|
||||
state_key = 'put'
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
local higroup = opts.higroup or 'IncSearch'
|
||||
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local winid = api.nvim_get_current_win()
|
||||
|
||||
if yank_timer and not yank_timer:is_closing() then
|
||||
yank_timer:close()
|
||||
assert(yank_hl_clear)
|
||||
yank_hl_clear()
|
||||
local state = hl_op_state[state_key]
|
||||
if state ~= nil and state.timer and not state.timer:is_closing() then
|
||||
state.timer:close()
|
||||
assert(state.clear)
|
||||
state.clear()
|
||||
end
|
||||
|
||||
api.nvim__ns_set(yank_ns, { wins = { winid } })
|
||||
yank_timer, yank_hl_clear = M.range(bufnr, yank_ns, higroup, "'[", "']", {
|
||||
api.nvim__ns_set(events_ns, { wins = { winid } })
|
||||
local timer, clear = M.range(bufnr, events_ns, higroup, "'[", "']", {
|
||||
regtype = event.regtype,
|
||||
inclusive = true,
|
||||
priority = opts.priority or M.priorities.user,
|
||||
timeout = opts.timeout or 150,
|
||||
})
|
||||
|
||||
hl_op_state[state_key] = {
|
||||
timer = timer,
|
||||
clear = clear,
|
||||
}
|
||||
end
|
||||
|
||||
--- @deprecated Please use |vim.hl.hl_op()| instead.
|
||||
function M.on_yank(opts)
|
||||
vim.deprecate('vim.hl.on_yank', 'vim.hl.hl_op', '0.13')
|
||||
return M.hl_op(opts)
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -215,7 +215,7 @@ describe('vim.hl.range', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('vim.hl.on_yank', function()
|
||||
describe('vim.hl.hl_op', function()
|
||||
before_each(function()
|
||||
clear()
|
||||
end)
|
||||
@@ -224,7 +224,7 @@ describe('vim.hl.on_yank', function()
|
||||
command('new')
|
||||
n.feed('ifoo<esc>') -- set '[, ']
|
||||
exec_lua(function()
|
||||
vim.hl.on_yank({
|
||||
vim.hl.hl_op({
|
||||
timeout = 10,
|
||||
on_macro = true,
|
||||
event = { operator = 'y', regtype = 'v' },
|
||||
@@ -238,10 +238,10 @@ describe('vim.hl.on_yank', function()
|
||||
|
||||
it('does not close timer twice', function()
|
||||
exec_lua(function()
|
||||
vim.hl.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } })
|
||||
vim.hl.hl_op({ timeout = 10, on_macro = true, event = { operator = 'y' } })
|
||||
vim.uv.sleep(10)
|
||||
vim.schedule(function()
|
||||
vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } })
|
||||
vim.hl.hl_op({ timeout = 0, on_macro = true, event = { operator = 'y' } })
|
||||
end)
|
||||
end)
|
||||
eq('', eval('v:errmsg'))
|
||||
@@ -252,16 +252,16 @@ describe('vim.hl.on_yank', function()
|
||||
exec_lua(function()
|
||||
vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
|
||||
vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
|
||||
vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
|
||||
vim.hl.hl_op({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
|
||||
end)
|
||||
local ns = api.nvim_create_namespace('nvim.hlyank')
|
||||
local ns = api.nvim_create_namespace('nvim.hl.events')
|
||||
local win = api.nvim_get_current_win()
|
||||
eq({ win }, api.nvim__ns_get(ns).wins)
|
||||
command('wincmd w')
|
||||
eq({ win }, api.nvim__ns_get(ns).wins)
|
||||
-- Use a new vim.hl.on_yank() call to cancel the previous timer
|
||||
-- Use a new vim.hl.hl_op() call to cancel the previous timer
|
||||
exec_lua(function()
|
||||
vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } })
|
||||
vim.hl.hl_op({ timeout = 0, on_macro = true, event = { operator = 'y' } })
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -270,23 +270,23 @@ describe('vim.hl.on_yank', function()
|
||||
exec_lua(function()
|
||||
vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
|
||||
vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
|
||||
vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
|
||||
vim.hl.hl_op({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
|
||||
end)
|
||||
local ns = api.nvim_create_namespace('nvim.hlyank')
|
||||
local ns = api.nvim_create_namespace('nvim.hl.events')
|
||||
eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1])
|
||||
command('wincmd w')
|
||||
exec_lua(function()
|
||||
vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
|
||||
vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
|
||||
vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
|
||||
vim.hl.hl_op({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
|
||||
end)
|
||||
local win = api.nvim_get_current_win()
|
||||
eq({ win }, api.nvim__ns_get(ns).wins)
|
||||
command('wincmd w')
|
||||
eq({ win }, api.nvim__ns_get(ns).wins)
|
||||
-- Use a new vim.hl.on_yank() call to cancel the previous timer
|
||||
-- Use a new vim.hl.hl_op() call to cancel the previous timer
|
||||
exec_lua(function()
|
||||
vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } })
|
||||
vim.hl.hl_op({ timeout = 0, on_macro = true, event = { operator = 'y' } })
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -295,7 +295,7 @@ describe('vim.hl.on_yank', function()
|
||||
screen:add_extra_attr_ids({
|
||||
[100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true },
|
||||
})
|
||||
command('autocmd TextYankPost * lua vim.hl.on_yank{timeout=100000}')
|
||||
command('autocmd TextYankPost * lua vim.hl.hl_op{timeout=100000}')
|
||||
api.nvim_buf_set_lines(0, 0, -1, true, {
|
||||
[[foo(bar) 'baz']],
|
||||
[[foo(bar) 'baz']],
|
||||
@@ -321,9 +321,32 @@ describe('vim.hl.on_yank', function()
|
||||
{1:~ }|
|
||||
|
|
||||
]])
|
||||
-- Use a new vim.hl.on_yank() call to cancel the previous timer
|
||||
-- Use a new vim.hl.hl_op() call to cancel the previous timer
|
||||
exec_lua(function()
|
||||
vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } })
|
||||
vim.hl.hl_op({ timeout = 0, on_macro = true, event = { operator = 'y' } })
|
||||
end)
|
||||
end)
|
||||
|
||||
it('highlights TextPutPost', function()
|
||||
local screen = Screen.new(60, 4)
|
||||
screen:add_extra_attr_ids({
|
||||
[100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true },
|
||||
})
|
||||
command('autocmd TextPutPost * lua vim.hl.hl_op{timeout=100000}')
|
||||
api.nvim_buf_set_lines(0, 0, -1, true, {
|
||||
[[foo(bar) '1']],
|
||||
[[foo(bar) '2']],
|
||||
})
|
||||
n.feed('ggyyp')
|
||||
screen:expect([[
|
||||
foo(bar) '1' |
|
||||
{2:^foo(bar) '1'} |
|
||||
foo(bar) '2' |
|
||||
|
|
||||
]])
|
||||
-- Use a new vim.hl.hl_op() call to cancel the previous timer
|
||||
exec_lua(function()
|
||||
vim.hl.hl_op({ timeout = 0, on_macro = true, event = { operator = 'p' } })
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user