From 0a8be9f8ef1e23a375b3a35ec06734f205cfd181 Mon Sep 17 00:00:00 2001 From: Jason Felice Date: Wed, 8 Aug 2018 20:51:49 -0700 Subject: vim-patch:8.1.0057: popup menu displayed wrong when using autocmd Problem: Popup menu displayed wrong when using autocmd. Solution: Use aucmd_prepbuf(). Force updating status line if the popup menu is going to be redrawn anyway. (Christian Brabandt, closes vim/vim#3009) https://github.com/vim/vim/commit/6ba3ec1bace67513a352326864cebc16b3c5bc56 --- src/nvim/edit.c | 14 ++++++++++++-- src/nvim/screen.c | 12 +++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 0d99aa8fb2..7279110444 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1390,7 +1390,12 @@ ins_redraw ( if (ready && has_event(EVENT_TEXTCHANGEDI) && curbuf->b_last_changedtick != buf_get_changedtick(curbuf) && !pum_visible()) { + aco_save_T aco; + + // save and restore curwin and curbuf, in case the autocmd changes them + aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, false, curbuf); + aucmd_restbuf(&aco); curbuf->b_last_changedtick = buf_get_changedtick(curbuf); } @@ -1400,8 +1405,13 @@ ins_redraw ( if (ready && has_event(EVENT_TEXTCHANGEDP) && curbuf->b_last_changedtick_pum != buf_get_changedtick(curbuf) && pum_visible()) { - apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, false, curbuf); - curbuf->b_last_changedtick_pum = buf_get_changedtick(curbuf); + aco_save_T aco; + + // save and restore curwin and curbuf, in case the autocmd changes them + aucmd_prepbuf(&aco, curbuf); + apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, false, curbuf); + aucmd_restbuf(&aco); + curbuf->b_last_changedtick_pum = buf_get_changedtick(curbuf); } if (must_redraw) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index f7fdc6060d..43ab9cd356 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -423,7 +423,7 @@ void update_screen(int type) /* redraw status line after the window to minimize cursor movement */ if (wp->w_redr_status) { - win_redr_status(wp); + win_redr_status(wp, true); // any popup menu will be redrawn below } } end_search_hl(); @@ -589,7 +589,7 @@ void update_debug_sign(const buf_T *const buf, const linenr_T lnum) win_update(wp); } if (wp->w_redr_status) { - win_redr_status(wp); + win_redr_status(wp, false); } } @@ -4542,7 +4542,7 @@ void redraw_statuslines(void) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_redr_status) { - win_redr_status(wp); + win_redr_status(wp, false); } } if (redraw_tabline) @@ -4809,7 +4809,9 @@ win_redr_status_matches ( /// Redraw the status line of window `wp`. /// /// If inversion is possible we use it. Else '=' characters are used. -static void win_redr_status(win_T *wp) +/// If "ignore_pum" is true, also redraw statusline when the popup menu is +/// displayed. +static void win_redr_status(win_T *wp, int ignore_pum) { int row; char_u *p; @@ -4832,7 +4834,7 @@ static void win_redr_status(win_T *wp) if (wp->w_status_height == 0) { // no status line, can only be last window redraw_cmdline = true; - } else if (!redrawing() || pum_drawn()) { + } else if (!redrawing() || (!ignore_pum && pum_drawn())) { // Don't redraw right now, do it later. Don't update status line when // popup menu is visible and may be drawn over it wp->w_redr_status = true; -- cgit From d45efa5793e8b60192cc5b1f80d112d0401b14d3 Mon Sep 17 00:00:00 2001 From: Jason Felice Date: Wed, 8 Aug 2018 16:02:32 -0700 Subject: vim-patch:8.1.0245: calling setline() in TextChangedI autocmd breaks undo Problem: Calling setline() in TextChangedI autocmd breaks undo. (Jason Felice) Solution: Don't save lines for undo when already saved. (closes vim/vim#3291) https://github.com/vim/vim/commit/91d2e783b41ca900bc603b3cb5e083c8a4a33170 --- src/nvim/edit.c | 9 +++++++++ src/nvim/testdir/test_autocmd.vim | 28 +++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 7279110444..4d487041b8 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1392,11 +1392,20 @@ ins_redraw ( && !pum_visible()) { aco_save_T aco; + // Sync undo when the autocommand calls setline() or append(), so that + // it can be undone separately. + u_sync_once = 2; + // save and restore curwin and curbuf, in case the autocmd changes them aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, false, curbuf); aucmd_restbuf(&aco); curbuf->b_last_changedtick = buf_get_changedtick(curbuf); + + if (u_sync_once == 1) { + ins_need_undo = true; + } + u_sync_once = 0; } // Trigger TextChangedP if changedtick differs. When the popupmenu closes diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 772b3f721c..547ffe5a46 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -567,7 +567,7 @@ func Test_OptionSet() " Cleanup au! OptionSet for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp'] - exe printf(":set %s&vi", opt) + exe printf(":set %s&vim", opt) endfor call test_override('starting', 0) delfunc! AutoCommandOptionSet @@ -1221,3 +1221,29 @@ func Test_ChangedP() bw! endfunc + +let g:setline_handled = v:false +func! SetLineOne() + if !g:setline_handled + call setline(1, "(x)") + let g:setline_handled = v:true + endif +endfunc + +func Test_TextChangedI_with_setline() + throw 'skipped: Nvim does not support test_override()' + new + call test_override('char_avail', 1) + autocmd TextChangedI call SetLineOne() + call feedkeys("i(\\", 'tx') + call assert_equal('(', getline(1)) + call assert_equal('x)', getline(2)) + undo + call assert_equal('(', getline(1)) + call assert_equal('', getline(2)) + undo + call assert_equal('', getline(1)) + + call test_override('starting', 0) + bwipe! +endfunc -- cgit From 3c41df269173b68aa5572df8c5b7cae408229b88 Mon Sep 17 00:00:00 2001 From: Jason Felice Date: Wed, 8 Aug 2018 16:11:32 -0700 Subject: vim-patch:8.1.0256: using setline() in TextChangedI splits undo Problem: Using setline() in TextChangedI splits undo. Solution: Use another solution for undo not working properly. https://github.com/vim/vim/commit/9fa9506853516c82851baec643aa47458cb8b3bc This deviates from Vim in the handling of the CursorHoldI event. In Vim, any buffer changes are merged into the insert. In Neovim, CursorHoldI is handled via the multiqueue, and the point at which the cursor hold is implemented (in input.c) doesn't know enough about it. Making all queued events merge into the insert seems more wronger since changes by other asynchronous events really should be separately undoable. --- src/nvim/edit.c | 48 +++++++++++++++++++++++++++------------ src/nvim/testdir/test_autocmd.vim | 4 +--- 2 files changed, 34 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 4d487041b8..8635735df3 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -276,7 +276,7 @@ static void insert_enter(InsertState *s) set_vim_var_string(VV_INSERTMODE, (char *) s->ptr, 1); set_vim_var_string(VV_CHAR, NULL, -1); - apply_autocmds(EVENT_INSERTENTER, NULL, NULL, false, curbuf); + ins_apply_autocmds(EVENT_INSERTENTER); // Make sure the cursor didn't move. Do call check_cursor_col() in // case the text was modified. Since Insert mode was not started yet @@ -469,7 +469,7 @@ static void insert_enter(InsertState *s) foldUpdateAfterInsert(); if (s->cmdchar != 'r' && s->cmdchar != 'v') { - apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL, false, curbuf); + ins_apply_autocmds(EVENT_INSERTLEAVE); } did_cursorhold = false; } @@ -1376,7 +1376,7 @@ ins_redraw ( // Make sure curswant is correct, an autocommand may call // getcurpos() update_curswant(); - apply_autocmds(EVENT_CURSORMOVEDI, NULL, NULL, false, curbuf); + ins_apply_autocmds(EVENT_CURSORMOVEDI); } if (curwin->w_p_cole > 0) { conceal_old_cursor_line = last_cursormoved.lnum; @@ -1391,21 +1391,17 @@ ins_redraw ( && curbuf->b_last_changedtick != buf_get_changedtick(curbuf) && !pum_visible()) { aco_save_T aco; - - // Sync undo when the autocommand calls setline() or append(), so that - // it can be undone separately. - u_sync_once = 2; + varnumber_T tick = buf_get_changedtick(curbuf); // save and restore curwin and curbuf, in case the autocmd changes them aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, false, curbuf); aucmd_restbuf(&aco); curbuf->b_last_changedtick = buf_get_changedtick(curbuf); - - if (u_sync_once == 1) { - ins_need_undo = true; + if (tick != buf_get_changedtick(curbuf)) { // see ins_apply_autocmds() + u_save(curwin->w_cursor.lnum, + (linenr_T)(curwin->w_cursor.lnum + 1)); } - u_sync_once = 0; } // Trigger TextChangedP if changedtick differs. When the popupmenu closes @@ -1415,12 +1411,17 @@ ins_redraw ( && curbuf->b_last_changedtick_pum != buf_get_changedtick(curbuf) && pum_visible()) { aco_save_T aco; + varnumber_T tick = buf_get_changedtick(curbuf); // save and restore curwin and curbuf, in case the autocmd changes them aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, false, curbuf); aucmd_restbuf(&aco); curbuf->b_last_changedtick_pum = buf_get_changedtick(curbuf); + if (tick != buf_get_changedtick(curbuf)) { // see ins_apply_autocmds() + u_save(curwin->w_cursor.lnum, + (linenr_T)(curwin->w_cursor.lnum + 1)); + } } if (must_redraw) @@ -3411,12 +3412,12 @@ static bool ins_compl_prep(int c) do_c_expr_indent(); /* Trigger the CompleteDone event to give scripts a chance to act * upon the completion. */ - apply_autocmds(EVENT_COMPLETEDONE, NULL, NULL, FALSE, curbuf); + ins_apply_autocmds(EVENT_COMPLETEDONE); } } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) /* Trigger the CompleteDone event to give scripts a chance to act * upon the (possibly failed) completion. */ - apply_autocmds(EVENT_COMPLETEDONE, NULL, NULL, FALSE, curbuf); + ins_apply_autocmds(EVENT_COMPLETEDONE); /* reset continue_* if we left expansion-mode, if we stay they'll be * (re)set properly in ins_complete() */ @@ -7416,7 +7417,7 @@ static void ins_insert(int replaceState) set_vim_var_string(VV_INSERTMODE, ((State & REPLACE_FLAG) ? "i" : replaceState == VREPLACE ? "v" : "r"), 1); - apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, false, curbuf); + ins_apply_autocmds(EVENT_INSERTCHANGE); if (State & REPLACE_FLAG) { State = INSERT | (State & LANGMAP); } else { @@ -8678,7 +8679,7 @@ static char_u *do_insert_char_pre(int c) set_vim_var_string(VV_CHAR, buf, -1); char_u *res = NULL; - if (apply_autocmds(EVENT_INSERTCHARPRE, NULL, NULL, FALSE, curbuf)) { + if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) { /* Get the value of v:char. It may be empty or more than one * character. Only use it when changed, otherwise continue with the * original character to avoid breaking autoindent. */ @@ -8692,6 +8693,23 @@ static char_u *do_insert_char_pre(int c) return res; } +/// Trigger "event" and take care of fixing undo. +static int ins_apply_autocmds(event_T event) +{ + varnumber_T tick = buf_get_changedtick(curbuf); + int r; + + r = apply_autocmds(event, NULL, NULL, false, curbuf); + + // If u_savesub() was called then we are not prepared to start + // a new line. Call u_save() with no contents to fix that. + if (tick != buf_get_changedtick(curbuf)) { + u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1)); + } + + return r; +} + static void show_pum(int prev_w_wrow, int prev_w_leftcol) { // RedrawingDisabled may be set when invoked through complete(). diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 547ffe5a46..e4ab3ccea8 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -1239,10 +1239,8 @@ func Test_TextChangedI_with_setline() call assert_equal('(', getline(1)) call assert_equal('x)', getline(2)) undo - call assert_equal('(', getline(1)) - call assert_equal('', getline(2)) - undo call assert_equal('', getline(1)) + call assert_equal('', getline(2)) call test_override('starting', 0) bwipe! -- cgit From c6dd84e00b2860bb906d5fd61b8414620714594d Mon Sep 17 00:00:00 2001 From: Jason Felice Date: Wed, 8 Aug 2018 18:31:39 -0700 Subject: Fix lint --- src/nvim/edit.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 8635735df3..dfb0386d0a 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -8680,11 +8680,12 @@ static char_u *do_insert_char_pre(int c) char_u *res = NULL; if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) { - /* Get the value of v:char. It may be empty or more than one - * character. Only use it when changed, otherwise continue with the - * original character to avoid breaking autoindent. */ - if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) + // Get the value of v:char. It may be empty or more than one + // character. Only use it when changed, otherwise continue with the + // original character to avoid breaking autoindent. + if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) { res = vim_strsave(get_vim_var_str(VV_CHAR)); + } } set_vim_var_string(VV_CHAR, NULL, -1); -- cgit