neovim/test/functional/autocmd/textchanged_spec.lua
zeertzjq a469745338
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
2024-04-04 06:11:17 +08:00

212 lines
5.1 KiB
Lua

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 neq = helpers.neq
local eval = helpers.eval
local poke_eventloop = helpers.poke_eventloop
local write_file = helpers.write_file
-- oldtest: Test_ChangedP()
it('TextChangedI and TextChangedP autocommands', function()
clear()
-- 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>')
-- TextChangedI triggers only if text is actually changed in Insert mode
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()
clear()
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_TextChanged_with_norm()
it('TextChanged is triggered after :norm that enters Insert mode', function()
clear()
exec([[
let g:a = 0
au TextChanged * let g:a += 1
]])
eq(0, eval('g:a'))
feed(':norm! ia<CR>')
eq(1, eval('g:a'))
end)
-- oldtest: Test_Changed_ChangedI()
it('TextChangedI and TextChanged', function()
write_file('XTextChangedI2', 'one\ntwo\nthree')
finally(function()
os.remove('XTextChangedI2')
end)
clear('XTextChangedI2')
exec([[
let [g:autocmd_n, g:autocmd_i] = ['','']
func TextChangedAutocmd(char)
let g:autocmd_{tolower(a:char)} = a:char .. b:changedtick
endfunc
au TextChanged <buffer> :call TextChangedAutocmd('N')
au TextChangedI <buffer> :call TextChangedAutocmd('I')
nnoremap <CR> o<Esc>
]])
-- TextChanged should trigger if a mapping enters and leaves Insert mode.
feed('<CR>')
eq('N4', eval('g:autocmd_n'))
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)