mirror of
https://github.com/neovim/neovim.git
synced 2025-09-30 15:08:35 +00:00
vim-patch:9.1.0259: Normal mode TextChanged isn't tested properly (#28167)
Problem: Normal mode TextChanged isn't tested properly.
Solution: Combine Test_Changed_ChangedI() and Test_Changed_ChangedI_2()
and also run it on Windows. Fix a typo in main.c.
(zeertzjq)
closes: vim/vim#14396
c422662933
This commit is contained in:
@@ -289,7 +289,7 @@ static bool is_safe_now(void)
|
|||||||
&& !debug_mode;
|
&& !debug_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trigger SafeState if currently in s safe state, that is "safe" is TRUE and
|
/// Trigger SafeState if currently in a safe state, that is "safe" is true and
|
||||||
/// there is no typeahead.
|
/// there is no typeahead.
|
||||||
void may_trigger_safestate(bool safe)
|
void may_trigger_safestate(bool safe)
|
||||||
{
|
{
|
||||||
|
@@ -7,11 +7,11 @@ local eq = helpers.eq
|
|||||||
local neq = helpers.neq
|
local neq = helpers.neq
|
||||||
local eval = helpers.eval
|
local eval = helpers.eval
|
||||||
local poke_eventloop = helpers.poke_eventloop
|
local poke_eventloop = helpers.poke_eventloop
|
||||||
|
local write_file = helpers.write_file
|
||||||
before_each(clear)
|
|
||||||
|
|
||||||
-- oldtest: Test_ChangedP()
|
-- oldtest: Test_ChangedP()
|
||||||
it('TextChangedI and TextChangedP autocommands', function()
|
it('TextChangedI and TextChangedP autocommands', function()
|
||||||
|
clear()
|
||||||
-- The oldtest uses feedkeys() with 'x' flag, which never triggers TextChanged.
|
-- The oldtest uses feedkeys() with 'x' flag, which never triggers TextChanged.
|
||||||
-- So don't add TextChanged autocommand here.
|
-- So don't add TextChanged autocommand here.
|
||||||
exec([[
|
exec([[
|
||||||
@@ -93,6 +93,7 @@ end)
|
|||||||
|
|
||||||
-- oldtest: Test_TextChangedI_with_setline()
|
-- oldtest: Test_TextChangedI_with_setline()
|
||||||
it('TextChangedI with setline()', function()
|
it('TextChangedI with setline()', function()
|
||||||
|
clear()
|
||||||
exec([[
|
exec([[
|
||||||
let g:setline_handled = v:false
|
let g:setline_handled = v:false
|
||||||
func SetLineOne()
|
func SetLineOne()
|
||||||
@@ -118,70 +119,9 @@ it('TextChangedI with setline()', function()
|
|||||||
eq('', eval('getline(2)'))
|
eq('', eval('getline(2)'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- oldtest: Test_Changed_ChangedI()
|
|
||||||
it('TextChangedI and TextChanged', 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('', eval('g:autocmd_n'))
|
|
||||||
eq('I5', eval('g:autocmd_i'))
|
|
||||||
|
|
||||||
feed('yyp')
|
|
||||||
eq('N6', eval('g:autocmd_n'))
|
|
||||||
eq('I5', eval('g:autocmd_i'))
|
|
||||||
|
|
||||||
-- TextChangedI should only trigger if change was done in Insert mode
|
|
||||||
command([[let g:autocmd_i = '']])
|
|
||||||
feed('yypi<esc>')
|
|
||||||
eq('', eval('g:autocmd_i'))
|
|
||||||
|
|
||||||
command([[let g:autocmd_n = '']])
|
|
||||||
feed('ibar<esc>')
|
|
||||||
eq('N8', eval('g:autocmd_n'))
|
|
||||||
|
|
||||||
local function validate_mixed_textchangedi(keys)
|
|
||||||
feed('ifoo<esc>')
|
|
||||||
command([[let g:autocmd_i = '']])
|
|
||||||
command([[let g:autocmd_n = '']])
|
|
||||||
for _, s in ipairs(keys) do
|
|
||||||
feed(s)
|
|
||||||
poke_eventloop()
|
|
||||||
end
|
|
||||||
neq('', eval('g:autocmd_i'))
|
|
||||||
eq('', eval('g:autocmd_n'))
|
|
||||||
end
|
|
||||||
|
|
||||||
validate_mixed_textchangedi({ 'o', '<esc>' })
|
|
||||||
validate_mixed_textchangedi({ 'O', '<esc>' })
|
|
||||||
validate_mixed_textchangedi({ 'ciw', '<esc>' })
|
|
||||||
validate_mixed_textchangedi({ 'cc', '<esc>' })
|
|
||||||
validate_mixed_textchangedi({ 'C', '<esc>' })
|
|
||||||
validate_mixed_textchangedi({ 's', '<esc>' })
|
|
||||||
validate_mixed_textchangedi({ 'S', '<esc>' })
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- oldtest: Test_TextChanged_with_norm()
|
-- oldtest: Test_TextChanged_with_norm()
|
||||||
it('TextChanged is triggered after :norm that enters Insert mode', function()
|
it('TextChanged is triggered after :norm that enters Insert mode', function()
|
||||||
|
clear()
|
||||||
exec([[
|
exec([[
|
||||||
let g:a = 0
|
let g:a = 0
|
||||||
au TextChanged * let g:a += 1
|
au TextChanged * let g:a += 1
|
||||||
@@ -191,8 +131,14 @@ it('TextChanged is triggered after :norm that enters Insert mode', function()
|
|||||||
eq(1, eval('g:a'))
|
eq(1, eval('g:a'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- oldtest: Test_Changed_ChangedI_2()
|
-- oldtest: Test_Changed_ChangedI()
|
||||||
it('TextChanged is triggered after mapping that enters & exits Insert mode', function()
|
it('TextChangedI and TextChanged', function()
|
||||||
|
write_file('XTextChangedI2', 'one\ntwo\nthree')
|
||||||
|
finally(function()
|
||||||
|
os.remove('XTextChangedI2')
|
||||||
|
end)
|
||||||
|
clear('XTextChangedI2')
|
||||||
|
|
||||||
exec([[
|
exec([[
|
||||||
let [g:autocmd_n, g:autocmd_i] = ['','']
|
let [g:autocmd_n, g:autocmd_i] = ['','']
|
||||||
|
|
||||||
@@ -206,7 +152,60 @@ it('TextChanged is triggered after mapping that enters & exits Insert mode', fun
|
|||||||
nnoremap <CR> o<Esc>
|
nnoremap <CR> o<Esc>
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
-- TextChanged should trigger if a mapping enters and leaves Insert mode.
|
||||||
feed('<CR>')
|
feed('<CR>')
|
||||||
eq('N3', eval('g:autocmd_n'))
|
eq('N4', eval('g:autocmd_n'))
|
||||||
eq('', eval('g:autocmd_i'))
|
eq('', eval('g:autocmd_i'))
|
||||||
|
|
||||||
|
feed('i')
|
||||||
|
eq('N4', eval('g:autocmd_n'))
|
||||||
|
eq('', eval('g:autocmd_i'))
|
||||||
|
-- TextChangedI should trigger if change is done in Insert mode.
|
||||||
|
feed('f')
|
||||||
|
eq('N4', eval('g:autocmd_n'))
|
||||||
|
eq('I5', eval('g:autocmd_i'))
|
||||||
|
feed('o')
|
||||||
|
eq('N4', eval('g:autocmd_n'))
|
||||||
|
eq('I6', eval('g:autocmd_i'))
|
||||||
|
feed('o')
|
||||||
|
eq('N4', eval('g:autocmd_n'))
|
||||||
|
eq('I7', eval('g:autocmd_i'))
|
||||||
|
-- TextChanged shouldn't trigger when leaving Insert mode and TextChangedI
|
||||||
|
-- has been triggered.
|
||||||
|
feed('<Esc>')
|
||||||
|
eq('N4', eval('g:autocmd_n'))
|
||||||
|
eq('I7', eval('g:autocmd_i'))
|
||||||
|
|
||||||
|
-- TextChanged should trigger if change is done in Normal mode.
|
||||||
|
feed('yyp')
|
||||||
|
eq('N8', eval('g:autocmd_n'))
|
||||||
|
eq('I7', eval('g:autocmd_i'))
|
||||||
|
|
||||||
|
-- TextChangedI shouldn't trigger if change isn't done in Insert mode.
|
||||||
|
feed('i')
|
||||||
|
eq('N8', eval('g:autocmd_n'))
|
||||||
|
eq('I7', eval('g:autocmd_i'))
|
||||||
|
feed('<Esc>')
|
||||||
|
eq('N8', eval('g:autocmd_n'))
|
||||||
|
eq('I7', eval('g:autocmd_i'))
|
||||||
|
|
||||||
|
-- TextChangedI should trigger if change is a mix of Normal and Insert modes.
|
||||||
|
local function validate_mixed_textchangedi(keys)
|
||||||
|
feed('ifoo<Esc>')
|
||||||
|
command(":let [g:autocmd_n, g:autocmd_i] = ['', '']")
|
||||||
|
feed(keys)
|
||||||
|
eq('', eval('g:autocmd_n'))
|
||||||
|
neq('', eval('g:autocmd_i'))
|
||||||
|
feed('<Esc>')
|
||||||
|
eq('', eval('g:autocmd_n'))
|
||||||
|
neq('', eval('g:autocmd_i'))
|
||||||
|
end
|
||||||
|
|
||||||
|
validate_mixed_textchangedi('o')
|
||||||
|
validate_mixed_textchangedi('O')
|
||||||
|
validate_mixed_textchangedi('ciw')
|
||||||
|
validate_mixed_textchangedi('cc')
|
||||||
|
validate_mixed_textchangedi('C')
|
||||||
|
validate_mixed_textchangedi('s')
|
||||||
|
validate_mixed_textchangedi('S')
|
||||||
end)
|
end)
|
||||||
|
@@ -3497,69 +3497,6 @@ func Test_autocmd_vimgrep()
|
|||||||
augroup END
|
augroup END
|
||||||
endfunc
|
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)
|
|
||||||
|
|
||||||
" TextChangedI should only trigger if change was done in Insert mode
|
|
||||||
let g:autocmd_i = ''
|
|
||||||
call feedkeys("yypi\<esc>", 'tnix')
|
|
||||||
call assert_equal('', g:autocmd_i)
|
|
||||||
|
|
||||||
" If change is a mix of Normal and Insert modes, TextChangedI should trigger
|
|
||||||
func s:validate_mixed_textchangedi(keys)
|
|
||||||
call feedkeys("ifoo\<esc>", 'tnix')
|
|
||||||
let g:autocmd_i = ''
|
|
||||||
let g:autocmd_n = ''
|
|
||||||
call feedkeys(a:keys, 'tnix')
|
|
||||||
call assert_notequal('', g:autocmd_i)
|
|
||||||
call assert_equal('', g:autocmd_n)
|
|
||||||
endfunc
|
|
||||||
|
|
||||||
call s:validate_mixed_textchangedi("o\<esc>")
|
|
||||||
call s:validate_mixed_textchangedi("O\<esc>")
|
|
||||||
call s:validate_mixed_textchangedi("ciw\<esc>")
|
|
||||||
call s:validate_mixed_textchangedi("cc\<esc>")
|
|
||||||
call s:validate_mixed_textchangedi("C\<esc>")
|
|
||||||
call s:validate_mixed_textchangedi("s\<esc>")
|
|
||||||
call s:validate_mixed_textchangedi("S\<esc>")
|
|
||||||
|
|
||||||
|
|
||||||
" 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()
|
func Test_closing_autocmd_window()
|
||||||
let lines =<< trim END
|
let lines =<< trim END
|
||||||
edit Xa.txt
|
edit Xa.txt
|
||||||
@@ -3953,32 +3890,97 @@ func Test_implicit_session()
|
|||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test TextChangedI and TextChanged
|
" Test TextChangedI and TextChanged
|
||||||
func Test_Changed_ChangedI_2()
|
func Test_Changed_ChangedI()
|
||||||
" Run this test in a terminal because it requires running the main loop.
|
" Run this test in a terminal because it requires running the main loop.
|
||||||
CheckRunVimInTerminal
|
" Don't use CheckRunVimInTerminal as that will skip the test on Windows.
|
||||||
|
CheckFeature terminal
|
||||||
|
CheckNotGui
|
||||||
|
" Starting a terminal to run Vim is always considered flaky.
|
||||||
|
let g:test_is_flaky = 1
|
||||||
|
|
||||||
call writefile(['one', 'two', 'three'], 'XTextChangedI2', 'D')
|
call writefile(['one', 'two', 'three'], 'XTextChangedI2', 'D')
|
||||||
let before =<< trim END
|
let before =<< trim END
|
||||||
|
set ttimeout ttimeoutlen=10
|
||||||
let [g:autocmd_n, g:autocmd_i] = ['','']
|
let [g:autocmd_n, g:autocmd_i] = ['','']
|
||||||
|
|
||||||
func TextChangedAutocmd(char)
|
func TextChangedAutocmd(char)
|
||||||
let g:autocmd_{tolower(a:char)} = a:char .. b:changedtick
|
let g:autocmd_{tolower(a:char)} = a:char .. b:changedtick
|
||||||
call writefile([g:autocmd_n, g:autocmd_i], 'XTextChangedI3')
|
call writefile([$'{g:autocmd_n},{g:autocmd_i}'], 'XTextChangedI3')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
au TextChanged <buffer> :call TextChangedAutocmd('N')
|
au TextChanged <buffer> :call TextChangedAutocmd('N')
|
||||||
au TextChangedI <buffer> :call TextChangedAutocmd('I')
|
au TextChangedI <buffer> :call TextChangedAutocmd('I')
|
||||||
|
|
||||||
nnoremap <CR> o<Esc>
|
nnoremap <CR> o<Esc>
|
||||||
call writefile([], 'XTextChangedI3')
|
call writefile([''], 'XTextChangedI3')
|
||||||
END
|
END
|
||||||
|
|
||||||
call writefile(before, 'Xinit', 'D')
|
call writefile(before, 'Xinit', 'D')
|
||||||
let buf = RunVimInTerminal('-S Xinit XtextChangedI2', {})
|
let buf = term_start(
|
||||||
|
\ GetVimCommandCleanTerm() .. '-n -S Xinit XTextChangedI2',
|
||||||
|
\ {'term_rows': 10})
|
||||||
|
call assert_equal('running', term_getstatus(buf))
|
||||||
call WaitForAssert({-> assert_true(filereadable('XTextChangedI3'))})
|
call WaitForAssert({-> assert_true(filereadable('XTextChangedI3'))})
|
||||||
call term_sendkeys(buf, "\<cr>")
|
|
||||||
call WaitForAssert({-> assert_equal(['N4', ''], readfile('XTextChangedI3'))})
|
|
||||||
call StopVimInTerminal(buf)
|
|
||||||
|
|
||||||
|
" TextChanged should trigger if a mapping enters and leaves Insert mode.
|
||||||
|
call term_sendkeys(buf, "\<CR>")
|
||||||
|
call WaitForAssert({-> assert_equal('N4,', readfile('XTextChangedI3')[0])})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, "i")
|
||||||
|
call WaitForAssert({-> assert_match('^-- INSERT --', term_getline(buf, 10))})
|
||||||
|
call WaitForAssert({-> assert_equal('N4,', readfile('XTextChangedI3')[0])})
|
||||||
|
" TextChangedI should trigger if change is done in Insert mode.
|
||||||
|
call term_sendkeys(buf, "f")
|
||||||
|
call WaitForAssert({-> assert_equal('N4,I5', readfile('XTextChangedI3')[0])})
|
||||||
|
call term_sendkeys(buf, "o")
|
||||||
|
call WaitForAssert({-> assert_equal('N4,I6', readfile('XTextChangedI3')[0])})
|
||||||
|
call term_sendkeys(buf, "o")
|
||||||
|
call WaitForAssert({-> assert_equal('N4,I7', readfile('XTextChangedI3')[0])})
|
||||||
|
" TextChanged shouldn't trigger when leaving Insert mode and TextChangedI
|
||||||
|
" has been triggered.
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
call WaitForAssert({-> assert_notmatch('^-- INSERT --', term_getline(buf, 10))})
|
||||||
|
call WaitForAssert({-> assert_equal('N4,I7', readfile('XTextChangedI3')[0])})
|
||||||
|
|
||||||
|
" TextChanged should trigger if change is done in Normal mode.
|
||||||
|
call term_sendkeys(buf, "yyp")
|
||||||
|
call WaitForAssert({-> assert_equal('N8,I7', readfile('XTextChangedI3')[0])})
|
||||||
|
|
||||||
|
" TextChangedI shouldn't trigger if change isn't done in Insert mode.
|
||||||
|
call term_sendkeys(buf, "i")
|
||||||
|
call WaitForAssert({-> assert_match('^-- INSERT --', term_getline(buf, 10))})
|
||||||
|
call WaitForAssert({-> assert_equal('N8,I7', readfile('XTextChangedI3')[0])})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
call WaitForAssert({-> assert_notmatch('^-- INSERT --', term_getline(buf, 10))})
|
||||||
|
call WaitForAssert({-> assert_equal('N8,I7', readfile('XTextChangedI3')[0])})
|
||||||
|
|
||||||
|
" TextChangedI should trigger if change is a mix of Normal and Insert modes.
|
||||||
|
func! s:validate_mixed_textchangedi(buf, keys)
|
||||||
|
let buf = a:buf
|
||||||
|
call term_sendkeys(buf, "ifoo")
|
||||||
|
call WaitForAssert({-> assert_match('^-- INSERT --', term_getline(buf, 10))})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
call WaitForAssert({-> assert_notmatch('^-- INSERT --', term_getline(buf, 10))})
|
||||||
|
call term_sendkeys(buf, ":let [g:autocmd_n, g:autocmd_i] = ['', '']\<CR>")
|
||||||
|
call delete('XTextChangedI3')
|
||||||
|
call term_sendkeys(buf, a:keys)
|
||||||
|
call WaitForAssert({-> assert_match('^-- INSERT --', term_getline(buf, 10))})
|
||||||
|
call WaitForAssert({-> assert_match('^,I\d\+', readfile('XTextChangedI3')[0])})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
call WaitForAssert({-> assert_notmatch('^-- INSERT --', term_getline(buf, 10))})
|
||||||
|
call WaitForAssert({-> assert_match('^,I\d\+', readfile('XTextChangedI3')[0])})
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
call s:validate_mixed_textchangedi(buf, "o")
|
||||||
|
call s:validate_mixed_textchangedi(buf, "O")
|
||||||
|
call s:validate_mixed_textchangedi(buf, "ciw")
|
||||||
|
call s:validate_mixed_textchangedi(buf, "cc")
|
||||||
|
call s:validate_mixed_textchangedi(buf, "C")
|
||||||
|
call s:validate_mixed_textchangedi(buf, "s")
|
||||||
|
call s:validate_mixed_textchangedi(buf, "S")
|
||||||
|
|
||||||
|
" clean up
|
||||||
|
bwipe!
|
||||||
call delete('XTextChangedI3')
|
call delete('XTextChangedI3')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user