mirror of
https://github.com/neovim/neovim.git
synced 2025-09-08 04:18:18 +00:00
fix(events): avoid unnecessary CursorMoved (#24675)
Problem: Temporarily changing current window in a script causes CursorMoved to be triggerd. Solution: Don't trigger CursorMoved if neither curwin nor cursor changed between two checks.
This commit is contained in:
@@ -455,7 +455,7 @@ coerced to strings. See |id()| for more details, currently it uses
|
|||||||
|
|
||||||
|c_CTRL-R| pasting a non-special register into |cmdline| omits the last <CR>.
|
|c_CTRL-R| pasting a non-special register into |cmdline| omits the last <CR>.
|
||||||
|
|
||||||
|CursorMoved| always triggers when moving between windows.
|
|CursorMoved| triggers when moving between windows.
|
||||||
|
|
||||||
Lua interface (|lua.txt|):
|
Lua interface (|lua.txt|):
|
||||||
|
|
||||||
|
@@ -1030,7 +1030,8 @@ int autocmd_register(int64_t id, event_T event, const char *pat, int patlen, int
|
|||||||
// If the event is CursorMoved, update the last cursor position
|
// If the event is CursorMoved, update the last cursor position
|
||||||
// position to avoid immediately triggering the autocommand
|
// position to avoid immediately triggering the autocommand
|
||||||
if (event == EVENT_CURSORMOVED && !has_event(EVENT_CURSORMOVED)) {
|
if (event == EVENT_CURSORMOVED && !has_event(EVENT_CURSORMOVED)) {
|
||||||
curwin->w_last_cursormoved = curwin->w_cursor;
|
last_cursormoved_win = curwin;
|
||||||
|
last_cursormoved = curwin->w_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the fields checked by the WinScrolled and
|
// Initialize the fields checked by the WinScrolled and
|
||||||
|
@@ -80,6 +80,11 @@ typedef kvec_t(AutoCmd) AutoCmdVec;
|
|||||||
// apply_autocmds_group.
|
// apply_autocmds_group.
|
||||||
EXTERN bool au_did_filetype INIT(= false);
|
EXTERN bool au_did_filetype INIT(= false);
|
||||||
|
|
||||||
|
/// For CursorMoved event
|
||||||
|
EXTERN win_T *last_cursormoved_win INIT(= NULL);
|
||||||
|
/// For CursorMoved event, only used when last_cursormoved_win == curwin
|
||||||
|
EXTERN pos_T last_cursormoved INIT(= { 0, 0, 0 });
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "autocmd.h.generated.h"
|
# include "autocmd.h.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1101,7 +1101,6 @@ struct window_S {
|
|||||||
///< can be different from w_cursor.lnum
|
///< can be different from w_cursor.lnum
|
||||||
///< for closed folds.
|
///< for closed folds.
|
||||||
linenr_T w_last_cursorline; ///< where last 'cursorline' was drawn
|
linenr_T w_last_cursorline; ///< where last 'cursorline' was drawn
|
||||||
pos_T w_last_cursormoved; ///< for CursorMoved event
|
|
||||||
|
|
||||||
// the next seven are used to update the visual part
|
// the next seven are used to update the visual part
|
||||||
char w_old_visual_mode; ///< last known VIsual_mode
|
char w_old_visual_mode; ///< last known VIsual_mode
|
||||||
|
@@ -361,9 +361,10 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when the cursor line is changed always trigger CursorMoved
|
// when the cursor line is changed always trigger CursorMoved
|
||||||
if (lnum <= curwin->w_cursor.lnum
|
if (last_cursormoved_win == curwin
|
||||||
|
&& lnum <= curwin->w_cursor.lnum
|
||||||
&& lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum) {
|
&& lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum) {
|
||||||
curwin->w_last_cursormoved.lnum = 0;
|
last_cursormoved.lnum = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1287,7 +1287,8 @@ void ins_redraw(bool ready)
|
|||||||
// Trigger CursorMoved if the cursor moved. Not when the popup menu is
|
// Trigger CursorMoved if the cursor moved. Not when the popup menu is
|
||||||
// visible, the command might delete it.
|
// visible, the command might delete it.
|
||||||
if (ready && has_event(EVENT_CURSORMOVEDI)
|
if (ready && has_event(EVENT_CURSORMOVEDI)
|
||||||
&& !equalpos(curwin->w_last_cursormoved, curwin->w_cursor)
|
&& (last_cursormoved_win != curwin
|
||||||
|
|| !equalpos(last_cursormoved, curwin->w_cursor))
|
||||||
&& !pum_visible()) {
|
&& !pum_visible()) {
|
||||||
// Need to update the screen first, to make sure syntax
|
// Need to update the screen first, to make sure syntax
|
||||||
// highlighting is correct after making a change (e.g., inserting
|
// highlighting is correct after making a change (e.g., inserting
|
||||||
@@ -1300,7 +1301,8 @@ void ins_redraw(bool ready)
|
|||||||
// getcurpos()
|
// getcurpos()
|
||||||
update_curswant();
|
update_curswant();
|
||||||
ins_apply_autocmds(EVENT_CURSORMOVEDI);
|
ins_apply_autocmds(EVENT_CURSORMOVEDI);
|
||||||
curwin->w_last_cursormoved = curwin->w_cursor;
|
last_cursormoved_win = curwin;
|
||||||
|
last_cursormoved = curwin->w_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger TextChangedI if changedtick differs.
|
// Trigger TextChangedI if changedtick differs.
|
||||||
|
@@ -1267,9 +1267,11 @@ static void normal_check_cursor_moved(NormalState *s)
|
|||||||
{
|
{
|
||||||
// Trigger CursorMoved if the cursor moved.
|
// Trigger CursorMoved if the cursor moved.
|
||||||
if (!finish_op && has_event(EVENT_CURSORMOVED)
|
if (!finish_op && has_event(EVENT_CURSORMOVED)
|
||||||
&& !equalpos(curwin->w_last_cursormoved, curwin->w_cursor)) {
|
&& (last_cursormoved_win != curwin
|
||||||
|
|| !equalpos(last_cursormoved, curwin->w_cursor))) {
|
||||||
apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, false, curbuf);
|
apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, false, curbuf);
|
||||||
curwin->w_last_cursormoved = curwin->w_cursor;
|
last_cursormoved_win = curwin;
|
||||||
|
last_cursormoved = curwin->w_cursor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4943,7 +4943,6 @@ static void win_enter_ext(win_T *const wp, const int flags)
|
|||||||
if (other_buffer) {
|
if (other_buffer) {
|
||||||
apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
|
apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
|
||||||
}
|
}
|
||||||
curwin->w_last_cursormoved.lnum = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
maketitle();
|
maketitle();
|
||||||
|
@@ -3,7 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
|
|||||||
local clear = helpers.clear
|
local clear = helpers.clear
|
||||||
local eq = helpers.eq
|
local eq = helpers.eq
|
||||||
local eval = helpers.eval
|
local eval = helpers.eval
|
||||||
local funcs = helpers.funcs
|
local meths = helpers.meths
|
||||||
local source = helpers.source
|
local source = helpers.source
|
||||||
local command = helpers.command
|
local command = helpers.command
|
||||||
|
|
||||||
@@ -12,10 +12,10 @@ describe('CursorMoved', function()
|
|||||||
|
|
||||||
it('is triggered after BufEnter when changing or splitting windows #11878 #12031', function()
|
it('is triggered after BufEnter when changing or splitting windows #11878 #12031', function()
|
||||||
source([[
|
source([[
|
||||||
call setline(1, 'foo')
|
call setline(1, 'foo')
|
||||||
let g:log = []
|
let g:log = []
|
||||||
autocmd BufEnter * let g:log += ['BufEnter' .. expand("<abuf>")]
|
autocmd BufEnter * let g:log += ['BufEnter' .. expand("<abuf>")]
|
||||||
autocmd CursorMoved * let g:log += ['CursorMoved' .. expand("<abuf>")]
|
autocmd CursorMoved * let g:log += ['CursorMoved' .. expand("<abuf>")]
|
||||||
]])
|
]])
|
||||||
eq({}, eval('g:log'))
|
eq({}, eval('g:log'))
|
||||||
command('new')
|
command('new')
|
||||||
@@ -24,23 +24,34 @@ describe('CursorMoved', function()
|
|||||||
eq({'BufEnter2', 'CursorMoved2', 'BufEnter1', 'CursorMoved1'}, eval('g:log'))
|
eq({'BufEnter2', 'CursorMoved2', 'BufEnter1', 'CursorMoved1'}, eval('g:log'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('is not triggered by temporarily switching window', function()
|
||||||
|
source([[
|
||||||
|
let g:cursormoved = 0
|
||||||
|
vnew
|
||||||
|
autocmd CursorMoved * let g:cursormoved += 1
|
||||||
|
]])
|
||||||
|
command('wincmd w | wincmd p')
|
||||||
|
eq(0, eval('g:cursormoved'))
|
||||||
|
end)
|
||||||
|
|
||||||
it("is not triggered by functions that don't change the window", function()
|
it("is not triggered by functions that don't change the window", function()
|
||||||
source([[
|
source([[
|
||||||
let g:cursormoved = 0
|
let g:cursormoved = 0
|
||||||
let g:buf = bufnr('%')
|
let g:buf = bufnr('%')
|
||||||
vsplit foo
|
vsplit foo
|
||||||
autocmd CursorMoved * let g:cursormoved += 1
|
autocmd CursorMoved * let g:cursormoved += 1
|
||||||
call nvim_buf_set_lines(g:buf, 0, -1, v:true, ['aaa'])
|
|
||||||
]])
|
]])
|
||||||
eq({'aaa'}, funcs.nvim_buf_get_lines(eval('g:buf'), 0, -1, true))
|
meths.buf_set_lines(eval('g:buf'), 0, -1, true, {'aaa'})
|
||||||
|
eq(0, eval('g:cursormoved'))
|
||||||
|
eq({'aaa'}, meths.buf_get_lines(eval('g:buf'), 0, -1, true))
|
||||||
eq(0, eval('g:cursormoved'))
|
eq(0, eval('g:cursormoved'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("is not triggered by cursor movement prior to first CursorMoved instantiation", function()
|
it("is not triggered by cursor movement prior to first CursorMoved instantiation", function()
|
||||||
source([[
|
source([[
|
||||||
let g:cursormoved = 0
|
let g:cursormoved = 0
|
||||||
autocmd! CursorMoved
|
autocmd! CursorMoved
|
||||||
autocmd CursorMoved * let g:cursormoved += 1
|
autocmd CursorMoved * let g:cursormoved += 1
|
||||||
]])
|
]])
|
||||||
eq(0, eval('g:cursormoved'))
|
eq(0, eval('g:cursormoved'))
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user