mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
lua: Add highlight.on_yank (#12279)
* add lua function to highlight yanked region * extract namespace, better naming, default values * add default for event argument * free timer * factor out mark to position calculation * d'oh * make sure timer stops before callback (cf. luv example) * factor out timer, more documentation * fixup * validate function argument for schedule * fix block selection past eol * correct handling of multibyte characters * move arguments around, some cleanup * move utility functions to vim.lua * use anonymous namespaces, avoid local api * rename function * add test for schedule_fn * fix indent * turn hl-yank into proper (hightlight) module * factor out position-to-region function mark extraction now part of highlight.on_yank * rename schedule_fn to defer_fn * add test for vim.region * todo: handle double-width characters * remove debug printout * do not shadow arguments * defer also callable table * whitespace change * move highlight to vim/highlight.lua * add documentation * add @return documentation * test: add check before vim.defer fires * doc: fixup
This commit is contained in:
parent
a6be7a9180
commit
f2894bffb0
@ -692,6 +692,27 @@ identical identifiers, highlighting both as |hl-WarningMsg|: >
|
||||
((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right)
|
||||
(eq? @WarningMsg.left @WarningMsg.right))
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
VIM.HIGHLIGHT *lua-highlight*
|
||||
|
||||
Nvim includes a function for highlighting a selection on yank (see for example
|
||||
https://github.com/machakann/vim-highlightedyank). To enable it, add
|
||||
>
|
||||
au TextYankPost * silent! lua require'vim.highlight'.on_yank()
|
||||
<
|
||||
to your `init.vim`. You can customize the highlight group and the duration of
|
||||
the highlight via
|
||||
>
|
||||
au TextYankPost * silent! lua require'vim.highlight'.on_yank("IncSearch", 500)
|
||||
<
|
||||
|
||||
vim.highlight.on_yank([{higroup}, {timeout}, {event}])
|
||||
*vim.highlight.on_yank()*
|
||||
Highlights the yanked text. Optional arguments are the highlight group
|
||||
to use ({higroup}, default `"IncSearch"`), the duration of highlighting
|
||||
in milliseconds ({timeout}, default `500`), and the event structure
|
||||
that is fired ({event}, default `vim.v.event`).
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
VIM.REGEX *lua-regex*
|
||||
|
||||
@ -758,6 +779,14 @@ vim.empty_dict() *vim.empty_dict()*
|
||||
Note: if numeric keys are added to the table, the metatable will be
|
||||
ignored and the dict converted to a list/array anyway.
|
||||
|
||||
vim.region({bufnr}, {pos1}, {pos2}, {type}, {inclusive}) *vim.region()*
|
||||
Converts a selection specified by the buffer ({bufnr}), starting
|
||||
position ({pos1}, a zero-indexed pair `{line1,column1}`), ending
|
||||
position ({pos2}, same format as {pos1}), the type of the register
|
||||
for the selection ({type}, see |regtype|), and a boolean indicating
|
||||
whether the selection is inclusive or not, into a zero-indexed table
|
||||
of linewise selections of the form `{linenr = {startcol, endcol}}` .
|
||||
|
||||
vim.rpcnotify({channel}, {method}[, {args}...]) *vim.rpcnotify()*
|
||||
Sends {event} to {channel} via |RPC| and returns immediately.
|
||||
If {channel} is 0, the event is broadcast to all channels.
|
||||
|
@ -116,6 +116,10 @@ backwards-compatibility cost. Some examples:
|
||||
- Directories for 'directory' and 'undodir' are auto-created.
|
||||
- Terminal features such as 'guicursor' are enabled where possible.
|
||||
|
||||
Some features are built in that otherwise required external plugins:
|
||||
|
||||
- Highlighting the yanked region, see |lua-highlight|.
|
||||
|
||||
ARCHITECTURE ~
|
||||
|
||||
External plugins run in separate processes. |remote-plugin| This improves
|
||||
|
41
runtime/lua/vim/highlight.lua
Normal file
41
runtime/lua/vim/highlight.lua
Normal file
@ -0,0 +1,41 @@
|
||||
local api = vim.api
|
||||
|
||||
local highlight = {}
|
||||
|
||||
--- Highlight the yanked region
|
||||
--
|
||||
--- use from init.vim via
|
||||
--- au TextYankPost * lua require'vim.highlight'.on_yank()
|
||||
--- customize highlight group and timeout via
|
||||
--- au TextYankPost * lua require'vim.highlight'.on_yank("IncSearch", 500)
|
||||
-- @param higroup highlight group for yanked region
|
||||
-- @param timeout time in ms before highlight is cleared
|
||||
-- @param event event structure
|
||||
function highlight.on_yank(higroup, timeout, event)
|
||||
event = event or vim.v.event
|
||||
if event.operator ~= 'y' or event.regtype == '' then return end
|
||||
higroup = higroup or "IncSearch"
|
||||
timeout = timeout or 500
|
||||
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local yank_ns = api.nvim_create_namespace('')
|
||||
api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1)
|
||||
|
||||
local pos1 = vim.fn.getpos("'[")
|
||||
local pos2 = vim.fn.getpos("']")
|
||||
|
||||
pos1 = {pos1[2] - 1, pos1[3] - 1 + pos1[4]}
|
||||
pos2 = {pos2[2] - 1, pos2[3] - 1 + pos2[4]}
|
||||
|
||||
local region = vim.region(bufnr, pos1, pos2, event.regtype, event.inclusive)
|
||||
for linenr, cols in pairs(region) do
|
||||
api.nvim_buf_add_highlight(bufnr, yank_ns, higroup, linenr, cols[1], cols[2])
|
||||
end
|
||||
|
||||
vim.defer_fn(
|
||||
function() api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1) end,
|
||||
timeout
|
||||
)
|
||||
end
|
||||
|
||||
return highlight
|
@ -415,4 +415,67 @@ do
|
||||
vim.wo = new_win_opt_accessor(nil)
|
||||
end
|
||||
|
||||
--- Get a table of lines with start, end columns for a region marked by two points
|
||||
---
|
||||
--@param bufnr number of buffer
|
||||
--@param pos1 (line, column) tuple marking beginning of region
|
||||
--@param pos2 (line, column) tuple marking end of region
|
||||
--@param regtype type of selection (:help setreg)
|
||||
--@param inclusive boolean indicating whether the selection is end-inclusive
|
||||
--@return region lua table of the form {linenr = {startcol,endcol}}
|
||||
function vim.region(bufnr, pos1, pos2, regtype, inclusive)
|
||||
if not vim.api.nvim_buf_is_loaded(bufnr) then
|
||||
vim.fn.bufload(bufnr)
|
||||
end
|
||||
|
||||
-- in case of block selection, columns need to be adjusted for non-ASCII characters
|
||||
-- TODO: handle double-width characters
|
||||
local bufline
|
||||
if regtype:byte() == 22 then
|
||||
bufline = vim.api.nvim_buf_get_lines(bufnr, pos1[1], pos1[1] + 1, true)[1]
|
||||
pos1[2] = vim.str_utfindex(bufline, pos1[2])
|
||||
end
|
||||
|
||||
local region = {}
|
||||
for l = pos1[1], pos2[1] do
|
||||
local c1, c2
|
||||
if regtype:byte() == 22 then -- block selection: take width from regtype
|
||||
c1 = pos1[2]
|
||||
c2 = c1 + regtype:sub(2)
|
||||
-- and adjust for non-ASCII characters
|
||||
bufline = vim.api.nvim_buf_get_lines(bufnr, l, l + 1, true)[1]
|
||||
if c1 < #bufline then
|
||||
c1 = vim.str_byteindex(bufline, c1)
|
||||
end
|
||||
if c2 < #bufline then
|
||||
c2 = vim.str_byteindex(bufline, c2)
|
||||
end
|
||||
else
|
||||
c1 = (l == pos1[1]) and (pos1[2]) or 0
|
||||
c2 = (l == pos2[1]) and (pos2[2] + (inclusive and 1 or 0)) or -1
|
||||
end
|
||||
table.insert(region, l, {c1, c2})
|
||||
end
|
||||
return region
|
||||
end
|
||||
|
||||
--- Defers calling `fn` until `timeout` ms passes.
|
||||
---
|
||||
--- Use to do a one-shot timer that calls `fn`
|
||||
--@param fn Callback to call once `timeout` expires
|
||||
--@param timeout Number of milliseconds to wait before calling `fn`
|
||||
--@return timer luv timer object
|
||||
function vim.defer_fn(fn, timeout)
|
||||
vim.validate { fn = { fn, 'c', true}; }
|
||||
local timer = vim.loop.new_timer()
|
||||
timer:start(timeout, 0, vim.schedule_wrap(function()
|
||||
timer:stop()
|
||||
timer:close()
|
||||
|
||||
fn()
|
||||
end))
|
||||
|
||||
return timer
|
||||
end
|
||||
|
||||
return module
|
||||
|
@ -1046,4 +1046,24 @@ describe('lua stdlib', function()
|
||||
eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]])
|
||||
eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]])
|
||||
end)
|
||||
end)
|
||||
|
||||
it('vim.defer_fn', function()
|
||||
exec_lua [[
|
||||
vim.g.test = 0
|
||||
vim.defer_fn(function() vim.g.test = 1 end, 10)
|
||||
]]
|
||||
eq(0, exec_lua[[return vim.g.test]])
|
||||
exec_lua [[vim.cmd("sleep 10m")]]
|
||||
eq(1, exec_lua[[return vim.g.test]])
|
||||
end)
|
||||
|
||||
it('vim.region', function()
|
||||
helpers.insert(helpers.dedent( [[
|
||||
text tααt tααt text
|
||||
text tαxt txtα tex
|
||||
text tαxt tαxt
|
||||
]]))
|
||||
eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]])
|
||||
end)
|
||||
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user