From e2e63bd045491f36e12c924fddbe76b3ef884b38 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Thu, 22 Feb 2024 09:39:32 +0100 Subject: [PATCH] fix(lua): make highlight.on_yank use win-local highlight (#27349) Currently, highlight.on_yank() does buffer-local highlighting, this PR makes it window scoped. Also fix the problem that when yanking in a buffer, moving to another buffer, and yanking before the original buffer highlight disappears, the original buffer highlight won't disappear on timeout. --- runtime/lua/vim/highlight.lua | 22 ++++++++++++------ test/functional/lua/highlight_spec.lua | 32 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index 1d04f95d2d..b055cce49d 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -55,6 +55,7 @@ function M.range(bufnr, ns, higroup, start, finish, opts) local regtype = opts.regtype or 'v' local inclusive = opts.inclusive or false local priority = opts.priority or M.priorities.user + local scoped = opts._scoped or false -- TODO: in case of 'v', 'V' (not block), this should calculate equivalent -- bounds (row, col, end_row, end_col) as multiline regions are natively @@ -72,12 +73,14 @@ function M.range(bufnr, ns, higroup, start, finish, opts) end_col = cols[2], priority = priority, strict = false, + scoped = scoped, }) end end local yank_ns = api.nvim_create_namespace('hlyank') local yank_timer +local yank_cancel --- Highlight the yanked text --- @@ -120,24 +123,29 @@ function M.on_yank(opts) local higroup = opts.higroup or 'IncSearch' local timeout = opts.timeout or 150 - local bufnr = api.nvim_get_current_buf() - api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1) + local bufnr = vim.api.nvim_get_current_buf() + local winid = vim.api.nvim_get_current_win() if yank_timer then yank_timer:close() + yank_cancel() end M.range(bufnr, yank_ns, higroup, "'[", "']", { regtype = event.regtype, inclusive = event.inclusive, priority = opts.priority or M.priorities.user, + _scoped = true, }) + vim.api.nvim_win_add_ns(winid, yank_ns) - yank_timer = vim.defer_fn(function() + yank_cancel = function() yank_timer = nil - if api.nvim_buf_is_valid(bufnr) then - api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1) - end - end, timeout) + yank_cancel = nil + pcall(vim.api.nvim_buf_clear_namespace, bufnr, yank_ns, 0, -1) + pcall(vim.api.nvim_win_remove_ns, winid, yank_ns) + end + + yank_timer = vim.defer_fn(yank_cancel, timeout) end return M diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index f304bec411..197f3139f3 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -1,9 +1,11 @@ local helpers = require('test.functional.helpers')(after_each) local exec_lua = helpers.exec_lua local eq = helpers.eq +local neq = helpers.neq local eval = helpers.eval local command = helpers.command local clear = helpers.clear +local api = helpers.api describe('vim.highlight.on_yank', function() before_each(function() @@ -31,4 +33,34 @@ describe('vim.highlight.on_yank', function() ]]) eq('', eval('v:errmsg')) end) + + it('does not show in another window', function() + command('vsplit') + exec_lua([[ + vim.api.nvim_buf_set_mark(0,"[",1,1,{}) + vim.api.nvim_buf_set_mark(0,"]",1,1,{}) + vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) + ]]) + neq({}, api.nvim_win_get_ns(0)) + command('wincmd w') + eq({}, api.nvim_win_get_ns(0)) + end) + + it('removes old highlight if new one is created before old one times out', function() + command('vnew') + exec_lua([[ + vim.api.nvim_buf_set_mark(0,"[",1,1,{}) + vim.api.nvim_buf_set_mark(0,"]",1,1,{}) + vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) + ]]) + neq({}, api.nvim_win_get_ns(0)) + command('wincmd w') + exec_lua([[ + vim.api.nvim_buf_set_mark(0,"[",1,1,{}) + vim.api.nvim_buf_set_mark(0,"]",1,1,{}) + vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) + ]]) + command('wincmd w') + eq({}, api.nvim_win_get_ns(0)) + end) end)