feat(event): add VisualChanged autocmd

This commit is contained in:
Bara C. Tudor 2024-08-14 20:18:40 +03:00
parent 6bcefad5a6
commit 8ffb9fafa7
5 changed files with 110 additions and 0 deletions

View File

@ -1116,6 +1116,10 @@ VimResized After the Vim window was resized, thus 'lines'
VimResume After Nvim resumes from |suspend| state.
*VimSuspend*
VimSuspend Before Nvim enters |suspend| state.
*VisualChanged*
VisualChanged When Visual mode starts, visual mode changes
to another visual mode, selection changes,
cursor moves while in visual mode.
*WinClosed*
WinClosed When closing a window, just before it is
removed from the window layout. The pattern

View File

@ -125,6 +125,7 @@ EVENTS
• |CompleteDone| now sets the `reason` key in `v:event` which specifies the reason
for completion being done.
• Added |VisualChanged| autocommand that fires when the visual selection changes
LSP

View File

@ -127,6 +127,7 @@ return {
'VimResized', -- after Vim window was resized
'VimResume', -- after Nvim is resumed
'VimSuspend', -- before Nvim is suspended
'VisualChanged', -- when visual selection was changed
'WinClosed', -- after closing a window
'WinEnter', -- after entering a window
'WinLeave', -- before leaving a window

View File

@ -1297,6 +1297,27 @@ static void normal_check_cursor_moved(NormalState *s)
}
}
static int last_visualchanged_mode;
static pos_T last_visualchanged_cursor;
static pos_T last_visualchanged_anchor;
/// Trigger VisualChanged if visual selection has changed
static void normal_check_visual_changed(NormalState *s)
{
if (!finish_op && VIsual_active && (has_event(EVENT_VISUALCHANGED))
&& (VIsual_mode != last_visualchanged_mode
|| !equalpos(curwin->w_cursor, last_visualchanged_cursor)
|| !equalpos(VIsual, last_visualchanged_anchor))) {
apply_autocmds(EVENT_VISUALCHANGED, NULL, NULL, false, curbuf);
last_visualchanged_cursor = curwin->w_cursor;
last_visualchanged_anchor = VIsual;
last_visualchanged_mode = VIsual_mode;
} else {
// isn't visual mode; reset
last_visualchanged_mode = -1;
}
}
static void normal_check_text_changed(NormalState *s)
{
// Trigger TextChanged if changedtick differs.
@ -1437,6 +1458,7 @@ static int normal_check(VimState *state)
normal_check_window_scrolled(s);
normal_check_buffer_modified(s);
normal_check_safe_state(s);
normal_check_visual_changed(s);
// Updating diffs from changed() does not always work properly,
// esp. updating folds. Do an update just before redrawing if

View File

@ -0,0 +1,82 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local eq = t.eq
local clear = n.clear
local source = n.source
local feed = n.feed
local insert = n.insert
local eval = n.eval
local api = n.api
describe('VisualChanged', function()
before_each(function()
clear()
insert [[
Hello
Hello
Hello]]
api.nvim_win_set_cursor(0, { 1, 0 })
source [[
let g:visual_count = 0
au VisualChanged * let g:visual_count += 1
]]
end)
local function count()
return eval('g:visual_count')
end
it('fires when visual mode changes or starts', function()
feed 'v'
eq(1, count())
feed 'iw'
eq(2, count())
feed 'V'
eq(3, count())
feed '<c-v>'
eq(4, count())
feed 'v'
eq(5, count())
feed '<esc>v'
eq(6, count())
feed '<esc>V'
eq(7, count())
feed '<esc><c-v>'
eq(8, count())
end)
it('fires when visual area changes or cursor moves', function()
feed 'v'
eq(1, count())
feed 'iw'
eq(2, count())
feed 'Vj0'
eq(5, count())
feed '<esc>Vjl'
eq(8, count())
feed '<esc>gg<c-v>ejh'
eq(12, count())
end)
it('works with gv', function()
feed 'vjl'
eq(3, count())
feed '<esc>Ggv'
eq(4, count())
end)
end)