diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-09-27 18:51:40 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-27 18:51:40 +0800 |
commit | b65f4151d9e52a8521c0682a817c4dab9690e1e7 (patch) | |
tree | e76592f65135cf3b18e9eca05dfe71cd249b20ab | |
parent | dfa8b582a64aa22d3c57261bfcdc970b26cb58f3 (diff) | |
download | rneovim-b65f4151d9e52a8521c0682a817c4dab9690e1e7.tar.gz rneovim-b65f4151d9e52a8521c0682a817c4dab9690e1e7.tar.bz2 rneovim-b65f4151d9e52a8521c0682a817c4dab9690e1e7.zip |
vim-patch:8.2.3517: TextChanged does not trigger after TextChangedI (#25384)
Problem: TextChanged does not trigger after TextChangedI.
Solution: Store the tick separately for TextChangedI. (Christian Brabandt,
closes vim/vim#8968, closes vim/vim#8932)
https://github.com/vim/vim/commit/db3b44640d69ab27270691a3cab8d83cc93a0861
Co-authored-by: Christian Brabandt <cb@256bit.org>
-rw-r--r-- | src/nvim/buffer.c | 1 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 6 | ||||
-rw-r--r-- | src/nvim/bufwrite.c | 4 | ||||
-rw-r--r-- | src/nvim/edit.c | 12 | ||||
-rw-r--r-- | test/functional/autocmd/textchanged_spec.lua | 150 | ||||
-rw-r--r-- | test/functional/editor/completion_spec.lua | 87 | ||||
-rw-r--r-- | test/old/testdir/test_autocmd.vim | 44 |
7 files changed, 204 insertions, 100 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 7a3e65e10e..15fbf7df7b 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -354,6 +354,7 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags_arg) // Set last_changedtick to avoid triggering a TextChanged autocommand right // after it was added. curbuf->b_last_changedtick = buf_get_changedtick(curbuf); + curbuf->b_last_changedtick_i = buf_get_changedtick(curbuf); curbuf->b_last_changedtick_pum = buf_get_changedtick(curbuf); // require "!" to overwrite the file, because it wasn't read completely diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index ff0fca1a56..f267dbb2f1 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -418,10 +418,10 @@ struct file_buffer { /// This is a dictionary item used to store b:changedtick. ChangedtickDictItem changedtick_di; - 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 + varnumber_T b_last_changedtick; // b:changedtick when TextChanged was // last triggered. + varnumber_T b_last_changedtick_i; // b:changedtick for TextChangedI + varnumber_T b_last_changedtick_pum; // b:changedtick for TextChangedP bool b_saving; // Set to true if we are in the middle of // saving the buffer. diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 0c95314c52..2f13586dcc 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -1797,8 +1797,8 @@ restore_backup: unchanged(buf, true, false); const varnumber_T changedtick = buf_get_changedtick(buf); if (buf->b_last_changedtick + 1 == changedtick) { - // b:changedtick may be incremented in unchanged() but that - // should not trigger a TextChanged event. + // b:changedtick may be incremented in unchanged() but that should not + // trigger a TextChanged event. buf->b_last_changedtick = changedtick; } u_unchanged(buf); diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 520d3bc2b3..9169cbcd9c 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1306,9 +1306,9 @@ void ins_redraw(bool ready) last_cursormoved = curwin->w_cursor; } - // Trigger TextChangedI if changedtick differs. + // Trigger TextChangedI if changedtick_i differs. if (ready && has_event(EVENT_TEXTCHANGEDI) - && curbuf->b_last_changedtick != buf_get_changedtick(curbuf) + && curbuf->b_last_changedtick_i != buf_get_changedtick(curbuf) && !pum_visible()) { aco_save_T aco; varnumber_T tick = buf_get_changedtick(curbuf); @@ -1317,16 +1317,16 @@ void ins_redraw(bool ready) aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, false, curbuf); aucmd_restbuf(&aco); - curbuf->b_last_changedtick = buf_get_changedtick(curbuf); + curbuf->b_last_changedtick_i = 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)); } } - // Trigger TextChangedP if changedtick differs. When the popupmenu closes - // TextChangedI will need to trigger for backwards compatibility, thus use - // different b_last_changedtick* variables. + // Trigger TextChangedP if changedtick_pum 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 != buf_get_changedtick(curbuf) && pum_visible()) { diff --git a/test/functional/autocmd/textchanged_spec.lua b/test/functional/autocmd/textchanged_spec.lua new file mode 100644 index 0000000000..ffeb76835d --- /dev/null +++ b/test/functional/autocmd/textchanged_spec.lua @@ -0,0 +1,150 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local exec = helpers.exec +local command = helpers.command +local feed = helpers.feed +local eq = helpers.eq +local eval = helpers.eval +local poke_eventloop = helpers.poke_eventloop + +before_each(clear) + +-- oldtest: Test_ChangedP() +it('TextChangedI and TextChangedP autocommands', function() + -- The oldtest uses feedkeys() with 'x' flag, which never triggers TextChanged. + -- So don't add TextChanged autocommand here. + exec([[ + call setline(1, ['foo', 'bar', 'foobar']) + set complete=. completeopt=menuone + au! TextChangedI <buffer> let g:autocmd ..= 'I' + au! TextChangedP <buffer> let g:autocmd ..= 'P' + call cursor(3, 1) + ]]) + + command([[let g:autocmd = '']]) + feed('o') + poke_eventloop() + feed('<esc>') + eq('I', eval('g:autocmd')) + + command([[let g:autocmd = '']]) + feed('S') + poke_eventloop() + feed('f') + poke_eventloop() + eq('II', eval('g:autocmd')) + feed('<esc>') + + command([[let g:autocmd = '']]) + feed('S') + poke_eventloop() + feed('f') + poke_eventloop() + feed('<C-N>') + poke_eventloop() + eq('IIP', eval('g:autocmd')) + feed('<esc>') + + command([[let g:autocmd = '']]) + feed('S') + poke_eventloop() + feed('f') + poke_eventloop() + feed('<C-N>') + poke_eventloop() + feed('<C-N>') + poke_eventloop() + eq('IIPP', eval('g:autocmd')) + feed('<esc>') + + command([[let g:autocmd = '']]) + feed('S') + poke_eventloop() + feed('f') + poke_eventloop() + feed('<C-N>') + poke_eventloop() + feed('<C-N>') + poke_eventloop() + feed('<C-N>') + poke_eventloop() + eq('IIPPP', eval('g:autocmd')) + feed('<esc>') + + command([[let g:autocmd = '']]) + feed('S') + poke_eventloop() + feed('f') + poke_eventloop() + feed('<C-N>') + poke_eventloop() + feed('<C-N>') + poke_eventloop() + feed('<C-N>') + poke_eventloop() + feed('<C-N>') + eq('IIPPPP', eval('g:autocmd')) + feed('<esc>') + + eq({'foo', 'bar', 'foobar', 'foo'}, eval('getline(1, "$")')) +end) + +-- oldtest: Test_TextChangedI_with_setline() +it('TextChangedI with setline()', function() + exec([[ + let g:setline_handled = v:false + func SetLineOne() + if !g:setline_handled + call setline(1, "(x)") + let g:setline_handled = v:true + endif + endfunc + autocmd TextChangedI <buffer> call SetLineOne() + ]]) + + feed('i') + poke_eventloop() + feed('(') + poke_eventloop() + feed('<CR>') + poke_eventloop() + feed('<Esc>') + eq('(', eval('getline(1)')) + eq('x)', eval('getline(2)')) + command('undo') + eq('', eval('getline(1)')) + eq('', eval('getline(2)')) +end) + +-- oldtest: Test_Changed_ChangedI() +it('TextChanged is triggerd after TextChangedI', function() + exec([[ + let [g:autocmd_i, g:autocmd_n] = ['',''] + + func! TextChangedAutocmdI(char) + let g:autocmd_{tolower(a:char)} = a:char .. b:changedtick + endfunc + + augroup Test_TextChanged + au! + au TextChanged <buffer> :call TextChangedAutocmdI('N') + au TextChangedI <buffer> :call TextChangedAutocmdI('I') + augroup END + ]]) + + feed('i') + poke_eventloop() + feed('f') + poke_eventloop() + feed('o') + poke_eventloop() + feed('o') + poke_eventloop() + feed('<esc>') + eq('N5', eval('g:autocmd_n')) + eq('I5', eval('g:autocmd_i')) + + command([[call feedkeys("yyp", 'tnix')]]) + eq('N6', eval('g:autocmd_n')) + eq('I5', eval('g:autocmd_i')) +end) diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index dcd7ef720f..8c299636cc 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -1032,93 +1032,6 @@ describe('completion', function() ]]) end) - -- oldtest: Test_ChangedP() - it('TextChangedI and TextChangedP autocommands', function() - curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar'}) - source([[ - set complete=. completeopt=menuone - let g:foo = [] - autocmd! TextChanged * :call add(g:foo, "N") - autocmd! TextChangedI * :call add(g:foo, "I") - autocmd! TextChangedP * :call add(g:foo, "P") - call cursor(3, 1) - ]]) - - command('let g:foo = []') - feed('o') - poke_eventloop() - feed('<esc>') - eq({'I'}, eval('g:foo')) - - command('let g:foo = []') - feed('S') - poke_eventloop() - feed('f') - poke_eventloop() - eq({'I', 'I'}, eval('g:foo')) - feed('<esc>') - - command('let g:foo = []') - feed('S') - poke_eventloop() - feed('f') - poke_eventloop() - feed('<C-N>') - poke_eventloop() - eq({'I', 'I', 'P'}, eval('g:foo')) - feed('<esc>') - - command('let g:foo = []') - feed('S') - poke_eventloop() - feed('f') - poke_eventloop() - feed('<C-N>') - poke_eventloop() - feed('<C-N>') - poke_eventloop() - eq({'I', 'I', 'P', 'P'}, eval('g:foo')) - feed('<esc>') - - command('let g:foo = []') - feed('S') - poke_eventloop() - feed('f') - poke_eventloop() - feed('<C-N>') - poke_eventloop() - feed('<C-N>') - poke_eventloop() - feed('<C-N>') - poke_eventloop() - eq({'I', 'I', 'P', 'P', 'P'}, eval('g:foo')) - feed('<esc>') - - command('let g:foo = []') - feed('S') - poke_eventloop() - feed('f') - poke_eventloop() - feed('<C-N>') - poke_eventloop() - feed('<C-N>') - poke_eventloop() - feed('<C-N>') - poke_eventloop() - feed('<C-N>') - eq({'I', 'I', 'P', 'P', 'P', 'P'}, eval('g:foo')) - feed('<esc>') - - eq({'foo', 'bar', 'foobar', 'foo'}, eval('getline(1, "$")')) - - source([[ - au! TextChanged - au! TextChangedI - au! TextChangedP - set complete&vim completeopt&vim - ]]) - end) - it('CompleteChanged autocommand', function() curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar', ''}) source([[ diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index b3238e8214..406de695a3 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -2442,7 +2442,7 @@ endfunc " Test TextChangedI and TextChangedP func Test_ChangedP() - throw 'Skipped: use test/functional/editor/completion_spec.lua' + throw 'Skipped: use test/functional/autocmd/textchanged_spec.lua' new call setline(1, ['foo', 'bar', 'foobar']) call test_override("char_avail", 1) @@ -2452,6 +2452,7 @@ func Test_ChangedP() let g:autocmd .= a:char endfunc + " TextChanged will not be triggered, only check that it isn't. au! TextChanged <buffer> :call TextChangedAutocmd('N') au! TextChangedI <buffer> :call TextChangedAutocmd('I') au! TextChangedP <buffer> :call TextChangedAutocmd('P') @@ -2505,7 +2506,7 @@ func SetLineOne() endfunc func Test_TextChangedI_with_setline() - CheckFunction test_override + throw 'Skipped: use test/functional/autocmd/textchanged_spec.lua' new call test_override('char_avail', 1) autocmd TextChangedI <buffer> call SetLineOne() @@ -3433,6 +3434,45 @@ func Test_autocmd_vimgrep() augroup END endfunc +" Test TextChangedI and TextChanged +func Test_Changed_ChangedI() + throw 'Skipped: use test/functional/autocmd/textchanged_spec.lua' + new + call test_override("char_avail", 1) + let [g:autocmd_i, g:autocmd_n] = ['',''] + + func! TextChangedAutocmdI(char) + let g:autocmd_{tolower(a:char)} = a:char .. b:changedtick + endfunc + + augroup Test_TextChanged + au! + au TextChanged <buffer> :call TextChangedAutocmdI('N') + au TextChangedI <buffer> :call TextChangedAutocmdI('I') + augroup END + + call feedkeys("ifoo\<esc>", 'tnix') + " TODO: Test test does not seem to trigger TextChanged autocommand, this + " requires running Vim in a terminal window. + " call assert_equal('N3', g:autocmd_n) + call assert_equal('I3', g:autocmd_i) + + call feedkeys("yyp", 'tnix') + " TODO: Test test does not seem to trigger TextChanged autocommand. + " call assert_equal('N4', g:autocmd_n) + call assert_equal('I3', g:autocmd_i) + + " CleanUp + call test_override("char_avail", 0) + au! TextChanged <buffer> + au! TextChangedI <buffer> + augroup! Test_TextChanged + delfu TextChangedAutocmdI + unlet! g:autocmd_i g:autocmd_n + + bw! +endfunc + func Test_closing_autocmd_window() let lines =<< trim END edit Xa.txt |