diff options
author | Shougo Matsushita <Shougo.Matsu@gmail.com> | 2018-02-11 22:37:14 +0900 |
---|---|---|
committer | chemzqm <chemzqm@gmail.com> | 2018-05-14 19:14:25 +0800 |
commit | 021c5875c13e0c4a5bab67e2e2ac50c4be653ad6 (patch) | |
tree | c109ca4837ca488fea961de395e42950e1756d05 | |
parent | 36b2e3f743aaeb27531e67079d1a20bb4ac75e35 (diff) | |
download | rneovim-021c5875c13e0c4a5bab67e2e2ac50c4be653ad6.tar.gz rneovim-021c5875c13e0c4a5bab67e2e2ac50c4be653ad6.tar.bz2 rneovim-021c5875c13e0c4a5bab67e2e2ac50c4be653ad6.zip |
vim-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 vim/vim#2372, closes vim/vim#1691)
Fix that the TextChanged autocommands are not always triggered
when sourcing a script.
https://github.com/vim/vim/commit/5a093437199001a0d60d8e18e2b9539b99a7757c
-rw-r--r-- | runtime/doc/autocmd.txt | 8 | ||||
-rw-r--r-- | src/nvim/auevents.lua | 3 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 5 | ||||
-rw-r--r-- | src/nvim/edit.c | 18 | ||||
-rw-r--r-- | src/nvim/fileio.c | 5 | ||||
-rw-r--r-- | src/nvim/globals.h | 3 | ||||
-rw-r--r-- | src/nvim/normal.c | 8 | ||||
-rw-r--r-- | src/nvim/testdir/test_autocmd.vim | 56 | ||||
-rw-r--r-- | test/functional/viml/completion_spec.lua | 90 |
9 files changed, 178 insertions, 18 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 06a016eddb..0b7cd5b2cd 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -325,6 +325,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 |ColorScheme| after loading a color scheme @@ -969,6 +972,11 @@ TextChangedI After a change was made to the text in the 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. *User* User Never executed automatically. To be used for autocommands that are only executed with diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index 1153314e76..f07a92ab87 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -85,7 +85,8 @@ return { 'TermOpen', -- after opening a terminal buffer 'TermResponse', -- after setting "v:termresponse" 'TextChanged', -- text was modified - 'TextChangedI', -- text was modified in Insert mode + 'TextChangedI', -- text was modified in Insert mode(no popup) + 'TextChangedP', -- text was modified in Insert mode(popup) 'TextYankPost', -- after a yank or delete was done (y, d, c) 'User', -- user defined autocommand 'VimEnter', -- after starting Vim diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 53edae58a5..807baf02c1 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -484,6 +484,11 @@ struct file_buffer { #define b_changedtick changedtick_di.di_tv.vval.v_number ChangedtickDictItem changedtick_di; // b:changedtick dictionary item. + varnumber_T b_last_changedtick; // b:changedtick when TextChanged or + // TextChangedI was last triggered. + varnumber_T b_last_changedtick_pum; // b:changedtick when TextChangedP was + // last triggered. + bool b_saving; /* Set to true if we are in the middle of saving the buffer. */ diff --git a/src/nvim/edit.c b/src/nvim/edit.c index a1987cf2d5..4e0b868374 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1387,13 +1387,20 @@ ins_redraw ( // Trigger TextChangedI if b_changedtick differs. if (ready && has_event(EVENT_TEXTCHANGEDI) - && last_changedtick != curbuf->b_changedtick + && curbuf->b_last_changedtick != curbuf->b_changedtick && !pum_visible()) { - if (last_changedtick_buf == curbuf) { apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, false, curbuf); - } - last_changedtick_buf = curbuf; - last_changedtick = curbuf->b_changedtick; + curbuf->b_last_changedtick = curbuf->b_changedtick; + } + + // 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_event(EVENT_TEXTCHANGEDP) + && curbuf->b_last_changedtick_pum != curbuf->b_changedtick + && pum_visible()) { + apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, false, curbuf); + curbuf->b_last_changedtick_pum = curbuf->b_changedtick; } if (must_redraw) @@ -1415,6 +1422,7 @@ ins_redraw ( emsg_on_display = FALSE; /* may remove error message now */ } + /* * Handle a CTRL-V or CTRL-Q typed in Insert mode. */ diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index efeee1ba2b..102af1dba9 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3571,9 +3571,8 @@ restore_backup: unchanged(buf, TRUE); /* buf->b_changedtick is always incremented in unchanged() but that * should not trigger a TextChanged event. */ - if (last_changedtick + 1 == buf->b_changedtick - && last_changedtick_buf == buf) { - last_changedtick = buf->b_changedtick; + if (buf->b_last_changedtick + 1 == buf->b_changedtick) { + buf->b_last_changedtick = buf->b_changedtick; } u_unchanged(buf); u_update_save_nr(buf); diff --git a/src/nvim/globals.h b/src/nvim/globals.h index ddc58c2425..4aa0ef7def 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -868,9 +868,6 @@ EXTERN int did_cursorhold INIT(= false); // set when CursorHold t'gerd // for CursorMoved event EXTERN pos_T last_cursormoved INIT(= INIT_POS_T(0, 0, 0)); -EXTERN varnumber_T last_changedtick INIT(= 0); // for TextChanged event -EXTERN buf_T *last_changedtick_buf INIT(= NULL); - EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */ EXTERN int postponed_split_flags INIT(= 0); /* args for win_split() */ EXTERN int postponed_split_tab INIT(= 0); /* cmdmod.tab */ diff --git a/src/nvim/normal.c b/src/nvim/normal.c index e4310de5d8..e6d00f4d82 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1215,13 +1215,9 @@ static void normal_check_text_changed(NormalState *s) { // Trigger TextChanged if b_changedtick differs. if (!finish_op && has_event(EVENT_TEXTCHANGED) - && last_changedtick != curbuf->b_changedtick) { - if (last_changedtick_buf == curbuf) { + && curbuf->b_last_changedtick != curbuf->b_changedtick) { apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, false, curbuf); - } - - last_changedtick_buf = curbuf; - last_changedtick = curbuf->b_changedtick; + curbuf->b_last_changedtick = curbuf->b_changedtick; } } diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 24651b75e1..e285ea2d00 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -1165,3 +1165,59 @@ func Test_nocatch_wipe_dummy_buffer() call assert_fails('lv½ /x', 'E480') au! endfunc + +" Test TextChangedI and TextChangedP +func Test_ChangedP() abort + throw 'skipped: Nvim does not support test_override()' + 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 <buffer> :call TextChangedAutocmd('N') + au! TextChangedI <buffer> :call TextChangedAutocmd('I') + au! TextChangedP <buffer> :call TextChangedAutocmd('P') + + call cursor(3, 1) + let g:autocmd = '' + call feedkeys("o\<esc>", '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\<C-N>", 'tnix') + call assert_equal('IIP', g:autocmd) + + let g:autocmd = '' + call feedkeys("Sf\<C-N>\<C-N>", 'tnix') + call assert_equal('IIPP', g:autocmd) + + let g:autocmd = '' + call feedkeys("Sf\<C-N>\<C-N>\<C-N>", 'tnix') + call assert_equal('IIPPP', g:autocmd) + + let g:autocmd = '' + call feedkeys("Sf\<C-N>\<C-N>\<C-N>\<C-N>", '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/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua index 216ccb3744..93d3909568 100644 --- a/test/functional/viml/completion_spec.lua +++ b/test/functional/viml/completion_spec.lua @@ -3,7 +3,10 @@ local Screen = require('test.functional.ui.screen') local clear, feed = helpers.clear, helpers.feed local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq local feed_command, source, expect = helpers.feed_command, helpers.source, helpers.expect +local curbufmeths = helpers.curbufmeths +local command = helpers.command local meths = helpers.meths +local wait = helpers.wait describe('completion', function() local screen @@ -971,4 +974,91 @@ describe('ui/ext_popupmenu', function() eq(nil, items) -- popupmenu was hidden end) end) + + describe('TextChangeP autocommand', function() + it('can trigger TextChangedP autocommand as expected', + function() + curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar'}) + command('set complete=. completeopt=menuone') + command('let g:foo = []') + command('autocmd! TextChanged * :call add(g:foo, "N")') + command('autocmd! TextChangedI * :call add(g:foo, "I")') + command('autocmd! TextChangedP * :call add(g:foo, "P")') + command('call cursor(3, 1)') + + command('let g:foo = []') + feed('o') + wait() + feed('<esc>') + assert.same({'I'}, eval('g:foo')) + + command('let g:foo = []') + feed('S') + wait() + feed('f') + wait() + assert.same({'I', 'I'}, eval('g:foo')) + feed('<esc>') + + command('let g:foo = []') + feed('S') + wait() + feed('f') + wait() + feed('<C-n>') + wait() + assert.same({'I', 'I', 'P'}, eval('g:foo')) + feed('<esc>') + + command('let g:foo = []') + feed('S') + wait() + feed('f') + wait() + feed('<C-n>') + wait() + feed('<C-n>') + wait() + assert.same({'I', 'I', 'P', 'P'}, eval('g:foo')) + feed('<esc>') + + command('let g:foo = []') + feed('S') + wait() + feed('f') + wait() + feed('<C-n>') + wait() + feed('<C-n>') + wait() + feed('<C-n>') + wait() + assert.same({'I', 'I', 'P', 'P', 'P'}, eval('g:foo')) + feed('<esc>') + + command('let g:foo = []') + feed('S') + wait() + feed('f') + wait() + feed('<C-n>') + wait() + feed('<C-n>') + wait() + feed('<C-n>') + wait() + feed('<C-n>') + assert.same({'I', 'I', 'P', 'P', 'P', 'P'}, eval('g:foo')) + feed('<esc>') + + assert.same({'foo', 'bar', 'foobar', 'foo'}, eval('getline(1, "$")')) + + source([[ + au! TextChanged + au! TextChangedI + au! TextChangedP + set complete&vim completeopt&vim + ]]) + end) + end) end) |