# HG changeset patch # User Christian Brabandt # Date 1518283806 -3600 # Node ID 5ed6e4a25925082a9e8f7aeb80dd9802ce4181f5 # Parent cb07abe792aee12251972f4c7d096efef90b73b3 patch 8.0.1494: no autocmd triggered in Insert mode with visible popup menu commit https://github.com/vim/vim/commit/5a093437199001a0d60d8e18e2b9539b99a7757c Author: Bram Moolenaar Date: Sat Feb 10 18:15:19 2018 +0100 patch 8.0.1494: no autocmd triggered in Insert mode with visible popup menu Problem: No autocmd triggered in Insert mode with visible popup menu. Solution: Add TextChangedP. (Prabir Shrestha, Christian Brabandt, closes #2372, closes #1691) Fix that the TextChanged autocommands are not always triggered when sourcing a script. diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -1,4 +1,4 @@ -*autocmd.txt* For Vim version 8.0. Last change: 2018 Feb 09 +*autocmd.txt* For Vim version 8.0. Last change: 2018 Feb 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -332,6 +332,9 @@ Name triggered by ~ |TextChanged| after a change was made to the text in Normal mode |TextChangedI| after a change was made to the text in Insert mode + when popup menu is not visible +|TextChangedP| after a change was made to the text in Insert mode + when popup menu visible |TextYankPost| after text is yanked or deleted |ColorScheme| after loading a color scheme @@ -976,6 +979,11 @@ TextChangedI After a change was made t current buffer in Insert mode. Not triggered when the popup menu is visible. Otherwise the same as TextChanged. + *TextChangedP* +TextChangedP After a change was made to the text in the + current buffer in Insert mode, only when the + popup menu is visible. Otherwise the same as + TextChanged. *TextYankPost* TextYankPost After text has been yanked or deleted in the current buffer. The following values of diff --git a/src/edit.c b/src/edit.c --- a/src/edit.c +++ b/src/edit.c @@ -1682,17 +1682,28 @@ ins_redraw( #ifdef FEAT_AUTOCMD /* Trigger TextChangedI if b_changedtick differs. */ if (ready && has_textchangedI() - && last_changedtick != CHANGEDTICK(curbuf) + && curbuf->b_last_changedtick != CHANGEDTICK(curbuf) # ifdef FEAT_INS_EXPAND && !pum_visible() # endif ) { - if (last_changedtick_buf == curbuf) - apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf); - last_changedtick_buf = curbuf; - last_changedtick = CHANGEDTICK(curbuf); - } + apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf); + curbuf->b_last_changedtick = CHANGEDTICK(curbuf); + } + +# ifdef FEAT_INS_EXPAND + /* Trigger TextChangedP if b_changedtick differs. When the popupmenu closes + * TextChangedI will need to trigger for backwards compatibility, thus use + * different b_last_changedtick* variables. */ + if (ready && has_textchangedP() + && curbuf->b_last_changedtick_pum != CHANGEDTICK(curbuf) + && pum_visible()) + { + apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf); + curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf); + } +# endif #endif if (must_redraw) diff --git a/src/fileio.c b/src/fileio.c --- a/src/fileio.c +++ b/src/fileio.c @@ -5037,9 +5037,8 @@ restore_backup: #ifdef FEAT_AUTOCMD /* b:changedtick is always incremented in unchanged() but that * should not trigger a TextChanged event. */ - if (last_changedtick + 1 == CHANGEDTICK(buf) - && last_changedtick_buf == buf) - last_changedtick = CHANGEDTICK(buf); + if (buf->b_last_changedtick + 1 == CHANGEDTICK(buf)) + buf->b_last_changedtick = CHANGEDTICK(buf); #endif u_unchanged(buf); u_update_save_nr(buf); @@ -7851,6 +7850,7 @@ static struct event_name {"TermResponse", EVENT_TERMRESPONSE}, {"TextChanged", EVENT_TEXTCHANGED}, {"TextChangedI", EVENT_TEXTCHANGEDI}, + {"TextChangedP", EVENT_TEXTCHANGEDP}, {"User", EVENT_USER}, {"VimEnter", EVENT_VIMENTER}, {"VimLeave", EVENT_VIMLEAVE}, @@ -9377,6 +9377,15 @@ has_textchangedI(void) } /* + * Return TRUE when there is a TextChangedP autocommand defined. + */ + int +has_textchangedP(void) +{ + return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL); +} + +/* * Return TRUE when there is an InsertCharPre autocommand defined. */ int diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -1085,8 +1085,6 @@ EXTERN pos_T last_cursormoved /* f = INIT_POS_T(0, 0, 0) # endif ; -EXTERN varnumber_T last_changedtick INIT(= 0); /* for TextChanged event */ -EXTERN buf_T *last_changedtick_buf INIT(= NULL); #endif EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */ diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.c @@ -1201,13 +1201,10 @@ main_loop( #ifdef FEAT_AUTOCMD /* Trigger TextChanged if b:changedtick differs. */ if (!finish_op && has_textchanged() - && last_changedtick != CHANGEDTICK(curbuf)) + && curbuf->b_last_changedtick != CHANGEDTICK(curbuf)) { - if (last_changedtick_buf == curbuf) - apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, - FALSE, curbuf); - last_changedtick_buf = curbuf; - last_changedtick = CHANGEDTICK(curbuf); + apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, FALSE, curbuf); + curbuf->b_last_changedtick = CHANGEDTICK(curbuf); } #endif diff --git a/src/proto/fileio.pro b/src/proto/fileio.pro --- a/src/proto/fileio.pro +++ b/src/proto/fileio.pro @@ -48,6 +48,7 @@ int has_cursormoved(void); int has_cursormovedI(void); int has_textchanged(void); int has_textchangedI(void); +int has_textchangedP(void); int has_insertcharpre(void); int has_cmdundefined(void); int has_funcundefined(void); diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1983,6 +1983,15 @@ struct file_buffer incremented for each change, also for undo */ #define CHANGEDTICK(buf) ((buf)->b_ct_di.di_tv.vval.v_number) +#ifdef FEAT_AUTOCMD + varnumber_T b_last_changedtick; /* b:changedtick when TextChanged or + TextChangedI was last triggered. */ +# ifdef FEAT_INS_EXPAND + varnumber_T b_last_changedtick_pum; /* b:changedtick when TextChangedP was + last triggered. */ +# endif +#endif + int b_saving; /* Set to TRUE if we are in the middle of saving the buffer. */ diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -1249,3 +1249,58 @@ function Test_dirchanged_auto() bwipe! call s:After_test_dirchanged() endfunc + +" Test TextChangedI and TextChangedP +func Test_ChangedP() + new + call setline(1, ['foo', 'bar', 'foobar']) + call test_override("char_avail", 1) + set complete=. completeopt=menuone + + func! TextChangedAutocmd(char) + let g:autocmd .= a:char + endfunc + + au! TextChanged :call TextChangedAutocmd('N') + au! TextChangedI :call TextChangedAutocmd('I') + au! TextChangedP :call TextChangedAutocmd('P') + + call cursor(3, 1) + let g:autocmd = '' + call feedkeys("o\", 'tnix') + call assert_equal('I', g:autocmd) + + let g:autocmd = '' + call feedkeys("Sf", 'tnix') + call assert_equal('II', g:autocmd) + + let g:autocmd = '' + call feedkeys("Sf\", 'tnix') + call assert_equal('IIP', g:autocmd) + + let g:autocmd = '' + call feedkeys("Sf\\", 'tnix') + call assert_equal('IIPP', g:autocmd) + + let g:autocmd = '' + call feedkeys("Sf\\\", 'tnix') + call assert_equal('IIPPP', g:autocmd) + + let g:autocmd = '' + call feedkeys("Sf\\\\", 'tnix') + call assert_equal('IIPPPP', g:autocmd) + + call assert_equal(['foo', 'bar', 'foobar', 'foo'], getline(1, '$')) + " TODO: how should it handle completeopt=noinsert,noselect? + + " CleanUp + call test_override("char_avail", 0) + au! TextChanged + au! TextChangedI + au! TextChangedP + delfu TextChangedAutocmd + unlet! g:autocmd + set complete&vim completeopt&vim + + bw! +endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -772,6 +772,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1494, +/**/ 1493, /**/ 1492, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -1337,8 +1337,11 @@ enum auto_event EVENT_TABCLOSED, /* after closing a tab page */ EVENT_SHELLCMDPOST, /* after ":!cmd" */ EVENT_SHELLFILTERPOST, /* after ":1,2!cmd", ":w !cmd", ":r !cmd". */ - EVENT_TEXTCHANGED, /* text was modified */ - EVENT_TEXTCHANGEDI, /* text was modified in Insert mode*/ + EVENT_TEXTCHANGED, /* text was modified not in Insert mode */ + EVENT_TEXTCHANGEDI, /* text was modified in Insert mode without + popup menu visible */ + EVENT_TEXTCHANGEDP, /* text was modified in Insert mode with popup + menu visible */ EVENT_CMDUNDEFINED, /* command undefined */ EVENT_OPTIONSET, /* option was set */ EVENT_TEXTYANKPOST, /* after some text was yanked */