Merge #26398 lintlua for test/ dir

This commit is contained in:
Justin M. Keyes
2024-01-03 03:05:22 -08:00
committed by GitHub
369 changed files with 32907 additions and 22641 deletions

View File

@@ -1,9 +1,12 @@
/build /build/
/.deps/
/runtime/lua/coxpcall.lua /runtime/lua/coxpcall.lua
/runtime/lua/vim/_meta /runtime/lua/vim/_meta
/runtime/lua/vim/re.lua /runtime/lua/vim/re.lua
/test/functional test/functional/ui/decorations_spec.lua
test/functional/ui/float_spec.lua
test/functional/ui/multigrid_spec.lua
/test/functional/fixtures/lua/syntax_error.lua /test/functional/fixtures/lua/syntax_error.lua
/test/functional/legacy/030_fileformats_spec.lua /test/functional/legacy/030_fileformats_spec.lua
/test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua /test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua

View File

@@ -227,7 +227,7 @@ endif()
find_program(SHELLCHECK_PRG shellcheck ${LINT_REQUIRED}) find_program(SHELLCHECK_PRG shellcheck ${LINT_REQUIRED})
find_program(STYLUA_PRG stylua ${LINT_REQUIRED}) find_program(STYLUA_PRG stylua ${LINT_REQUIRED})
set(STYLUA_DIRS runtime scripts src test/unit) set(STYLUA_DIRS runtime scripts src test)
add_glob_target( add_glob_target(
TARGET lintlua-luacheck TARGET lintlua-luacheck
@@ -235,7 +235,7 @@ add_glob_target(
FLAGS -ll ${PROJECT_SOURCE_DIR}/test/lua_runner.lua ${CMAKE_BINARY_DIR}/usr luacheck -q FLAGS -ll ${PROJECT_SOURCE_DIR}/test/lua_runner.lua ${CMAKE_BINARY_DIR}/usr luacheck -q
GLOB_DIRS runtime scripts src test GLOB_DIRS runtime scripts src test
GLOB_PAT *.lua GLOB_PAT *.lua
TOUCH_STRATEGY SINGLE) TOUCH_STRATEGY PER_DIR)
add_dependencies(lintlua-luacheck lua-dev-deps) add_dependencies(lintlua-luacheck lua-dev-deps)
add_glob_target( add_glob_target(
@@ -244,7 +244,7 @@ add_glob_target(
FLAGS --color=always --check --respect-ignores FLAGS --color=always --check --respect-ignores
GLOB_DIRS ${STYLUA_DIRS} GLOB_DIRS ${STYLUA_DIRS}
GLOB_PAT *.lua GLOB_PAT *.lua
TOUCH_STRATEGY SINGLE) TOUCH_STRATEGY PER_DIR)
add_custom_target(lintlua) add_custom_target(lintlua)
add_dependencies(lintlua lintlua-luacheck lintlua-stylua) add_dependencies(lintlua lintlua-luacheck lintlua-stylua)
@@ -255,7 +255,7 @@ add_glob_target(
FLAGS -x -a FLAGS -x -a
GLOB_DIRS scripts GLOB_DIRS scripts
GLOB_PAT *.sh GLOB_PAT *.sh
TOUCH_STRATEGY SINGLE) TOUCH_STRATEGY PER_DIR)
add_custom_target(lintcommit add_custom_target(lintcommit
COMMAND $<TARGET_FILE:nvim> -u NONE -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main) COMMAND $<TARGET_FILE:nvim> -u NONE -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main)
@@ -270,7 +270,8 @@ add_glob_target(
COMMAND ${STYLUA_PRG} COMMAND ${STYLUA_PRG}
FLAGS --respect-ignores FLAGS --respect-ignores
GLOB_DIRS ${STYLUA_DIRS} GLOB_DIRS ${STYLUA_DIRS}
GLOB_PAT *.lua) GLOB_PAT *.lua
TOUCH_STRATEGY PER_DIR)
add_custom_target(format) add_custom_target(format)
add_dependencies(format formatc formatlua) add_dependencies(format formatc formatlua)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@ local pcall_err = helpers.pcall_err
local ok = helpers.ok local ok = helpers.ok
local assert_alive = helpers.assert_alive local assert_alive = helpers.assert_alive
describe('API: highlight',function() describe('API: highlight', function()
clear() clear()
Screen.new() -- initialize Screen.colors Screen.new() -- initialize Screen.colors
@@ -45,31 +45,35 @@ describe('API: highlight',function()
before_each(function() before_each(function()
clear() clear()
command("hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold") command(
'hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold'
)
end) end)
it("nvim_get_hl_by_id", function() it('nvim_get_hl_by_id', function()
local hl_id = eval("hlID('NewHighlight')") local hl_id = eval("hlID('NewHighlight')")
eq(expected_cterm, nvim("get_hl_by_id", hl_id, false)) eq(expected_cterm, nvim('get_hl_by_id', hl_id, false))
hl_id = eval("hlID('NewHighlight')") hl_id = eval("hlID('NewHighlight')")
-- Test valid id. -- Test valid id.
eq(expected_rgb, nvim("get_hl_by_id", hl_id, true)) eq(expected_rgb, nvim('get_hl_by_id', hl_id, true))
-- Test invalid id. -- Test invalid id.
eq('Invalid highlight id: 30000', pcall_err(meths.get_hl_by_id, 30000, false)) eq('Invalid highlight id: 30000', pcall_err(meths.get_hl_by_id, 30000, false))
-- Test all highlight properties. -- Test all highlight properties.
command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine') command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine')
eq(expected_rgb2, nvim("get_hl_by_id", hl_id, true)) eq(expected_rgb2, nvim('get_hl_by_id', hl_id, true))
-- Test undercurl -- Test undercurl
command('hi NewHighlight gui=undercurl') command('hi NewHighlight gui=undercurl')
eq(expected_undercurl, nvim("get_hl_by_id", hl_id, true)) eq(expected_undercurl, nvim('get_hl_by_id', hl_id, true))
-- Test nil argument. -- Test nil argument.
eq('Wrong type for argument 1 when calling nvim_get_hl_by_id, expecting Integer', eq(
pcall_err(meths.get_hl_by_id, { nil }, false)) 'Wrong type for argument 1 when calling nvim_get_hl_by_id, expecting Integer',
pcall_err(meths.get_hl_by_id, { nil }, false)
)
-- Test 0 argument. -- Test 0 argument.
eq('Invalid highlight id: 0', pcall_err(meths.get_hl_by_id, 0, false)) eq('Invalid highlight id: 0', pcall_err(meths.get_hl_by_id, 0, false))
@@ -81,76 +85,83 @@ describe('API: highlight',function()
command('hi Normal ctermfg=red ctermbg=yellow') command('hi Normal ctermfg=red ctermbg=yellow')
command('hi NewConstant ctermfg=green guifg=white guibg=blue') command('hi NewConstant ctermfg=green guifg=white guibg=blue')
hl_id = eval("hlID('NewConstant')") hl_id = eval("hlID('NewConstant')")
eq({foreground = 10,}, meths.get_hl_by_id(hl_id, false)) eq({ foreground = 10 }, meths.get_hl_by_id(hl_id, false))
-- Test highlight group without ctermfg value. -- Test highlight group without ctermfg value.
command('hi clear NewConstant') command('hi clear NewConstant')
command('hi NewConstant ctermbg=Magenta guifg=white guibg=blue') command('hi NewConstant ctermbg=Magenta guifg=white guibg=blue')
eq({background = 13,}, meths.get_hl_by_id(hl_id, false)) eq({ background = 13 }, meths.get_hl_by_id(hl_id, false))
-- Test highlight group with ctermfg and ctermbg values. -- Test highlight group with ctermfg and ctermbg values.
command('hi clear NewConstant') command('hi clear NewConstant')
command('hi NewConstant ctermfg=green ctermbg=Magenta guifg=white guibg=blue') command('hi NewConstant ctermfg=green ctermbg=Magenta guifg=white guibg=blue')
eq({foreground = 10, background = 13,}, meths.get_hl_by_id(hl_id, false)) eq({ foreground = 10, background = 13 }, meths.get_hl_by_id(hl_id, false))
end) end)
it("nvim_get_hl_by_name", function() it('nvim_get_hl_by_name', function()
local expected_normal = { background = Screen.colors.Yellow, local expected_normal = { background = Screen.colors.Yellow, foreground = Screen.colors.Red }
foreground = Screen.colors.Red }
-- Test `Normal` default values. -- Test `Normal` default values.
eq({}, nvim("get_hl_by_name", 'Normal', true)) eq({}, nvim('get_hl_by_name', 'Normal', true))
eq(expected_cterm, nvim("get_hl_by_name", 'NewHighlight', false)) eq(expected_cterm, nvim('get_hl_by_name', 'NewHighlight', false))
eq(expected_rgb, nvim("get_hl_by_name", 'NewHighlight', true)) eq(expected_rgb, nvim('get_hl_by_name', 'NewHighlight', true))
-- Test `Normal` modified values. -- Test `Normal` modified values.
command('hi Normal guifg=red guibg=yellow') command('hi Normal guifg=red guibg=yellow')
eq(expected_normal, nvim("get_hl_by_name", 'Normal', true)) eq(expected_normal, nvim('get_hl_by_name', 'Normal', true))
-- Test invalid name. -- Test invalid name.
eq("Invalid highlight name: 'unknown_highlight'", eq(
pcall_err(meths.get_hl_by_name , 'unknown_highlight', false)) "Invalid highlight name: 'unknown_highlight'",
pcall_err(meths.get_hl_by_name, 'unknown_highlight', false)
)
-- Test nil argument. -- Test nil argument.
eq('Wrong type for argument 1 when calling nvim_get_hl_by_name, expecting String', eq(
pcall_err(meths.get_hl_by_name , { nil }, false)) 'Wrong type for argument 1 when calling nvim_get_hl_by_name, expecting String',
pcall_err(meths.get_hl_by_name, { nil }, false)
)
-- Test empty string argument. -- Test empty string argument.
eq('Invalid highlight name', eq('Invalid highlight name', pcall_err(meths.get_hl_by_name, '', false))
pcall_err(meths.get_hl_by_name , '', false))
-- Test "standout" attribute. #8054 -- Test "standout" attribute. #8054
eq({ underline = true, }, eq({ underline = true }, meths.get_hl_by_name('cursorline', 0))
meths.get_hl_by_name('cursorline', 0));
command('hi CursorLine cterm=standout,underline term=standout,underline gui=standout,underline') command('hi CursorLine cterm=standout,underline term=standout,underline gui=standout,underline')
command('set cursorline') command('set cursorline')
eq({ underline = true, standout = true, }, eq({ underline = true, standout = true }, meths.get_hl_by_name('cursorline', 0))
meths.get_hl_by_name('cursorline', 0));
-- Test cterm & Normal values. #18024 (tail) & #18980 -- Test cterm & Normal values. #18024 (tail) & #18980
-- Ensure Normal, and groups that match Normal return their fg & bg cterm values -- Ensure Normal, and groups that match Normal return their fg & bg cterm values
meths.set_hl(0, 'Normal', {ctermfg = 17, ctermbg = 213}) meths.set_hl(0, 'Normal', { ctermfg = 17, ctermbg = 213 })
meths.set_hl(0, 'NotNormal', {ctermfg = 17, ctermbg = 213, nocombine = true}) meths.set_hl(0, 'NotNormal', { ctermfg = 17, ctermbg = 213, nocombine = true })
-- Note colors are "cterm" values, not rgb-as-ints -- Note colors are "cterm" values, not rgb-as-ints
eq({foreground = 17, background = 213}, nvim("get_hl_by_name", 'Normal', false)) eq({ foreground = 17, background = 213 }, nvim('get_hl_by_name', 'Normal', false))
eq({foreground = 17, background = 213, nocombine = true}, nvim("get_hl_by_name", 'NotNormal', false)) eq(
{ foreground = 17, background = 213, nocombine = true },
nvim('get_hl_by_name', 'NotNormal', false)
)
end) end)
it('nvim_get_hl_id_by_name', function() it('nvim_get_hl_id_by_name', function()
-- precondition: use a hl group that does not yet exist -- precondition: use a hl group that does not yet exist
eq("Invalid highlight name: 'Shrubbery'", pcall_err(meths.get_hl_by_name, "Shrubbery", true)) eq("Invalid highlight name: 'Shrubbery'", pcall_err(meths.get_hl_by_name, 'Shrubbery', true))
eq(0, funcs.hlID("Shrubbery")) eq(0, funcs.hlID('Shrubbery'))
local hl_id = meths.get_hl_id_by_name("Shrubbery") local hl_id = meths.get_hl_id_by_name('Shrubbery')
ok(hl_id > 0) ok(hl_id > 0)
eq(hl_id, funcs.hlID("Shrubbery")) eq(hl_id, funcs.hlID('Shrubbery'))
command('hi Shrubbery guifg=#888888 guibg=#888888') command('hi Shrubbery guifg=#888888 guibg=#888888')
eq({foreground=tonumber("0x888888"), background=tonumber("0x888888")}, eq(
meths.get_hl_by_id(hl_id, true)) { foreground = tonumber('0x888888'), background = tonumber('0x888888') },
eq({foreground=tonumber("0x888888"), background=tonumber("0x888888")}, meths.get_hl_by_id(hl_id, true)
meths.get_hl_by_name("Shrubbery", true)) )
eq(
{ foreground = tonumber('0x888888'), background = tonumber('0x888888') },
meths.get_hl_by_name('Shrubbery', true)
)
end) end)
it("nvim_buf_add_highlight to other buffer doesn't crash if undo is disabled #12873", function() it("nvim_buf_add_highlight to other buffer doesn't crash if undo is disabled #12873", function()
@@ -165,7 +176,7 @@ describe('API: highlight',function()
end) end)
end) end)
describe("API: set highlight", function() describe('API: set highlight', function()
local highlight_color = { local highlight_color = {
fg = tonumber('0xff0000'), fg = tonumber('0xff0000'),
bg = tonumber('0x0032aa'), bg = tonumber('0x0032aa'),
@@ -207,7 +218,7 @@ describe("API: set highlight", function()
strikethrough = true, strikethrough = true,
altfont = true, altfont = true,
nocombine = true, nocombine = true,
} },
} }
local highlight3_result_gui = { local highlight3_result_gui = {
background = highlight_color.bg, background = highlight_color.bg,
@@ -238,31 +249,35 @@ describe("API: set highlight", function()
before_each(clear) before_each(clear)
it('validation', function() it('validation', function()
eq("Invalid 'blend': out of range", eq(
pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend=999})) "Invalid 'blend': out of range",
eq("Invalid 'blend': expected Integer, got Array", pcall_err(meths.set_hl, 0, 'Test_hl3', { fg = '#FF00FF', blend = 999 })
pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend={}})) )
eq(
"Invalid 'blend': expected Integer, got Array",
pcall_err(meths.set_hl, 0, 'Test_hl3', { fg = '#FF00FF', blend = {} })
)
end) end)
it("can set gui highlight", function() it('can set gui highlight', function()
local ns = get_ns() local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight1) meths.set_hl(ns, 'Test_hl', highlight1)
eq(highlight1, meths.get_hl_by_name('Test_hl', true)) eq(highlight1, meths.get_hl_by_name('Test_hl', true))
end) end)
it("can set cterm highlight", function() it('can set cterm highlight', function()
local ns = get_ns() local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight2_config) meths.set_hl(ns, 'Test_hl', highlight2_config)
eq(highlight2_result, meths.get_hl_by_name('Test_hl', false)) eq(highlight2_result, meths.get_hl_by_name('Test_hl', false))
end) end)
it("can set empty cterm attr", function() it('can set empty cterm attr', function()
local ns = get_ns() local ns = get_ns()
meths.set_hl(ns, 'Test_hl', { cterm = {} }) meths.set_hl(ns, 'Test_hl', { cterm = {} })
eq({}, meths.get_hl_by_name('Test_hl', false)) eq({}, meths.get_hl_by_name('Test_hl', false))
end) end)
it("cterm attr defaults to gui attr", function() it('cterm attr defaults to gui attr', function()
local ns = get_ns() local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight1) meths.set_hl(ns, 'Test_hl', highlight1)
eq({ eq({
@@ -271,14 +286,14 @@ describe("API: set highlight", function()
}, meths.get_hl_by_name('Test_hl', false)) }, meths.get_hl_by_name('Test_hl', false))
end) end)
it("can overwrite attr for cterm", function() it('can overwrite attr for cterm', function()
local ns = get_ns() local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight3_config) meths.set_hl(ns, 'Test_hl', highlight3_config)
eq(highlight3_result_gui, meths.get_hl_by_name('Test_hl', true)) eq(highlight3_result_gui, meths.get_hl_by_name('Test_hl', true))
eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false)) eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false))
end) end)
it("only allows one underline attribute #22371", function() it('only allows one underline attribute #22371', function()
local ns = get_ns() local ns = get_ns()
meths.set_hl(ns, 'Test_hl', { meths.set_hl(ns, 'Test_hl', {
underdouble = true, underdouble = true,
@@ -292,80 +307,76 @@ describe("API: set highlight", function()
eq({ underdotted = true }, meths.get_hl_by_name('Test_hl', true)) eq({ underdotted = true }, meths.get_hl_by_name('Test_hl', true))
end) end)
it("can set a highlight in the global namespace", function() it('can set a highlight in the global namespace', function()
meths.set_hl(0, 'Test_hl', highlight2_config) meths.set_hl(0, 'Test_hl', highlight2_config)
eq('Test_hl xxx cterm=underline,reverse ctermfg=8 ctermbg=15 gui=underline,reverse', eq(
exec_capture('highlight Test_hl')) 'Test_hl xxx cterm=underline,reverse ctermfg=8 ctermbg=15 gui=underline,reverse',
exec_capture('highlight Test_hl')
)
meths.set_hl(0, 'Test_hl', { background = highlight_color.bg }) meths.set_hl(0, 'Test_hl', { background = highlight_color.bg })
eq('Test_hl xxx guibg=#0032aa', eq('Test_hl xxx guibg=#0032aa', exec_capture('highlight Test_hl'))
exec_capture('highlight Test_hl'))
meths.set_hl(0, 'Test_hl2', highlight3_config) meths.set_hl(0, 'Test_hl2', highlight3_config)
eq('Test_hl2 xxx cterm=italic,reverse,strikethrough,altfont,nocombine ctermfg=8 ctermbg=15 gui=bold,underdashed,italic,reverse,strikethrough,altfont guifg=#ff0000 guibg=#0032aa', eq(
exec_capture('highlight Test_hl2')) 'Test_hl2 xxx cterm=italic,reverse,strikethrough,altfont,nocombine ctermfg=8 ctermbg=15 gui=bold,underdashed,italic,reverse,strikethrough,altfont guifg=#ff0000 guibg=#0032aa',
exec_capture('highlight Test_hl2')
)
-- Colors are stored with the name they are defined, but -- Colors are stored with the name they are defined, but
-- with canonical casing -- with canonical casing
meths.set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue'}) meths.set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue' })
eq('Test_hl3 xxx guifg=Blue guibg=Red', eq('Test_hl3 xxx guifg=Blue guibg=Red', exec_capture('highlight Test_hl3'))
exec_capture('highlight Test_hl3'))
end) end)
it("can modify a highlight in the global namespace", function() it('can modify a highlight in the global namespace', function()
meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue'}) meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue' })
eq('Test_hl3 xxx guifg=Blue guibg=Red', eq('Test_hl3 xxx guifg=Blue guibg=Red', exec_capture('highlight Test_hl3'))
exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { bg = 'red' }) meths.set_hl(0, 'Test_hl3', { bg = 'red' })
eq('Test_hl3 xxx guibg=Red', eq('Test_hl3 xxx guibg=Red', exec_capture('highlight Test_hl3'))
exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { ctermbg = 9, ctermfg = 12}) meths.set_hl(0, 'Test_hl3', { ctermbg = 9, ctermfg = 12 })
eq('Test_hl3 xxx ctermfg=12 ctermbg=9', eq('Test_hl3 xxx ctermfg=12 ctermbg=9', exec_capture('highlight Test_hl3'))
exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { ctermbg = 'red' , ctermfg = 'blue'}) meths.set_hl(0, 'Test_hl3', { ctermbg = 'red', ctermfg = 'blue' })
eq('Test_hl3 xxx ctermfg=12 ctermbg=9', eq('Test_hl3 xxx ctermfg=12 ctermbg=9', exec_capture('highlight Test_hl3'))
exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { ctermbg = 9 }) meths.set_hl(0, 'Test_hl3', { ctermbg = 9 })
eq('Test_hl3 xxx ctermbg=9', eq('Test_hl3 xxx ctermbg=9', exec_capture('highlight Test_hl3'))
exec_capture('highlight Test_hl3'))
eq("Invalid highlight color: 'redd'", eq("Invalid highlight color: 'redd'", pcall_err(meths.set_hl, 0, 'Test_hl3', { fg = 'redd' }))
pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='redd'}))
eq("Invalid highlight color: 'bleu'", eq(
pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='bleu'})) "Invalid highlight color: 'bleu'",
pcall_err(meths.set_hl, 0, 'Test_hl3', { ctermfg = 'bleu' })
)
meths.set_hl(0, 'Test_hl3', {fg='#FF00FF'}) meths.set_hl(0, 'Test_hl3', { fg = '#FF00FF' })
eq('Test_hl3 xxx guifg=#ff00ff', eq('Test_hl3 xxx guifg=#ff00ff', exec_capture('highlight Test_hl3'))
exec_capture('highlight Test_hl3'))
eq("Invalid highlight color: '#FF00FF'", eq(
pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='#FF00FF'})) "Invalid highlight color: '#FF00FF'",
pcall_err(meths.set_hl, 0, 'Test_hl3', { ctermfg = '#FF00FF' })
)
for _, fg_val in ipairs{ nil, 'NONE', 'nOnE', '', -1 } do for _, fg_val in ipairs { nil, 'NONE', 'nOnE', '', -1 } do
meths.set_hl(0, 'Test_hl3', {fg = fg_val}) meths.set_hl(0, 'Test_hl3', { fg = fg_val })
eq('Test_hl3 xxx cleared', eq('Test_hl3 xxx cleared', exec_capture('highlight Test_hl3'))
exec_capture('highlight Test_hl3'))
end end
meths.set_hl(0, 'Test_hl3', {fg='#FF00FF', blend=50}) meths.set_hl(0, 'Test_hl3', { fg = '#FF00FF', blend = 50 })
eq('Test_hl3 xxx guifg=#ff00ff blend=50', eq('Test_hl3 xxx guifg=#ff00ff blend=50', exec_capture('highlight Test_hl3'))
exec_capture('highlight Test_hl3'))
end) end)
it("correctly sets 'Normal' internal properties", function() it("correctly sets 'Normal' internal properties", function()
-- Normal has some special handling internally. #18024 -- Normal has some special handling internally. #18024
meths.set_hl(0, 'Normal', {fg='#000083', bg='#0000F3'}) meths.set_hl(0, 'Normal', { fg = '#000083', bg = '#0000F3' })
eq({foreground = 131, background = 243}, nvim("get_hl_by_name", 'Normal', true)) eq({ foreground = 131, background = 243 }, nvim('get_hl_by_name', 'Normal', true))
end) end)
it('does not segfault on invalid group name #20009', function() it('does not segfault on invalid group name #20009', function()
eq("Invalid highlight name: 'foo bar'", pcall_err(meths.set_hl, 0, 'foo bar', {bold = true})) eq("Invalid highlight name: 'foo bar'", pcall_err(meths.set_hl, 0, 'foo bar', { bold = true }))
assert_alive() assert_alive()
end) end)
end) end)
@@ -380,14 +391,16 @@ describe('API: get highlight', function()
local highlight1 = { local highlight1 = {
bg = highlight_color.bg, bg = highlight_color.bg,
fg = highlight_color.fg, fg = highlight_color.fg,
bold = true, italic = true, bold = true,
cterm = {bold = true, italic = true}, italic = true,
cterm = { bold = true, italic = true },
} }
local highlight2 = { local highlight2 = {
ctermbg = highlight_color.ctermbg, ctermbg = highlight_color.ctermbg,
ctermfg = highlight_color.ctermfg, ctermfg = highlight_color.ctermfg,
underline = true, reverse = true, underline = true,
cterm = {underline = true, reverse = true}, reverse = true,
cterm = { underline = true, reverse = true },
} }
local highlight3_config = { local highlight3_config = {
bg = highlight_color.bg, bg = highlight_color.bg,
@@ -413,8 +426,19 @@ describe('API: get highlight', function()
fg = highlight_color.fg, fg = highlight_color.fg,
ctermbg = highlight_color.ctermbg, ctermbg = highlight_color.ctermbg,
ctermfg = highlight_color.ctermfg, ctermfg = highlight_color.ctermfg,
bold = true, italic = true, reverse = true, underdashed = true, strikethrough = true, altfont = true, bold = true,
cterm = {italic = true, nocombine = true, reverse = true, strikethrough = true, altfont = true} italic = true,
reverse = true,
underdashed = true,
strikethrough = true,
altfont = true,
cterm = {
italic = true,
nocombine = true,
reverse = true,
strikethrough = true,
altfont = true,
},
} }
local function get_ns() local function get_ns()
@@ -434,17 +458,16 @@ describe('API: get highlight', function()
before_each(clear) before_each(clear)
it('validation', function() it('validation', function()
eq("Invalid 'name': expected String, got Integer", eq("Invalid 'name': expected String, got Integer", pcall_err(meths.get_hl, 0, { name = 177 }))
pcall_err(meths.get_hl, 0, { name = 177 }))
eq('Highlight id out of bounds', pcall_err(meths.get_hl, 0, { name = 'Test set hl' })) eq('Highlight id out of bounds', pcall_err(meths.get_hl, 0, { name = 'Test set hl' }))
end) end)
it('nvim_get_hl with create flag', function() it('nvim_get_hl with create flag', function()
eq({}, nvim("get_hl", 0, {name = 'Foo', create = false})) eq({}, nvim('get_hl', 0, { name = 'Foo', create = false }))
eq(0, funcs.hlexists('Foo')) eq(0, funcs.hlexists('Foo'))
meths.get_hl(0, {name = 'Bar', create = true}) meths.get_hl(0, { name = 'Bar', create = true })
eq(1, funcs.hlexists('Bar')) eq(1, funcs.hlexists('Bar'))
meths.get_hl(0, {name = 'FooBar'}) meths.get_hl(0, { name = 'FooBar' })
eq(1, funcs.hlexists('FooBar')) eq(1, funcs.hlexists('FooBar'))
end) end)
@@ -454,11 +477,11 @@ describe('API: get highlight', function()
meths.set_hl(ns, 'Test_hl_link', { link = 'Test_hl' }) meths.set_hl(ns, 'Test_hl_link', { link = 'Test_hl' })
eq({ eq({
Test_hl = { Test_hl = {
bg = 11845374 bg = 11845374,
}, },
Test_hl_link = { Test_hl_link = {
link = 'Test_hl' link = 'Test_hl',
} },
}, meths.get_hl(ns, {})) }, meths.get_hl(ns, {}))
end) end)
@@ -502,8 +525,7 @@ describe('API: get highlight', function()
undercurl = true, undercurl = true,
}, },
}) })
eq({ underdotted = true, cterm = { undercurl = true} }, eq({ underdotted = true, cterm = { undercurl = true } }, meths.get_hl(ns, { name = 'Test_hl' }))
meths.get_hl(ns, { name = 'Test_hl' }))
end) end)
it('can get a highlight in the global namespace', function() it('can get a highlight in the global namespace', function()
@@ -533,8 +555,13 @@ describe('API: get highlight', function()
command( command(
'hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold' 'hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold'
) )
eq({ fg = 16711680, bg = 16776960, sp = 255, bold = true, eq({
ctermbg = 10, cterm = { underline = true }, fg = 16711680,
bg = 16776960,
sp = 255,
bold = true,
ctermbg = 10,
cterm = { underline = true },
}, meths.get_hl(0, { id = hl_id })) }, meths.get_hl(0, { id = hl_id }))
-- Test 0 argument -- Test 0 argument
@@ -547,16 +574,30 @@ describe('API: get highlight', function()
-- Test all highlight properties. -- Test all highlight properties.
command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine') command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine')
eq({ fg = 16711680, bg = 16776960, sp = 255, eq({
altfont = true, bold = true, italic = true, nocombine = true, reverse = true, strikethrough = true, underline = true, fg = 16711680,
ctermbg = 10, cterm = {underline = true}, bg = 16776960,
sp = 255,
altfont = true,
bold = true,
italic = true,
nocombine = true,
reverse = true,
strikethrough = true,
underline = true,
ctermbg = 10,
cterm = { underline = true },
}, meths.get_hl(0, { id = hl_id })) }, meths.get_hl(0, { id = hl_id }))
-- Test undercurl -- Test undercurl
command('hi NewHighlight gui=undercurl') command('hi NewHighlight gui=undercurl')
eq({ fg = 16711680, bg = 16776960, sp = 255, undercurl = true, eq({
ctermbg = 10, fg = 16711680,
cterm = {underline = true}, bg = 16776960,
sp = 255,
undercurl = true,
ctermbg = 10,
cterm = { underline = true },
}, meths.get_hl(0, { id = hl_id })) }, meths.get_hl(0, { id = hl_id }))
end) end)
@@ -573,7 +614,10 @@ describe('API: get highlight', function()
command('hi Bar guifg=red') command('hi Bar guifg=red')
command('hi Foo guifg=#00ff00 gui=bold,underline') command('hi Foo guifg=#00ff00 gui=bold,underline')
command('hi! link Foo Bar') command('hi! link Foo Bar')
eq({ link = 'Bar', fg = tonumber('00ff00', 16), bold = true, underline = true }, meths.get_hl(0, { name = 'Foo', link = true })) eq(
{ link = 'Bar', fg = tonumber('00ff00', 16), bold = true, underline = true },
meths.get_hl(0, { name = 'Foo', link = true })
)
end) end)
it('can set link as well as other attributes', function() it('can set link as well as other attributes', function()
@@ -584,57 +628,57 @@ describe('API: get highlight', function()
end) end)
it("doesn't contain unset groups", function() it("doesn't contain unset groups", function()
local id = meths.get_hl_id_by_name "@foobar.hubbabubba" local id = meths.get_hl_id_by_name '@foobar.hubbabubba'
ok(id > 0) ok(id > 0)
local data = meths.get_hl(0, {}) local data = meths.get_hl(0, {})
eq(nil, data["@foobar.hubbabubba"]) eq(nil, data['@foobar.hubbabubba'])
eq(nil, data["@foobar"]) eq(nil, data['@foobar'])
command 'hi @foobar.hubbabubba gui=bold' command 'hi @foobar.hubbabubba gui=bold'
data = meths.get_hl(0, {}) data = meths.get_hl(0, {})
eq({bold = true}, data["@foobar.hubbabubba"]) eq({ bold = true }, data['@foobar.hubbabubba'])
eq(nil, data["@foobar"]) eq(nil, data['@foobar'])
-- @foobar.hubbabubba was explicitly cleared and thus shows up -- @foobar.hubbabubba was explicitly cleared and thus shows up
-- but @foobar was never touched, and thus doesn't -- but @foobar was never touched, and thus doesn't
command 'hi clear @foobar.hubbabubba' command 'hi clear @foobar.hubbabubba'
data = meths.get_hl(0, {}) data = meths.get_hl(0, {})
eq({}, data["@foobar.hubbabubba"]) eq({}, data['@foobar.hubbabubba'])
eq(nil, data["@foobar"]) eq(nil, data['@foobar'])
end) end)
it('should return default flag', function() it('should return default flag', function()
meths.set_hl(0, 'Tried', { fg = "#00ff00", default = true }) meths.set_hl(0, 'Tried', { fg = '#00ff00', default = true })
eq({ fg = tonumber('00ff00', 16), default = true }, meths.get_hl(0, { name = 'Tried' })) eq({ fg = tonumber('00ff00', 16), default = true }, meths.get_hl(0, { name = 'Tried' }))
end) end)
it('should not output empty gui and cterm #23474', function() it('should not output empty gui and cterm #23474', function()
meths.set_hl(0, 'Foo', {default = true}) meths.set_hl(0, 'Foo', { default = true })
meths.set_hl(0, 'Bar', { default = true, fg = '#ffffff' }) meths.set_hl(0, 'Bar', { default = true, fg = '#ffffff' })
meths.set_hl(0, 'FooBar', { default = true, fg = '#ffffff', cterm = {bold = true} }) meths.set_hl(0, 'FooBar', { default = true, fg = '#ffffff', cterm = { bold = true } })
meths.set_hl(0, 'FooBarA', { default = true, fg = '#ffffff', cterm = {bold = true,italic = true}}) meths.set_hl(
0,
'FooBarA',
{ default = true, fg = '#ffffff', cterm = { bold = true, italic = true } }
)
eq('Foo xxx cleared', eq('Foo xxx cleared', exec_capture('highlight Foo'))
exec_capture('highlight Foo')) eq({ default = true }, meths.get_hl(0, { name = 'Foo' }))
eq({default = true}, meths.get_hl(0, {name = 'Foo'})) eq('Bar xxx guifg=#ffffff', exec_capture('highlight Bar'))
eq('Bar xxx guifg=#ffffff', eq('FooBar xxx cterm=bold guifg=#ffffff', exec_capture('highlight FooBar'))
exec_capture('highlight Bar')) eq('FooBarA xxx cterm=bold,italic guifg=#ffffff', exec_capture('highlight FooBarA'))
eq('FooBar xxx cterm=bold guifg=#ffffff',
exec_capture('highlight FooBar'))
eq('FooBarA xxx cterm=bold,italic guifg=#ffffff',
exec_capture('highlight FooBarA'))
end) end)
it('can override exist highlight group by force #20323', function() it('can override exist highlight group by force #20323', function()
local white = tonumber('ffffff', 16) local white = tonumber('ffffff', 16)
local green = tonumber('00ff00', 16) local green = tonumber('00ff00', 16)
meths.set_hl(0, 'Foo', { fg=white }) meths.set_hl(0, 'Foo', { fg = white })
meths.set_hl(0, 'Foo', { fg=green, force = true }) meths.set_hl(0, 'Foo', { fg = green, force = true })
eq({ fg = green },meths.get_hl(0, {name = 'Foo'})) eq({ fg = green }, meths.get_hl(0, { name = 'Foo' }))
meths.set_hl(0, 'Bar', {link = 'Comment', default = true}) meths.set_hl(0, 'Bar', { link = 'Comment', default = true })
meths.set_hl(0, 'Bar', {link = 'Foo',default = true, force = true}) meths.set_hl(0, 'Bar', { link = 'Foo', default = true, force = true })
eq({link ='Foo', default = true}, meths.get_hl(0, {name = 'Bar'})) eq({ link = 'Foo', default = true }, meths.get_hl(0, { name = 'Bar' }))
end) end)
end) end)
@@ -647,9 +691,9 @@ describe('API: set/get highlight namespace', function()
end) end)
it('set/get window highlight namespace', function() it('set/get window highlight namespace', function()
eq(-1, meths.get_hl_ns({winid = 0})) eq(-1, meths.get_hl_ns({ winid = 0 }))
local ns = meths.create_namespace('') local ns = meths.create_namespace('')
meths.win_set_hl_ns(0, ns) meths.win_set_hl_ns(0, ns)
eq(ns, meths.get_hl_ns({winid = 0})) eq(ns, meths.get_hl_ns({ winid = 0 }))
end) end)
end) end)

File diff suppressed because it is too large Load Diff

View File

@@ -5,8 +5,7 @@ local clear = helpers.clear
local command = helpers.command local command = helpers.command
local feed = helpers.feed local feed = helpers.feed
describe("update_menu notification", function() describe('update_menu notification', function()
local screen local screen
before_each(function() before_each(function()
@@ -16,23 +15,26 @@ describe("update_menu notification", function()
end) end)
local function expect_sent(expected) local function expect_sent(expected)
screen:expect{condition=function() screen:expect {
if screen.update_menu ~= expected then condition = function()
if expected then if screen.update_menu ~= expected then
error('update_menu was expected but not sent') if expected then
else error('update_menu was expected but not sent')
error('update_menu was sent unexpectedly') else
error('update_menu was sent unexpectedly')
end
end end
end end,
end, unchanged=(not expected)} unchanged = not expected,
}
end end
it("should be sent when adding a menu", function() it('should be sent when adding a menu', function()
command('menu Test.Test :') command('menu Test.Test :')
expect_sent(true) expect_sent(true)
end) end)
it("should be sent when deleting a menu", function() it('should be sent when deleting a menu', function()
command('menu Test.Test :') command('menu Test.Test :')
screen.update_menu = false screen.update_menu = false
@@ -40,9 +42,8 @@ describe("update_menu notification", function()
expect_sent(true) expect_sent(true)
end) end)
it("should not be sent unnecessarily", function() it('should not be sent unnecessarily', function()
feed('i12345<ESC>:redraw<CR>') feed('i12345<ESC>:redraw<CR>')
expect_sent(false) expect_sent(false)
end) end)
end) end)

View File

@@ -43,16 +43,16 @@ describe('API', function()
end) end)
it('validation', function() it('validation', function()
local status, rv = pcall(request, "nvim_get_proc_children", -1) local status, rv = pcall(request, 'nvim_get_proc_children', -1)
eq(false, status) eq(false, status)
eq("Invalid 'pid': -1", string.match(rv, "Invalid.*")) eq("Invalid 'pid': -1", string.match(rv, 'Invalid.*'))
status, rv = pcall(request, "nvim_get_proc_children", 0) status, rv = pcall(request, 'nvim_get_proc_children', 0)
eq(false, status) eq(false, status)
eq("Invalid 'pid': 0", string.match(rv, "Invalid.*")) eq("Invalid 'pid': 0", string.match(rv, 'Invalid.*'))
-- Assume PID 99999 does not exist. -- Assume PID 99999 does not exist.
status, rv = pcall(request, "nvim_get_proc_children", 99999) status, rv = pcall(request, 'nvim_get_proc_children', 99999)
eq(true, status) eq(true, status)
eq({}, rv) eq({}, rv)
end) end)
@@ -69,16 +69,16 @@ describe('API', function()
end) end)
it('validation', function() it('validation', function()
local status, rv = pcall(request, "nvim_get_proc", -1) local status, rv = pcall(request, 'nvim_get_proc', -1)
eq(false, status) eq(false, status)
eq("Invalid 'pid': -1", string.match(rv, "Invalid.*")) eq("Invalid 'pid': -1", string.match(rv, 'Invalid.*'))
status, rv = pcall(request, "nvim_get_proc", 0) status, rv = pcall(request, 'nvim_get_proc', 0)
eq(false, status) eq(false, status)
eq("Invalid 'pid': 0", string.match(rv, "Invalid.*")) eq("Invalid 'pid': 0", string.match(rv, 'Invalid.*'))
-- Assume PID 99999 does not exist. -- Assume PID 99999 does not exist.
status, rv = pcall(request, "nvim_get_proc", 99999) status, rv = pcall(request, 'nvim_get_proc', 99999)
eq(true, status) eq(true, status)
eq(NIL, rv) eq(NIL, rv)
end) end)

View File

@@ -4,8 +4,8 @@
package.path = arg[1] package.path = arg[1]
package.cpath = arg[2] package.cpath = arg[2]
local StdioStream = require'test.client.uv_stream'.StdioStream local StdioStream = require 'test.client.uv_stream'.StdioStream
local Session = require'test.client.session' local Session = require 'test.client.session'
local stdio_stream = StdioStream.open() local stdio_stream = StdioStream.open()
local session = Session.new(stdio_stream) local session = Session.new(stdio_stream)
@@ -15,8 +15,8 @@ local function on_request(method, args)
return 'ok' return 'ok'
elseif method == 'write_stderr' then elseif method == 'write_stderr' then
io.stderr:write(args[1]) io.stderr:write(args[1])
return "done!" return 'done!'
elseif method == "exit" then elseif method == 'exit' then
session:stop() session:stop()
return vim.NIL return vim.NIL
end end
@@ -24,7 +24,7 @@ end
local function on_notification(event, args) local function on_notification(event, args)
if event == 'ping' and #args == 0 then if event == 'ping' and #args == 0 then
session:notify("nvim_eval", "rpcnotify(g:channel, 'pong')") session:notify('nvim_eval', "rpcnotify(g:channel, 'pong')")
end end
end end

View File

@@ -1,8 +1,7 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local assert_log = helpers.assert_log local assert_log = helpers.assert_log
local eq, clear, eval, command, nvim, next_msg = local eq, clear, eval, command, nvim, next_msg =
helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.nvim, helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.nvim, helpers.next_msg
helpers.next_msg
local meths = helpers.meths local meths = helpers.meths
local exec_lua = helpers.exec_lua local exec_lua = helpers.exec_lua
local retry = helpers.retry local retry = helpers.retry
@@ -24,11 +23,11 @@ describe('notify', function()
describe('passing a valid channel id', function() describe('passing a valid channel id', function()
it('sends the notification/args to the corresponding channel', function() it('sends the notification/args to the corresponding channel', function()
eval('rpcnotify('..channel..', "test-event", 1, 2, 3)') eval('rpcnotify(' .. channel .. ', "test-event", 1, 2, 3)')
eq({'notification', 'test-event', {1, 2, 3}}, next_msg()) eq({ 'notification', 'test-event', { 1, 2, 3 } }, next_msg())
command('au FileType lua call rpcnotify('..channel..', "lua!")') command('au FileType lua call rpcnotify(' .. channel .. ', "lua!")')
command('set filetype=lua') command('set filetype=lua')
eq({'notification', 'lua!', {}}, next_msg()) eq({ 'notification', 'lua!', {} }, next_msg())
end) end)
end) end)
@@ -38,20 +37,20 @@ describe('notify', function()
eval('rpcnotify(0, "event1", 1, 2, 3)') eval('rpcnotify(0, "event1", 1, 2, 3)')
eval('rpcnotify(0, "event2", 4, 5, 6)') eval('rpcnotify(0, "event2", 4, 5, 6)')
eval('rpcnotify(0, "event2", 7, 8, 9)') eval('rpcnotify(0, "event2", 7, 8, 9)')
eq({'notification', 'event2', {4, 5, 6}}, next_msg()) eq({ 'notification', 'event2', { 4, 5, 6 } }, next_msg())
eq({'notification', 'event2', {7, 8, 9}}, next_msg()) eq({ 'notification', 'event2', { 7, 8, 9 } }, next_msg())
nvim('unsubscribe', 'event2') nvim('unsubscribe', 'event2')
nvim('subscribe', 'event1') nvim('subscribe', 'event1')
eval('rpcnotify(0, "event2", 10, 11, 12)') eval('rpcnotify(0, "event2", 10, 11, 12)')
eval('rpcnotify(0, "event1", 13, 14, 15)') eval('rpcnotify(0, "event1", 13, 14, 15)')
eq({'notification', 'event1', {13, 14, 15}}, next_msg()) eq({ 'notification', 'event1', { 13, 14, 15 } }, next_msg())
end) end)
it('does not crash for deeply nested variable', function() it('does not crash for deeply nested variable', function()
meths.set_var('l', {}) meths.set_var('l', {})
local nest_level = 1000 local nest_level = 1000
meths.command(('call map(range(%u), "extend(g:, {\'l\': [g:l]})")'):format(nest_level - 1)) meths.command(('call map(range(%u), "extend(g:, {\'l\': [g:l]})")'):format(nest_level - 1))
eval('rpcnotify('..channel..', "event", g:l)') eval('rpcnotify(' .. channel .. ', "event", g:l)')
local msg = next_msg() local msg = next_msg()
eq('notification', msg[1]) eq('notification', msg[1])
eq('event', msg[2]) eq('event', msg[2])
@@ -77,9 +76,9 @@ describe('notify', function()
end) end)
it('unsubscribe non-existing event #8745', function() it('unsubscribe non-existing event #8745', function()
clear{env={ clear { env = {
NVIM_LOG_FILE=testlog, NVIM_LOG_FILE = testlog,
}} } }
nvim('subscribe', 'event1') nvim('subscribe', 'event1')
nvim('unsubscribe', 'doesnotexist') nvim('unsubscribe', 'doesnotexist')
assert_log("tried to unsubscribe unknown event 'doesnotexist'", testlog, 10) assert_log("tried to unsubscribe unknown event 'doesnotexist'", testlog, 10)
@@ -90,14 +89,24 @@ describe('notify', function()
it('cancels stale events on channel close', function() it('cancels stale events on channel close', function()
local catchan = eval("jobstart(['cat'], {'rpc': v:true})") local catchan = eval("jobstart(['cat'], {'rpc': v:true})")
local catpath = eval('exepath("cat")') local catpath = eval('exepath("cat")')
eq({id=catchan, argv={catpath}, stream='job', mode='rpc', client = {}}, exec_lua ([[ eq(
{ id = catchan, argv = { catpath }, stream = 'job', mode = 'rpc', client = {} },
exec_lua(
[[
vim.rpcnotify(..., "nvim_call_function", 'chanclose', {..., 'rpc'}) vim.rpcnotify(..., "nvim_call_function", 'chanclose', {..., 'rpc'})
vim.rpcnotify(..., "nvim_subscribe", "daily_rant") vim.rpcnotify(..., "nvim_subscribe", "daily_rant")
return vim.api.nvim_get_chan_info(...) return vim.api.nvim_get_chan_info(...)
]], catchan)) ]],
catchan
)
)
assert_alive() assert_alive()
eq({false, 'Invalid channel: '..catchan}, eq(
exec_lua ([[ return {pcall(vim.rpcrequest, ..., 'nvim_eval', '1+1')}]], catchan)) { false, 'Invalid channel: ' .. catchan },
retry(nil, 3000, function() eq({}, meths.get_chan_info(catchan)) end) -- cat be dead :( exec_lua([[ return {pcall(vim.rpcrequest, ..., 'nvim_eval', '1+1')}]], catchan)
)
retry(nil, 3000, function()
eq({}, meths.get_chan_info(catchan))
end) -- cat be dead :(
end) end)
end) end)

View File

@@ -40,13 +40,13 @@ describe('server -> client', function()
describe('simple call', function() describe('simple call', function()
it('works', function() it('works', function()
local function on_setup() local function on_setup()
eq({4, 5, 6}, eval('rpcrequest('..cid..', "scall", 1, 2, 3)')) eq({ 4, 5, 6 }, eval('rpcrequest(' .. cid .. ', "scall", 1, 2, 3)'))
stop() stop()
end end
local function on_request(method, args) local function on_request(method, args)
eq('scall', method) eq('scall', method)
eq({1, 2, 3}, args) eq({ 1, 2, 3 }, args)
nvim('command', 'let g:result = [4, 5, 6]') nvim('command', 'let g:result = [4, 5, 6]')
return eval('g:result') return eval('g:result')
end end
@@ -61,14 +61,14 @@ describe('server -> client', function()
-- elements following the empty string. -- elements following the empty string.
it('works', function() it('works', function()
local function on_setup() local function on_setup()
eq({1, 2, '', 3, 'asdf'}, eval('rpcrequest('..cid..', "nstring")')) eq({ 1, 2, '', 3, 'asdf' }, eval('rpcrequest(' .. cid .. ', "nstring")'))
stop() stop()
end end
local function on_request() local function on_request()
-- No need to evaluate the args, we are only interested in -- No need to evaluate the args, we are only interested in
-- a response that contains an array with an empty string. -- a response that contains an array with an empty string.
return {1, 2, '', 3, 'asdf'} return { 1, 2, '', 3, 'asdf' }
end end
run(on_request, nil, on_setup) run(on_request, nil, on_setup)
end) end)
@@ -81,7 +81,7 @@ describe('server -> client', function()
nvim('set_var', 'result2', 0) nvim('set_var', 'result2', 0)
nvim('set_var', 'result3', 0) nvim('set_var', 'result3', 0)
nvim('set_var', 'result4', 0) nvim('set_var', 'result4', 0)
nvim('command', 'let g:result1 = rpcrequest('..cid..', "rcall", 2)') nvim('command', 'let g:result1 = rpcrequest(' .. cid .. ', "rcall", 2)')
eq(4, nvim('get_var', 'result1')) eq(4, nvim('get_var', 'result1'))
eq(8, nvim('get_var', 'result2')) eq(8, nvim('get_var', 'result2'))
eq(16, nvim('get_var', 'result3')) eq(16, nvim('get_var', 'result3'))
@@ -95,11 +95,11 @@ describe('server -> client', function()
if n <= 16 then if n <= 16 then
local cmd local cmd
if n == 4 then if n == 4 then
cmd = 'let g:result2 = rpcrequest('..cid..', "rcall", '..n..')' cmd = 'let g:result2 = rpcrequest(' .. cid .. ', "rcall", ' .. n .. ')'
elseif n == 8 then elseif n == 8 then
cmd = 'let g:result3 = rpcrequest('..cid..', "rcall", '..n..')' cmd = 'let g:result3 = rpcrequest(' .. cid .. ', "rcall", ' .. n .. ')'
elseif n == 16 then elseif n == 16 then
cmd = 'let g:result4 = rpcrequest('..cid..', "rcall", '..n..')' cmd = 'let g:result4 = rpcrequest(' .. cid .. ', "rcall", ' .. n .. ')'
end end
nvim('command', cmd) nvim('command', cmd)
end end
@@ -113,18 +113,18 @@ describe('server -> client', function()
it('does not delay notifications during pending request', function() it('does not delay notifications during pending request', function()
local received = false local received = false
local function on_setup() local function on_setup()
eq("retval", funcs.rpcrequest(cid, "doit")) eq('retval', funcs.rpcrequest(cid, 'doit'))
stop() stop()
end end
local function on_request(method) local function on_request(method)
if method == "doit" then if method == 'doit' then
funcs.rpcnotify(cid, "headsup") funcs.rpcnotify(cid, 'headsup')
eq(true,received) eq(true, received)
return "retval" return 'retval'
end end
end end
local function on_notification(method) local function on_notification(method)
if method == "headsup" then if method == 'headsup' then
received = true received = true
end end
end end
@@ -148,28 +148,28 @@ describe('server -> client', function()
-- of nvim's request stack). -- of nvim's request stack).
pending('will close connection if not properly synchronized', function() pending('will close connection if not properly synchronized', function()
local function on_setup() local function on_setup()
eq('notified!', eval('rpcrequest('..cid..', "notify")')) eq('notified!', eval('rpcrequest(' .. cid .. ', "notify")'))
end end
local function on_request(method) local function on_request(method)
if method == "notify" then if method == 'notify' then
eq(1, eval('rpcnotify('..cid..', "notification")')) eq(1, eval('rpcnotify(' .. cid .. ', "notification")'))
return 'notified!' return 'notified!'
elseif method == "nested" then elseif method == 'nested' then
-- do some busywork, so the first request will return -- do some busywork, so the first request will return
-- before this one -- before this one
for _ = 1, 5 do for _ = 1, 5 do
assert_alive() assert_alive()
end end
eq(1, eval('rpcnotify('..cid..', "nested_done")')) eq(1, eval('rpcnotify(' .. cid .. ', "nested_done")'))
return 'done!' return 'done!'
end end
end end
local function on_notification(method) local function on_notification(method)
if method == "notification" then if method == 'notification' then
eq('done!', eval('rpcrequest('..cid..', "nested")')) eq('done!', eval('rpcrequest(' .. cid .. ', "nested")'))
elseif method == "nested_done" then elseif method == 'nested_done' then
ok(false, 'never sent', 'sent') ok(false, 'never sent', 'sent')
end end
end end
@@ -182,11 +182,17 @@ describe('server -> client', function()
describe('recursive (child) nvim client', function() describe('recursive (child) nvim client', function()
before_each(function() before_each(function()
command("let vim = rpcstart('"..nvim_prog.."', ['-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--embed', '--headless'])") command(
"let vim = rpcstart('"
.. nvim_prog
.. "', ['-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--embed', '--headless'])"
)
neq(0, eval('vim')) neq(0, eval('vim'))
end) end)
after_each(function() command('call rpcstop(vim)') end) after_each(function()
command('call rpcstop(vim)')
end)
it('can send/receive notifications and make requests', function() it('can send/receive notifications and make requests', function()
nvim('command', "call rpcnotify(vim, 'vim_set_current_line', 'SOME TEXT')") nvim('command', "call rpcnotify(vim, 'vim_set_current_line', 'SOME TEXT')")
@@ -198,25 +204,27 @@ describe('server -> client', function()
end) end)
it('can communicate buffers, tabpages, and windows', function() it('can communicate buffers, tabpages, and windows', function()
eq({1}, eval("rpcrequest(vim, 'nvim_list_tabpages')")) eq({ 1 }, eval("rpcrequest(vim, 'nvim_list_tabpages')"))
-- Window IDs start at 1000 (LOWEST_WIN_ID in window.h) -- Window IDs start at 1000 (LOWEST_WIN_ID in window.h)
eq({1000}, eval("rpcrequest(vim, 'nvim_list_wins')")) eq({ 1000 }, eval("rpcrequest(vim, 'nvim_list_wins')"))
local buf = eval("rpcrequest(vim, 'nvim_list_bufs')")[1] local buf = eval("rpcrequest(vim, 'nvim_list_bufs')")[1]
eq(1, buf) eq(1, buf)
eval("rpcnotify(vim, 'buffer_set_line', "..buf..", 0, 'SOME TEXT')") eval("rpcnotify(vim, 'buffer_set_line', " .. buf .. ", 0, 'SOME TEXT')")
nvim('command', "call rpcrequest(vim, 'vim_eval', '0')") -- wait nvim('command', "call rpcrequest(vim, 'vim_eval', '0')") -- wait
eq('SOME TEXT', eval("rpcrequest(vim, 'buffer_get_line', "..buf..", 0)")) eq('SOME TEXT', eval("rpcrequest(vim, 'buffer_get_line', " .. buf .. ', 0)'))
-- Call get_lines(buf, range [0,0], strict_indexing) -- Call get_lines(buf, range [0,0], strict_indexing)
eq({'SOME TEXT'}, eval("rpcrequest(vim, 'buffer_get_lines', "..buf..", 0, 1, 1)")) eq({ 'SOME TEXT' }, eval("rpcrequest(vim, 'buffer_get_lines', " .. buf .. ', 0, 1, 1)'))
end) end)
it('returns an error if the request failed', function() it('returns an error if the request failed', function()
eq("Vim:Error invoking 'does-not-exist' on channel 3:\nInvalid method: does-not-exist", eq(
pcall_err(eval, "rpcrequest(vim, 'does-not-exist')")) "Vim:Error invoking 'does-not-exist' on channel 3:\nInvalid method: does-not-exist",
pcall_err(eval, "rpcrequest(vim, 'does-not-exist')")
)
end) end)
end) end)
@@ -236,13 +244,14 @@ describe('server -> client', function()
\ 'rpc': v:true \ 'rpc': v:true
\ } \ }
]]) ]])
meths.set_var("args", { meths.set_var('args', {
nvim_prog, '-ll', nvim_prog,
'-ll',
'test/functional/api/rpc_fixture.lua', 'test/functional/api/rpc_fixture.lua',
package.path, package.path,
package.cpath, package.cpath,
}) })
jobid = eval("jobstart(g:args, g:job_opts)") jobid = eval('jobstart(g:args, g:job_opts)')
neq(0, jobid) neq(0, jobid)
end) end)
@@ -250,7 +259,9 @@ describe('server -> client', function()
pcall(funcs.jobstop, jobid) pcall(funcs.jobstop, jobid)
end) end)
if helpers.skip(helpers.is_os('win')) then return end if helpers.skip(helpers.is_os('win')) then
return
end
it('rpc and text stderr can be combined', function() it('rpc and text stderr can be combined', function()
local status, rv = pcall(funcs.rpcrequest, jobid, 'poll') local status, rv = pcall(funcs.rpcrequest, jobid, 'poll')
@@ -258,18 +269,18 @@ describe('server -> client', function()
error(string.format('missing nvim Lua module? (%s)', rv)) error(string.format('missing nvim Lua module? (%s)', rv))
end end
eq('ok', rv) eq('ok', rv)
funcs.rpcnotify(jobid, "ping") funcs.rpcnotify(jobid, 'ping')
eq({'notification', 'pong', {}}, next_msg()) eq({ 'notification', 'pong', {} }, next_msg())
eq("done!",funcs.rpcrequest(jobid, "write_stderr", "fluff\n")) eq('done!', funcs.rpcrequest(jobid, 'write_stderr', 'fluff\n'))
eq({'notification', 'stderr', {0, {'fluff', ''}}}, next_msg()) eq({ 'notification', 'stderr', { 0, { 'fluff', '' } } }, next_msg())
pcall(funcs.rpcrequest, jobid, "exit") pcall(funcs.rpcrequest, jobid, 'exit')
eq({'notification', 'stderr', {0, {''}}}, next_msg()) eq({ 'notification', 'stderr', { 0, { '' } } }, next_msg())
eq({'notification', 'exit', {0, 0}}, next_msg()) eq({ 'notification', 'exit', { 0, 0 } }, next_msg())
end) end)
end) end)
describe('connecting to another (peer) nvim', function() describe('connecting to another (peer) nvim', function()
local nvim_argv = merge_args(helpers.nvim_argv, {'--headless'}) local nvim_argv = merge_args(helpers.nvim_argv, { '--headless' })
local function connect_test(server, mode, address) local function connect_test(server, mode, address)
local serverpid = funcs.getpid() local serverpid = funcs.getpid()
local client = spawn(nvim_argv, false, nil, true) local client = spawn(nvim_argv, false, nil, true)
@@ -277,7 +288,7 @@ describe('server -> client', function()
local clientpid = funcs.getpid() local clientpid = funcs.getpid()
neq(serverpid, clientpid) neq(serverpid, clientpid)
local id = funcs.sockconnect(mode, address, {rpc=true}) local id = funcs.sockconnect(mode, address, { rpc = true })
ok(id > 0) ok(id > 0)
funcs.rpcrequest(id, 'nvim_set_current_line', 'hello') funcs.rpcrequest(id, 'nvim_set_current_line', 'hello')
@@ -303,7 +314,7 @@ describe('server -> client', function()
local server = spawn(nvim_argv) local server = spawn(nvim_argv)
set_session(server) set_session(server)
local address = funcs.serverlist()[1] local address = funcs.serverlist()[1]
local first = string.sub(address,1,1) local first = string.sub(address, 1, 1)
ok(first == '/' or first == '\\') ok(first == '/' or first == '\\')
connect_test(server, 'pipe', address) connect_test(server, 'pipe', address)
end) end)
@@ -311,11 +322,11 @@ describe('server -> client', function()
it('via ipv4 address', function() it('via ipv4 address', function()
local server = spawn(nvim_argv) local server = spawn(nvim_argv)
set_session(server) set_session(server)
local status, address = pcall(funcs.serverstart, "127.0.0.1:") local status, address = pcall(funcs.serverstart, '127.0.0.1:')
if not status then if not status then
pending('no ipv4 stack') pending('no ipv4 stack')
end end
eq('127.0.0.1:', string.sub(address,1,10)) eq('127.0.0.1:', string.sub(address, 1, 10))
connect_test(server, 'tcp', address) connect_test(server, 'tcp', address)
end) end)
@@ -326,15 +337,15 @@ describe('server -> client', function()
if not status then if not status then
pending('no ipv6 stack') pending('no ipv6 stack')
end end
eq('::1:', string.sub(address,1,4)) eq('::1:', string.sub(address, 1, 4))
connect_test(server, 'tcp', address) connect_test(server, 'tcp', address)
end) end)
it('via hostname', function() it('via hostname', function()
local server = spawn(nvim_argv) local server = spawn(nvim_argv)
set_session(server) set_session(server)
local address = funcs.serverstart("localhost:") local address = funcs.serverstart('localhost:')
eq('localhost:', string.sub(address,1,10)) eq('localhost:', string.sub(address, 1, 10))
connect_test(server, 'tcp', address) connect_test(server, 'tcp', address)
end) end)
@@ -345,7 +356,7 @@ describe('server -> client', function()
local client = spawn(nvim_argv, false, nil, true) local client = spawn(nvim_argv, false, nil, true)
set_session(client) set_session(client)
local id = funcs.sockconnect('pipe', address, {rpc=true}) local id = funcs.sockconnect('pipe', address, { rpc = true })
funcs.rpcrequest(id, 'nvim_ui_attach', 80, 24, {}) funcs.rpcrequest(id, 'nvim_ui_attach', 80, 24, {})
assert_alive() assert_alive()
@@ -357,15 +368,15 @@ describe('server -> client', function()
describe('connecting to its own pipe address', function() describe('connecting to its own pipe address', function()
it('does not deadlock', function() it('does not deadlock', function()
local address = funcs.serverlist()[1] local address = funcs.serverlist()[1]
local first = string.sub(address,1,1) local first = string.sub(address, 1, 1)
ok(first == '/' or first == '\\') ok(first == '/' or first == '\\')
local serverpid = funcs.getpid() local serverpid = funcs.getpid()
local id = funcs.sockconnect('pipe', address, {rpc=true}) local id = funcs.sockconnect('pipe', address, { rpc = true })
funcs.rpcrequest(id, 'nvim_set_current_line', 'hello') funcs.rpcrequest(id, 'nvim_set_current_line', 'hello')
eq('hello', meths.get_current_line()) eq('hello', meths.get_current_line())
eq(serverpid, funcs.rpcrequest(id, "nvim_eval", "getpid()")) eq(serverpid, funcs.rpcrequest(id, 'nvim_eval', 'getpid()'))
eq(id, funcs.rpcrequest(id, 'nvim_get_api_info')[1]) eq(id, funcs.rpcrequest(id, 'nvim_get_api_info')[1])
end) end)

View File

@@ -1,7 +1,6 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local clear, nvim, tabpage, curtab, eq, ok = local clear, nvim, tabpage, curtab, eq, ok =
helpers.clear, helpers.nvim, helpers.tabpage, helpers.curtab, helpers.eq, helpers.clear, helpers.nvim, helpers.tabpage, helpers.curtab, helpers.eq, helpers.ok
helpers.ok
local curtabmeths = helpers.curtabmeths local curtabmeths = helpers.curtabmeths
local funcs = helpers.funcs local funcs = helpers.funcs
local request = helpers.request local request = helpers.request
@@ -18,8 +17,8 @@ describe('api/tabpage', function()
nvim('command', 'vsplit') nvim('command', 'vsplit')
local tab1, tab2 = unpack(nvim('list_tabpages')) local tab1, tab2 = unpack(nvim('list_tabpages'))
local win1, win2, win3 = unpack(nvim('list_wins')) local win1, win2, win3 = unpack(nvim('list_wins'))
eq({win1}, tabpage('list_wins', tab1)) eq({ win1 }, tabpage('list_wins', tab1))
eq({win2, win3}, tabpage('list_wins', tab2)) eq({ win2, win3 }, tabpage('list_wins', tab2))
eq(win2, tabpage('get_win', tab2)) eq(win2, tabpage('get_win', tab2))
nvim('set_current_win', win3) nvim('set_current_win', win3)
eq(win3, tabpage('get_win', tab2)) eq(win3, tabpage('get_win', tab2))
@@ -32,9 +31,9 @@ describe('api/tabpage', function()
describe('{get,set,del}_var', function() describe('{get,set,del}_var', function()
it('works', function() it('works', function()
curtab('set_var', 'lua', {1, 2, {['3'] = 1}}) curtab('set_var', 'lua', { 1, 2, { ['3'] = 1 } })
eq({1, 2, {['3'] = 1}}, curtab('get_var', 'lua')) eq({ 1, 2, { ['3'] = 1 } }, curtab('get_var', 'lua'))
eq({1, 2, {['3'] = 1}}, nvim('eval', 't:lua')) eq({ 1, 2, { ['3'] = 1 } }, nvim('eval', 't:lua'))
eq(1, funcs.exists('t:lua')) eq(1, funcs.exists('t:lua'))
curtabmeths.del_var('lua') curtabmeths.del_var('lua')
eq(0, funcs.exists('t:lua')) eq(0, funcs.exists('t:lua'))
@@ -46,16 +45,16 @@ describe('api/tabpage', function()
end) end)
it('tabpage_set_var returns the old value', function() it('tabpage_set_var returns the old value', function()
local val1 = {1, 2, {['3'] = 1}} local val1 = { 1, 2, { ['3'] = 1 } }
local val2 = {4, 7} local val2 = { 4, 7 }
eq(NIL, request('tabpage_set_var', 0, 'lua', val1)) eq(NIL, request('tabpage_set_var', 0, 'lua', val1))
eq(val1, request('tabpage_set_var', 0, 'lua', val2)) eq(val1, request('tabpage_set_var', 0, 'lua', val2))
end) end)
it('tabpage_del_var returns the old value', function() it('tabpage_del_var returns the old value', function()
local val1 = {1, 2, {['3'] = 1}} local val1 = { 1, 2, { ['3'] = 1 } }
local val2 = {4, 7} local val2 = { 4, 7 }
eq(NIL, request('tabpage_set_var', 0, 'lua', val1)) eq(NIL, request('tabpage_set_var', 0, 'lua', val1))
eq(val1, request('tabpage_set_var', 0, 'lua', val2)) eq(val1, request('tabpage_set_var', 0, 'lua', val2))
eq(val2, request('tabpage_del_var', 0, 'lua')) eq(val2, request('tabpage_del_var', 0, 'lua'))
end) end)

View File

@@ -23,42 +23,56 @@ describe('nvim_ui_attach()', function()
end) end)
it('validation', function() it('validation', function()
eq('No such UI option: foo', eq('No such UI option: foo', pcall_err(meths.ui_attach, 80, 24, { foo = { 'foo' } }))
pcall_err(meths.ui_attach, 80, 24, { foo={'foo'} }))
eq("Invalid 'ext_linegrid': expected Boolean, got Array", eq(
pcall_err(meths.ui_attach, 80, 24, { ext_linegrid={} })) "Invalid 'ext_linegrid': expected Boolean, got Array",
eq("Invalid 'override': expected Boolean, got Array", pcall_err(meths.ui_attach, 80, 24, { ext_linegrid = {} })
pcall_err(meths.ui_attach, 80, 24, { override={} })) )
eq("Invalid 'rgb': expected Boolean, got Array", eq(
pcall_err(meths.ui_attach, 80, 24, { rgb={} })) "Invalid 'override': expected Boolean, got Array",
eq("Invalid 'term_name': expected String, got Boolean", pcall_err(meths.ui_attach, 80, 24, { override = {} })
pcall_err(meths.ui_attach, 80, 24, { term_name=true })) )
eq("Invalid 'term_colors': expected Integer, got Boolean", eq(
pcall_err(meths.ui_attach, 80, 24, { term_colors=true })) "Invalid 'rgb': expected Boolean, got Array",
eq("Invalid 'stdin_fd': expected Integer, got String", pcall_err(meths.ui_attach, 80, 24, { rgb = {} })
pcall_err(meths.ui_attach, 80, 24, { stdin_fd='foo' })) )
eq("Invalid 'stdin_tty': expected Boolean, got String", eq(
pcall_err(meths.ui_attach, 80, 24, { stdin_tty='foo' })) "Invalid 'term_name': expected String, got Boolean",
eq("Invalid 'stdout_tty': expected Boolean, got String", pcall_err(meths.ui_attach, 80, 24, { term_name = true })
pcall_err(meths.ui_attach, 80, 24, { stdout_tty='foo' })) )
eq(
"Invalid 'term_colors': expected Integer, got Boolean",
pcall_err(meths.ui_attach, 80, 24, { term_colors = true })
)
eq(
"Invalid 'stdin_fd': expected Integer, got String",
pcall_err(meths.ui_attach, 80, 24, { stdin_fd = 'foo' })
)
eq(
"Invalid 'stdin_tty': expected Boolean, got String",
pcall_err(meths.ui_attach, 80, 24, { stdin_tty = 'foo' })
)
eq(
"Invalid 'stdout_tty': expected Boolean, got String",
pcall_err(meths.ui_attach, 80, 24, { stdout_tty = 'foo' })
)
eq('UI not attached to channel: 1', eq('UI not attached to channel: 1', pcall_err(request, 'nvim_ui_try_resize', 40, 10))
pcall_err(request, 'nvim_ui_try_resize', 40, 10)) eq('UI not attached to channel: 1', pcall_err(request, 'nvim_ui_set_option', 'rgb', true))
eq('UI not attached to channel: 1', eq('UI not attached to channel: 1', pcall_err(request, 'nvim_ui_detach'))
pcall_err(request, 'nvim_ui_set_option', 'rgb', true))
eq('UI not attached to channel: 1',
pcall_err(request, 'nvim_ui_detach'))
local screen = Screen.new() local screen = Screen.new()
screen:attach({rgb=false}) screen:attach({ rgb = false })
eq('UI already attached to channel: 1', eq(
pcall_err(request, 'nvim_ui_attach', 40, 10, { rgb=false })) 'UI already attached to channel: 1',
pcall_err(request, 'nvim_ui_attach', 40, 10, { rgb = false })
)
end) end)
end) end)
it('autocmds UIEnter/UILeave', function() it('autocmds UIEnter/UILeave', function()
clear{args_rm={'--headless'}} clear { args_rm = { '--headless' } }
exec([[ exec([[
let g:evs = [] let g:evs = []
autocmd UIEnter * call add(g:evs, "UIEnter") | let g:uienter_ev = deepcopy(v:event) autocmd UIEnter * call add(g:evs, "UIEnter") | let g:uienter_ev = deepcopy(v:event)
@@ -67,9 +81,9 @@ it('autocmds UIEnter/UILeave', function()
]]) ]])
local screen = Screen.new() local screen = Screen.new()
screen:attach() screen:attach()
eq({chan=1}, eval('g:uienter_ev')) eq({ chan = 1 }, eval('g:uienter_ev'))
screen:detach() screen:detach()
eq({chan=1}, eval('g:uileave_ev')) eq({ chan = 1 }, eval('g:uileave_ev'))
eq({ eq({
'VimEnter', 'VimEnter',
'UIEnter', 'UIEnter',
@@ -89,21 +103,27 @@ it('autocmds VimSuspend/VimResume #22041', function()
eq(false, screen.suspended) eq(false, screen.suspended)
feed('<C-Z>') feed('<C-Z>')
screen:expect(function() eq(true, screen.suspended) end) screen:expect(function()
eq(true, screen.suspended)
end)
eq({ 's' }, eval('g:ev')) eq({ 's' }, eval('g:ev'))
screen.suspended = false screen.suspended = false
feed('<Ignore>') feed('<Ignore>')
eq({ 's', 'r' }, eval('g:ev')) eq({ 's', 'r' }, eval('g:ev'))
command('suspend') command('suspend')
screen:expect(function() eq(true, screen.suspended) end) screen:expect(function()
eq(true, screen.suspended)
end)
eq({ 's', 'r', 's' }, eval('g:ev')) eq({ 's', 'r', 's' }, eval('g:ev'))
screen.suspended = false screen.suspended = false
meths.input_mouse('move', '', '', 0, 0, 0) meths.input_mouse('move', '', '', 0, 0, 0)
eq({ 's', 'r', 's', 'r' }, eval('g:ev')) eq({ 's', 'r', 's', 'r' }, eval('g:ev'))
feed('<C-Z><C-Z><C-Z>') feed('<C-Z><C-Z><C-Z>')
screen:expect(function() eq(true, screen.suspended) end) screen:expect(function()
eq(true, screen.suspended)
end)
meths.ui_set_focus(false) meths.ui_set_focus(false)
eq({ 's', 'r', 's', 'r', 's' }, eval('g:ev')) eq({ 's', 'r', 's', 'r', 's' }, eval('g:ev'))
screen.suspended = false screen.suspended = false
@@ -111,7 +131,9 @@ it('autocmds VimSuspend/VimResume #22041', function()
eq({ 's', 'r', 's', 'r', 's', 'r' }, eval('g:ev')) eq({ 's', 'r', 's', 'r', 's', 'r' }, eval('g:ev'))
command('suspend | suspend | suspend') command('suspend | suspend | suspend')
screen:expect(function() eq(true, screen.suspended) end) screen:expect(function()
eq(true, screen.suspended)
end)
screen:detach() screen:detach()
eq({ 's', 'r', 's', 'r', 's', 'r', 's' }, eval('g:ev')) eq({ 's', 'r', 's', 'r', 's', 'r', 's' }, eval('g:ev'))
screen.suspended = false screen.suspended = false

View File

@@ -19,41 +19,40 @@ end
describe("api_info()['version']", function() describe("api_info()['version']", function()
before_each(clear) before_each(clear)
it("returns API level", function() it('returns API level', function()
local version = call('api_info')['version'] local version = call('api_info')['version']
local current = version['api_level'] local current = version['api_level']
local compat = version['api_compatible'] local compat = version['api_compatible']
eq("number", type(current)) eq('number', type(current))
eq("number", type(compat)) eq('number', type(compat))
assert(current >= compat) assert(current >= compat)
end) end)
it("returns Nvim version", function() it('returns Nvim version', function()
local version = call('api_info')['version'] local version = call('api_info')['version']
local major = version['major'] local major = version['major']
local minor = version['minor'] local minor = version['minor']
local patch = version['patch'] local patch = version['patch']
local prerelease = version['prerelease'] local prerelease = version['prerelease']
local build = version['build'] local build = version['build']
eq("number", type(major)) eq('number', type(major))
eq("number", type(minor)) eq('number', type(minor))
eq("number", type(patch)) eq('number', type(patch))
eq("boolean", type(prerelease)) eq('boolean', type(prerelease))
eq(1, funcs.has("nvim-"..major.."."..minor.."."..patch)) eq(1, funcs.has('nvim-' .. major .. '.' .. minor .. '.' .. patch))
eq(0, funcs.has("nvim-"..major.."."..minor.."."..(patch + 1))) eq(0, funcs.has('nvim-' .. major .. '.' .. minor .. '.' .. (patch + 1)))
eq(0, funcs.has("nvim-"..major.."."..(minor + 1).."."..patch)) eq(0, funcs.has('nvim-' .. major .. '.' .. (minor + 1) .. '.' .. patch))
eq(0, funcs.has("nvim-"..(major + 1).."."..minor.."."..patch)) eq(0, funcs.has('nvim-' .. (major + 1) .. '.' .. minor .. '.' .. patch))
assert(build == nil or type(build) == 'string') assert(build == nil or type(build) == 'string')
end) end)
end) end)
describe('api metadata', function()
describe("api metadata", function()
before_each(clear) before_each(clear)
local function name_table(entries) local function name_table(entries)
local by_name = {} local by_name = {}
for _,e in ipairs(entries) do for _, e in ipairs(entries) do
by_name[e.name] = e by_name[e.name] = e
end end
return by_name return by_name
@@ -63,10 +62,10 @@ describe("api metadata", function()
local function filter_function_metadata(f) local function filter_function_metadata(f)
f.deprecated_since = nil f.deprecated_since = nil
for idx, _ in ipairs(f.parameters) do for idx, _ in ipairs(f.parameters) do
f.parameters[idx][2] = '' -- Remove parameter name. f.parameters[idx][2] = '' -- Remove parameter name.
end end
if string.sub(f.name, 1, 4) ~= "nvim" then if string.sub(f.name, 1, 4) ~= 'nvim' then
f.method = nil f.method = nil
end end
return f return f
@@ -76,7 +75,7 @@ describe("api metadata", function()
-- check types of existing params are the same -- check types of existing params are the same
-- adding parameters is ok, but removing params is not (gives nil error) -- adding parameters is ok, but removing params is not (gives nil error)
eq(old_e.since, new_e.since, old_e.name) eq(old_e.since, new_e.since, old_e.name)
for i,p in ipairs(old_e.parameters) do for i, p in ipairs(old_e.parameters) do
eq(new_e.parameters[i][1], p[1], old_e.name) eq(new_e.parameters[i][1], p[1], old_e.name)
end end
end end
@@ -95,25 +94,27 @@ describe("api metadata", function()
local api, compat, stable, api_level local api, compat, stable, api_level
local old_api = {} local old_api = {}
setup(function() setup(function()
clear() -- Ensure a session before requesting api_info. clear() -- Ensure a session before requesting api_info.
api = meths.get_api_info()[2] api = meths.get_api_info()[2]
compat = api.version.api_compatible compat = api.version.api_compatible
api_level = api.version.api_level api_level = api.version.api_level
if api.version.api_prerelease then if api.version.api_prerelease then
stable = api_level-1 stable = api_level - 1
else else
stable = api_level stable = api_level
end end
for level = compat, stable do for level = compat, stable do
local path = ('test/functional/fixtures/api_level_'.. local path = ('test/functional/fixtures/api_level_' .. tostring(level) .. '.mpack')
tostring(level)..'.mpack')
old_api[level] = read_mpack_file(path) old_api[level] = read_mpack_file(path)
if old_api[level] == nil then if old_api[level] == nil then
local errstr = "missing metadata fixture for stable level "..level..". " local errstr = 'missing metadata fixture for stable level ' .. level .. '. '
if level == api_level and not api.version.api_prerelease then if level == api_level and not api.version.api_prerelease then
errstr = (errstr.."If NVIM_API_CURRENT was bumped, ".. errstr = (
"don't forget to set NVIM_API_PRERELEASE to true.") errstr
.. 'If NVIM_API_CURRENT was bumped, '
.. "don't forget to set NVIM_API_PRERELEASE to true."
)
end end
error(errstr) error(errstr)
end end
@@ -124,60 +125,76 @@ describe("api metadata", function()
end end
end) end)
it("functions are compatible with old metadata or have new level", function() it('functions are compatible with old metadata or have new level', function()
local funcs_new = name_table(api.functions) local funcs_new = name_table(api.functions)
local funcs_compat = {} local funcs_compat = {}
for level = compat, stable do for level = compat, stable do
for _,f in ipairs(old_api[level].functions) do for _, f in ipairs(old_api[level].functions) do
if funcs_new[f.name] == nil then if funcs_new[f.name] == nil then
if f.since >= compat then if f.since >= compat then
error('function '..f.name..' was removed but exists in level '.. error(
f.since..' which nvim should be compatible with') 'function '
.. f.name
.. ' was removed but exists in level '
.. f.since
.. ' which nvim should be compatible with'
)
end end
else else
eq(filter_function_metadata(f), eq(filter_function_metadata(f), filter_function_metadata(funcs_new[f.name]))
filter_function_metadata(funcs_new[f.name]))
end end
end end
funcs_compat[level] = name_table(old_api[level].functions) funcs_compat[level] = name_table(old_api[level].functions)
end end
for _,f in ipairs(api.functions) do for _, f in ipairs(api.functions) do
if f.since <= stable then if f.since <= stable then
local f_old = funcs_compat[f.since][f.name] local f_old = funcs_compat[f.since][f.name]
if f_old == nil then if f_old == nil then
if string.sub(f.name, 1, 4) == "nvim" then if string.sub(f.name, 1, 4) == 'nvim' then
local errstr = ("function "..f.name.." has too low since value. ".. local errstr = (
"For new functions set it to "..(stable+1)..".") 'function '
.. f.name
.. ' has too low since value. '
.. 'For new functions set it to '
.. (stable + 1)
.. '.'
)
if not api.version.api_prerelease then if not api.version.api_prerelease then
errstr = (errstr.." Also bump NVIM_API_CURRENT and set ".. errstr = (
"NVIM_API_PRERELEASE to true in CMakeLists.txt.") errstr
.. ' Also bump NVIM_API_CURRENT and set '
.. 'NVIM_API_PRERELEASE to true in CMakeLists.txt.'
)
end end
error(errstr) error(errstr)
else else
error("function name '"..f.name.."' doesn't begin with 'nvim_'") error("function name '" .. f.name .. "' doesn't begin with 'nvim_'")
end end
end end
elseif f.since > api_level then elseif f.since > api_level then
if api.version.api_prerelease then if api.version.api_prerelease then
error("New function "..f.name.." should use since value ".. error('New function ' .. f.name .. ' should use since value ' .. api_level)
api_level)
else else
error("function "..f.name.." has since value > api_level. ".. error(
"Bump NVIM_API_CURRENT and set ".. 'function '
"NVIM_API_PRERELEASE to true in CMakeLists.txt.") .. f.name
.. ' has since value > api_level. '
.. 'Bump NVIM_API_CURRENT and set '
.. 'NVIM_API_PRERELEASE to true in CMakeLists.txt.'
)
end end
end end
end end
end) end)
it("UI events are compatible with old metadata or have new level", function() it('UI events are compatible with old metadata or have new level', function()
local ui_events_new = name_table(api.ui_events) local ui_events_new = name_table(api.ui_events)
local ui_events_compat = {} local ui_events_compat = {}
-- UI events were formalized in level 3 -- UI events were formalized in level 3
for level = 3, stable do for level = 3, stable do
for _,e in ipairs(old_api[level].ui_events) do for _, e in ipairs(old_api[level].ui_events) do
local new_e = ui_events_new[e.name] local new_e = ui_events_new[e.name]
if new_e ~= nil then if new_e ~= nil then
check_ui_event_compatible(e, new_e) check_ui_event_compatible(e, new_e)
@@ -186,32 +203,44 @@ describe("api metadata", function()
ui_events_compat[level] = name_table(old_api[level].ui_events) ui_events_compat[level] = name_table(old_api[level].ui_events)
end end
for _,e in ipairs(api.ui_events) do for _, e in ipairs(api.ui_events) do
if e.since <= stable then if e.since <= stable then
local e_old = ui_events_compat[e.since][e.name] local e_old = ui_events_compat[e.since][e.name]
if e_old == nil then if e_old == nil then
local errstr = ("UI event "..e.name.." has too low since value. ".. local errstr = (
"For new events set it to "..(stable+1)..".") 'UI event '
.. e.name
.. ' has too low since value. '
.. 'For new events set it to '
.. (stable + 1)
.. '.'
)
if not api.version.api_prerelease then if not api.version.api_prerelease then
errstr = (errstr.." Also bump NVIM_API_CURRENT and set ".. errstr = (
"NVIM_API_PRERELEASE to true in CMakeLists.txt.") errstr
.. ' Also bump NVIM_API_CURRENT and set '
.. 'NVIM_API_PRERELEASE to true in CMakeLists.txt.'
)
end end
error(errstr) error(errstr)
end end
elseif e.since > api_level then elseif e.since > api_level then
if api.version.api_prerelease then if api.version.api_prerelease then
error("New UI event "..e.name.." should use since value ".. error('New UI event ' .. e.name .. ' should use since value ' .. api_level)
api_level)
else else
error("UI event "..e.name.." has since value > api_level. ".. error(
"Bump NVIM_API_CURRENT and set ".. 'UI event '
"NVIM_API_PRERELEASE to true in CMakeLists.txt.") .. e.name
.. ' has since value > api_level. '
.. 'Bump NVIM_API_CURRENT and set '
.. 'NVIM_API_PRERELEASE to true in CMakeLists.txt.'
)
end end
end end
end end
end) end)
it("ui_options are preserved from older levels", function() it('ui_options are preserved from older levels', function()
local available_options = {} local available_options = {}
for _, option in ipairs(api.ui_options) do for _, option in ipairs(api.ui_options) do
available_options[option] = true available_options[option] = true
@@ -220,7 +249,7 @@ describe("api metadata", function()
for level = 4, stable do for level = 4, stable do
for _, option in ipairs(old_api[level].ui_options) do for _, option in ipairs(old_api[level].ui_options) do
if not available_options[option] then if not available_options[option] then
error("UI option "..option.." from stable metadata is missing") error('UI option ' .. option .. ' from stable metadata is missing')
end end
end end
end end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ describe('oldtests', function()
before_each(clear) before_each(clear)
local exec_lines = function(str) local exec_lines = function(str)
return funcs.split(funcs.execute(str), "\n") return funcs.split(funcs.execute(str), '\n')
end end
local add_an_autocmd = function() local add_an_autocmd = function()
@@ -38,7 +38,6 @@ describe('oldtests', function()
exec [[ augroup vimBarTest| au!| augroup END ]] exec [[ augroup vimBarTest| au!| augroup END ]]
eq(1, #exec_lines('au vimBarTest')) eq(1, #exec_lines('au vimBarTest'))
-- test that a bar is recognized after the {event} -- test that a bar is recognized after the {event}
add_an_autocmd() add_an_autocmd()
exec [[ augroup vimBarTest| au!BufReadCmd| augroup END ]] exec [[ augroup vimBarTest| au!BufReadCmd| augroup END ]]
@@ -50,8 +49,8 @@ describe('oldtests', function()
end) end)
it('should fire on unload buf', function() it('should fire on unload buf', function()
funcs.writefile({'Test file Xxx1'}, 'Xxx1') funcs.writefile({ 'Test file Xxx1' }, 'Xxx1')
funcs.writefile({'Test file Xxx2'}, 'Xxx2') funcs.writefile({ 'Test file Xxx2' }, 'Xxx2')
local fname = 'Xtest_functional_autocmd_unload' local fname = 'Xtest_functional_autocmd_unload'
local content = [[ local content = [[
@@ -72,7 +71,7 @@ describe('oldtests', function()
q q
]] ]]
funcs.writefile(funcs.split(content, "\n"), fname) funcs.writefile(funcs.split(content, '\n'), fname)
funcs.delete('Xout') funcs.delete('Xout')
funcs.system(string.format('%s --clean -N -S %s', meths.get_vvar('progpath'), fname)) funcs.system(string.format('%s --clean -N -S %s', meths.get_vvar('progpath'), fname))
@@ -89,7 +88,7 @@ describe('oldtests', function()
local screen = Screen.new(75, 10) local screen = Screen.new(75, 10)
screen:attach() screen:attach()
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {background = Screen.colors.Cyan}; [1] = { background = Screen.colors.Cyan },
}) })
exec([[ exec([[
set noshowcmd noruler scrolloff=0 set noshowcmd noruler scrolloff=0
@@ -97,7 +96,8 @@ describe('oldtests', function()
edit test/old/testdir/samples/box.txt edit test/old/testdir/samples/box.txt
]]) ]])
feed('249GV<C-End>d') feed('249GV<C-End>d')
screen:expect{grid=[[ screen:expect {
grid = [[
const auto themeEmoji = _forPeer->themeEmoji(); | const auto themeEmoji = _forPeer->themeEmoji(); |
if (themeEmoji.isEmpty()) { | if (themeEmoji.isEmpty()) { |
return nonCustom; | return nonCustom; |
@@ -108,9 +108,11 @@ describe('oldtests', function()
return nonCustom; | return nonCustom; |
{1:^}} | {1:^}} |
353 fewer lines | 353 fewer lines |
]]} ]],
}
feed('<PageUp>') feed('<PageUp>')
screen:expect{grid=[[ screen:expect {
grid = [[
| |
auto BackgroundBox::Inner::resolveResetCustomPaper() const | auto BackgroundBox::Inner::resolveResetCustomPaper() const |
-> std::optional<Data::WallPaper> { | -> std::optional<Data::WallPaper> { |
@@ -121,6 +123,7 @@ describe('oldtests', function()
const auto themeEmoji = _forPeer->themeEmoji(); | const auto themeEmoji = _forPeer->themeEmoji(); |
^if (themeEmoji.isEmpty()) { | ^if (themeEmoji.isEmpty()) { |
353 fewer lines | 353 fewer lines |
]]} ]],
}
end) end)
end) end)

View File

@@ -26,23 +26,23 @@ describe('autocmd', function()
it(':tabnew, :split, :close events order, <afile>', function() it(':tabnew, :split, :close events order, <afile>', function()
local expected = { local expected = {
{'WinLeave', ''}, { 'WinLeave', '' },
{'TabLeave', ''}, { 'TabLeave', '' },
{'WinEnter', ''}, { 'WinEnter', '' },
{'TabNew', 'testfile1'}, -- :tabnew { 'TabNew', 'testfile1' }, -- :tabnew
{'TabEnter', ''}, { 'TabEnter', '' },
{'BufLeave', ''}, { 'BufLeave', '' },
{'BufEnter', 'testfile1'}, -- :split { 'BufEnter', 'testfile1' }, -- :split
{'WinLeave', 'testfile1'}, { 'WinLeave', 'testfile1' },
{'WinEnter', 'testfile1'}, { 'WinEnter', 'testfile1' },
{'WinLeave', 'testfile1'}, { 'WinLeave', 'testfile1' },
{'WinClosed', '1002'}, -- :close, WinClosed <afile> = window-id { 'WinClosed', '1002' }, -- :close, WinClosed <afile> = window-id
{'WinEnter', 'testfile1'}, { 'WinEnter', 'testfile1' },
{'WinLeave', 'testfile1'}, -- :bdelete { 'WinLeave', 'testfile1' }, -- :bdelete
{'WinEnter', 'testfile1'}, { 'WinEnter', 'testfile1' },
{'BufLeave', 'testfile1'}, { 'BufLeave', 'testfile1' },
{'BufEnter', 'testfile2'}, { 'BufEnter', 'testfile2' },
{'WinClosed', '1000'}, { 'WinClosed', '1000' },
} }
command('let g:evs = []') command('let g:evs = []')
command('autocmd BufEnter * :call add(g:evs, ["BufEnter", expand("<afile>")])') command('autocmd BufEnter * :call add(g:evs, ["BufEnter", expand("<afile>")])')
@@ -63,10 +63,10 @@ describe('autocmd', function()
it('first edit causes BufUnload on NoName', function() it('first edit causes BufUnload on NoName', function()
local expected = { local expected = {
{'BufUnload', ''}, { 'BufUnload', '' },
{'BufDelete', ''}, { 'BufDelete', '' },
{'BufWipeout', ''}, { 'BufWipeout', '' },
{'BufEnter', 'testfile1'}, { 'BufEnter', 'testfile1' },
} }
command('let g:evs = []') command('let g:evs = []')
command('autocmd BufEnter * :call add(g:evs, ["BufEnter", expand("<afile>")])') command('autocmd BufEnter * :call add(g:evs, ["BufEnter", expand("<afile>")])')
@@ -106,20 +106,23 @@ describe('autocmd', function()
local buf1 = eval("bufnr('%')") local buf1 = eval("bufnr('%')")
command('new') command('new')
local buf2 = eval("bufnr('%')") local buf2 = eval("bufnr('%')")
command('autocmd WinClosed <buffer> :call add(g:evs, ["WinClosed", expand("<abuf>")])' command(
-- Attempt recursion. 'autocmd WinClosed <buffer> :call add(g:evs, ["WinClosed", expand("<abuf>")])'
..' | bdelete '..buf2) -- Attempt recursion.
.. ' | bdelete '
.. buf2
)
command('tabedit testfile2') command('tabedit testfile2')
command('tabedit testfile3') command('tabedit testfile3')
command('bdelete '..buf2) command('bdelete ' .. buf2)
-- Non-recursive: only triggered once. -- Non-recursive: only triggered once.
eq({ eq({
{'WinClosed', '2'}, { 'WinClosed', '2' },
}, eval('g:evs')) }, eval('g:evs'))
command('bdelete '..buf1) command('bdelete ' .. buf1)
eq({ eq({
{'WinClosed', '2'}, { 'WinClosed', '2' },
{'WinClosed', '1'}, { 'WinClosed', '1' },
}, eval('g:evs')) }, eval('g:evs'))
end) end)
@@ -130,7 +133,7 @@ describe('autocmd', function()
command('new') command('new')
command('close') command('close')
eq({ eq({
{'WinClosed', '1001'}, { 'WinClosed', '1001' },
}, eval('g:evs')) }, eval('g:evs'))
end) end)
@@ -139,16 +142,15 @@ describe('autocmd', function()
end) end)
describe('BufLeave autocommand', function() describe('BufLeave autocommand', function()
it('can wipe out the buffer created by :edit which triggered autocmd', it('can wipe out the buffer created by :edit which triggered autocmd', function()
function()
meths.set_option_value('hidden', true, {}) meths.set_option_value('hidden', true, {})
curbufmeths.set_lines(0, 1, false, { curbufmeths.set_lines(0, 1, false, {
'start of test file xx', 'start of test file xx',
'end of test file xx'}) 'end of test file xx',
})
command('autocmd BufLeave * bwipeout yy') command('autocmd BufLeave * bwipeout yy')
eq('Vim(edit):E143: Autocommands unexpectedly deleted new buffer yy', eq('Vim(edit):E143: Autocommands unexpectedly deleted new buffer yy', exc_exec('edit yy'))
exc_exec('edit yy'))
expect([[ expect([[
start of test file xx start of test file xx
@@ -156,7 +158,7 @@ describe('autocmd', function()
end) end)
end) end)
it('++once', function() -- :help autocmd-once it('++once', function() -- :help autocmd-once
-- --
-- ":autocmd ... ++once" executes its handler once, then removes the handler. -- ":autocmd ... ++once" executes its handler once, then removes the handler.
-- --
@@ -177,7 +179,8 @@ describe('autocmd', function()
command('autocmd TabNew * ++once :call add(g:foo, "Once2")') command('autocmd TabNew * ++once :call add(g:foo, "Once2")')
command('autocmd TabNew * :call add(g:foo, "Many2")') command('autocmd TabNew * :call add(g:foo, "Many2")')
command('autocmd TabNew * ++once :call add(g:foo, "Once3")') command('autocmd TabNew * ++once :call add(g:foo, "Once3")')
eq(dedent([[ eq(
dedent([[
--- Autocommands --- --- Autocommands ---
TabNew TabNew
@@ -186,18 +189,21 @@ describe('autocmd', function()
:call add(g:foo, "Once2") :call add(g:foo, "Once2")
:call add(g:foo, "Many2") :call add(g:foo, "Many2")
:call add(g:foo, "Once3")]]), :call add(g:foo, "Once3")]]),
funcs.execute('autocmd Tabnew')) funcs.execute('autocmd Tabnew')
)
command('tabnew') command('tabnew')
command('tabnew') command('tabnew')
command('tabnew') command('tabnew')
eq(expected, eval('g:foo')) eq(expected, eval('g:foo'))
eq(dedent([[ eq(
dedent([[
--- Autocommands --- --- Autocommands ---
TabNew TabNew
* :call add(g:foo, "Many1") * :call add(g:foo, "Many1")
:call add(g:foo, "Many2")]]), :call add(g:foo, "Many2")]]),
funcs.execute('autocmd Tabnew')) funcs.execute('autocmd Tabnew')
)
-- --
-- ":autocmd ... ++once" handlers can be deleted. -- ":autocmd ... ++once" handlers can be deleted.
@@ -218,7 +224,9 @@ describe('autocmd', function()
} }
command('let g:foo = []') command('let g:foo = []')
command('autocmd OptionSet binary ++nested ++once :call add(g:foo, "OptionSet-Once")') command('autocmd OptionSet binary ++nested ++once :call add(g:foo, "OptionSet-Once")')
command('autocmd CursorMoved <buffer> ++once ++nested setlocal binary|:call add(g:foo, "CursorMoved-Once")') command(
'autocmd CursorMoved <buffer> ++once ++nested setlocal binary|:call add(g:foo, "CursorMoved-Once")'
)
command("put ='foo bar baz'") command("put ='foo bar baz'")
feed('0llhlh') feed('0llhlh')
eq(expected, eval('g:foo')) eq(expected, eval('g:foo'))
@@ -231,15 +239,17 @@ describe('autocmd', function()
'Once2', 'Once2',
} }
command('let g:foo = []') command('let g:foo = []')
command('autocmd! TabNew') -- Clear all TabNew handlers. command('autocmd! TabNew') -- Clear all TabNew handlers.
command('autocmd TabNew * ++once :call add(g:foo, "Once1")') command('autocmd TabNew * ++once :call add(g:foo, "Once1")')
command('autocmd TabNew * ++once :call add(g:foo, "Once2")') command('autocmd TabNew * ++once :call add(g:foo, "Once2")')
command('tabnew') command('tabnew')
eq(expected, eval('g:foo')) eq(expected, eval('g:foo'))
eq(dedent([[ eq(
dedent([[
--- Autocommands ---]]), --- Autocommands ---]]),
funcs.execute('autocmd Tabnew')) funcs.execute('autocmd Tabnew')
)
end) end)
it('internal `aucmd_win` window', function() it('internal `aucmd_win` window', function()
@@ -250,9 +260,13 @@ describe('autocmd', function()
local screen = Screen.new(50, 10) local screen = Screen.new(50, 10)
screen:attach() screen:attach()
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1}, [1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = {background = Screen.colors.LightMagenta}, [2] = { background = Screen.colors.LightMagenta },
[3] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1}, [3] = {
background = Screen.colors.LightMagenta,
bold = true,
foreground = Screen.colors.Blue1,
},
}) })
source([[ source([[
@@ -276,7 +290,7 @@ describe('autocmd', function()
| |
]]) ]])
feed(":enew | doautoall User<cr>") feed(':enew | doautoall User<cr>')
screen:expect([[ screen:expect([[
{2:bb }| {2:bb }|
{3:~ }|*4 {3:~ }|*4
@@ -293,14 +307,16 @@ describe('autocmd', function()
eq(7, eval('g:test')) eq(7, eval('g:test'))
-- API calls are blocked when aucmd_win is not in scope -- API calls are blocked when aucmd_win is not in scope
eq('Vim(call):E5555: API call: Invalid window id: 1001', eq(
pcall_err(command, "call nvim_set_current_win(g:winid)")) 'Vim(call):E5555: API call: Invalid window id: 1001',
pcall_err(command, 'call nvim_set_current_win(g:winid)')
)
-- second time aucmd_win is needed, a different code path is invoked -- second time aucmd_win is needed, a different code path is invoked
-- to reuse the same window, so check again -- to reuse the same window, so check again
command("let g:test = v:null") command('let g:test = v:null')
command("let g:had_value = v:null") command('let g:had_value = v:null')
feed(":doautoall User<cr>") feed(':doautoall User<cr>')
screen:expect([[ screen:expect([[
{2:bb }| {2:bb }|
{3:~ }|*4 {3:~ }|*4
@@ -318,17 +334,19 @@ describe('autocmd', function()
eq(0, eval('g:had_value')) eq(0, eval('g:had_value'))
eq(7, eval('g:test')) eq(7, eval('g:test'))
eq('Vim(call):E5555: API call: Invalid window id: 1001', eq(
pcall_err(command, "call nvim_set_current_win(g:winid)")) 'Vim(call):E5555: API call: Invalid window id: 1001',
pcall_err(command, 'call nvim_set_current_win(g:winid)')
)
end) end)
it("`aucmd_win` cannot be changed into a normal window #13699", function() it('`aucmd_win` cannot be changed into a normal window #13699', function()
local screen = Screen.new(50, 10) local screen = Screen.new(50, 10)
screen:attach() screen:attach()
screen:set_default_attr_ids { screen:set_default_attr_ids {
[1] = {bold = true, foreground = Screen.colors.Blue1}, [1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = {reverse = true}, [2] = { reverse = true },
[3] = {bold = true, reverse = true}, [3] = { bold = true, reverse = true },
} }
-- Create specific layout and ensure it's left unchanged. -- Create specific layout and ensure it's left unchanged.
@@ -371,13 +389,16 @@ describe('autocmd', function()
-- After all of our messing around, aucmd_win should still be floating. -- After all of our messing around, aucmd_win should still be floating.
-- Use :only to ensure _G.buf is hidden again (so the aucmd_win is used). -- Use :only to ensure _G.buf is hidden again (so the aucmd_win is used).
eq("editor", exec_lua [[ eq(
'editor',
exec_lua [[
vim.cmd "only" vim.cmd "only"
vim.api.nvim_buf_call(_G.buf, function() vim.api.nvim_buf_call(_G.buf, function()
_G.config = vim.api.nvim_win_get_config(0) _G.config = vim.api.nvim_win_get_config(0)
end) end)
return _G.config.relative return _G.config.relative
]]) ]]
)
end) end)
describe('closing last non-floating window in tab from `aucmd_win`', function() describe('closing last non-floating window in tab from `aucmd_win`', function()
@@ -388,14 +409,18 @@ describe('autocmd', function()
end) end)
it('gives E814 when there are no other floating windows', function() it('gives E814 when there are no other floating windows', function()
eq('BufAdd Autocommands for "Xa.txt": Vim(close):E814: Cannot close window, only autocmd window would remain', eq(
pcall_err(command, 'doautoall BufAdd')) 'BufAdd Autocommands for "Xa.txt": Vim(close):E814: Cannot close window, only autocmd window would remain',
pcall_err(command, 'doautoall BufAdd')
)
end) end)
it('gives E814 when there are other floating windows', function() it('gives E814 when there are other floating windows', function()
meths.open_win(0, true, {width = 10, height = 10, relative = 'editor', row = 10, col = 10}) meths.open_win(0, true, { width = 10, height = 10, relative = 'editor', row = 10, col = 10 })
eq('BufAdd Autocommands for "Xa.txt": Vim(close):E814: Cannot close window, only autocmd window would remain', eq(
pcall_err(command, 'doautoall BufAdd')) 'BufAdd Autocommands for "Xa.txt": Vim(close):E814: Cannot close window, only autocmd window would remain',
pcall_err(command, 'doautoall BufAdd')
)
end) end)
end) end)
@@ -404,60 +429,88 @@ describe('autocmd', function()
vim.cmd('tabnew') vim.cmd('tabnew')
_G.buf = vim.api.nvim_create_buf(true, true) _G.buf = vim.api.nvim_create_buf(true, true)
]]) ]])
matches('Vim:E813: Cannot close autocmd window$', pcall_err(exec_lua, [[ matches(
'Vim:E813: Cannot close autocmd window$',
pcall_err(
exec_lua,
[[
vim.api.nvim_buf_call(_G.buf, function() vim.api.nvim_buf_call(_G.buf, function()
local win = vim.api.nvim_get_current_win() local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_close(win, true) vim.api.nvim_win_close(win, true)
end) end)
]])) ]]
matches('Vim:E813: Cannot close autocmd window$', pcall_err(exec_lua, [[ )
)
matches(
'Vim:E813: Cannot close autocmd window$',
pcall_err(
exec_lua,
[[
vim.api.nvim_buf_call(_G.buf, function() vim.api.nvim_buf_call(_G.buf, function()
local win = vim.api.nvim_get_current_win() local win = vim.api.nvim_get_current_win()
vim.cmd('tabnext') vim.cmd('tabnext')
vim.api.nvim_win_close(win, true) vim.api.nvim_win_close(win, true)
end) end)
]])) ]]
matches('Vim:E813: Cannot close autocmd window$', pcall_err(exec_lua, [[ )
)
matches(
'Vim:E813: Cannot close autocmd window$',
pcall_err(
exec_lua,
[[
vim.api.nvim_buf_call(_G.buf, function() vim.api.nvim_buf_call(_G.buf, function()
local win = vim.api.nvim_get_current_win() local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_hide(win) vim.api.nvim_win_hide(win)
end) end)
]])) ]]
matches('Vim:E813: Cannot close autocmd window$', pcall_err(exec_lua, [[ )
)
matches(
'Vim:E813: Cannot close autocmd window$',
pcall_err(
exec_lua,
[[
vim.api.nvim_buf_call(_G.buf, function() vim.api.nvim_buf_call(_G.buf, function()
local win = vim.api.nvim_get_current_win() local win = vim.api.nvim_get_current_win()
vim.cmd('tabnext') vim.cmd('tabnext')
vim.api.nvim_win_hide(win) vim.api.nvim_win_hide(win)
end) end)
]])) ]]
)
)
end) end)
it(':doautocmd does not warn "No matching autocommands" #10689', function() it(':doautocmd does not warn "No matching autocommands" #10689', function()
local screen = Screen.new(32, 3) local screen = Screen.new(32, 3)
screen:attach() screen:attach()
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1}, [1] = { bold = true, foreground = Screen.colors.Blue1 },
}) })
feed(':doautocmd User Foo<cr>') feed(':doautocmd User Foo<cr>')
screen:expect{grid=[[ screen:expect {
grid = [[
^ | ^ |
{1:~ }| {1:~ }|
:doautocmd User Foo | :doautocmd User Foo |
]]} ]],
}
feed(':autocmd! SessionLoadPost<cr>') feed(':autocmd! SessionLoadPost<cr>')
feed(':doautocmd SessionLoadPost<cr>') feed(':doautocmd SessionLoadPost<cr>')
screen:expect{grid=[[ screen:expect {
grid = [[
^ | ^ |
{1:~ }| {1:~ }|
:doautocmd SessionLoadPost | :doautocmd SessionLoadPost |
]]} ]],
}
end) end)
describe('v:event is readonly #18063', function() describe('v:event is readonly #18063', function()
it('during ChanOpen event', function() it('during ChanOpen event', function()
command('autocmd ChanOpen * let v:event.info.id = 0') command('autocmd ChanOpen * let v:event.info.id = 0')
funcs.jobstart({'cat'}) funcs.jobstart({ 'cat' })
retry(nil, nil, function() retry(nil, nil, function()
eq('E46: Cannot change read-only variable "v:event.info"', meths.get_vvar('errmsg')) eq('E46: Cannot change read-only variable "v:event.info"', meths.get_vvar('errmsg'))
end) end)
@@ -473,15 +526,19 @@ describe('autocmd', function()
it('during RecordingLeave event', function() it('during RecordingLeave event', function()
command([[autocmd RecordingLeave * let v:event.regname = '']]) command([[autocmd RecordingLeave * let v:event.regname = '']])
eq('RecordingLeave Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.regname"', eq(
pcall_err(command, 'normal! qqq')) 'RecordingLeave Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.regname"',
pcall_err(command, 'normal! qqq')
)
end) end)
it('during TermClose event', function() it('during TermClose event', function()
command('autocmd TermClose * let v:event.status = 0') command('autocmd TermClose * let v:event.status = 0')
command('terminal') command('terminal')
eq('TermClose Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.status"', eq(
pcall_err(command, 'bdelete!')) 'TermClose Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.status"',
pcall_err(command, 'bdelete!')
)
end) end)
end) end)
@@ -549,9 +606,12 @@ describe('autocmd', function()
eq(0, funcs.exists('#WinNew')) eq(0, funcs.exists('#WinNew'))
-- call assert_fails('au WinNew * ++once ++once echo bad', 'E983:') -- call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
local ok, msg = pcall(source, [[ local ok, msg = pcall(
source,
[[
au WinNew * ++once ++once echo bad au WinNew * ++once ++once echo bad
]]) ]]
)
eq(false, ok) eq(false, ok)
eq(true, not not string.find(msg, 'E983:')) eq(true, not not string.find(msg, 'E983:'))
@@ -559,7 +619,7 @@ describe('autocmd', function()
it('should have autocmds in filetypedetect group', function() it('should have autocmds in filetypedetect group', function()
source [[filetype on]] source [[filetype on]]
neq({}, meths.get_autocmds { group = "filetypedetect" }) neq({}, meths.get_autocmds { group = 'filetypedetect' })
end) end)
it('should allow comma-separated patterns', function() it('should allow comma-separated patterns', function()
@@ -571,7 +631,7 @@ describe('autocmd', function()
augroup END augroup END
]] ]]
eq(4, #meths.get_autocmds { event = "BufReadCmd", group = "TestingPatterns" }) eq(4, #meths.get_autocmds { event = 'BufReadCmd', group = 'TestingPatterns' })
end) end)
end) end)
@@ -590,7 +650,7 @@ describe('autocmd', function()
}) })
vim.cmd "tabnew" vim.cmd "tabnew"
]] ]]
eq(1, eval('g:count')) -- Added autocommands should not be executed eq(1, eval('g:count')) -- Added autocommands should not be executed
end) end)
it('no crash when clearing a group inside a callback #23355', function() it('no crash when clearing a group inside a callback #23355', function()

View File

@@ -12,9 +12,9 @@ describe('autocmd BufEnter', function()
it("triggered by nvim_command('edit <dir>')", function() it("triggered by nvim_command('edit <dir>')", function()
command("autocmd BufEnter * if isdirectory(expand('<afile>')) | let g:dir_bufenter = 1 | endif") command("autocmd BufEnter * if isdirectory(expand('<afile>')) | let g:dir_bufenter = 1 | endif")
request("nvim_command", "split .") request('nvim_command', 'split .')
eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory. eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory.
eq(2, eval("bufnr('%')")) -- Switched to the dir buffer. eq(2, eval("bufnr('%')")) -- Switched to the dir buffer.
end) end)
it('triggered by "try|:split <dir>|endtry" in a function', function() it('triggered by "try|:split <dir>|endtry" in a function', function()
@@ -27,21 +27,20 @@ describe('autocmd BufEnter', function()
endtry endtry
endfunction endfunction
]]) ]])
command("call Test()") command('call Test()')
eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory. eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory.
eq(2, eval("bufnr('%')")) -- Switched to the dir buffer. eq(2, eval("bufnr('%')")) -- Switched to the dir buffer.
end) end)
it('triggered by ":split normal|:help|:bw"', function() it('triggered by ":split normal|:help|:bw"', function()
helpers.add_builddir_to_rtp() helpers.add_builddir_to_rtp()
command("split normal") command('split normal')
command("wincmd j") command('wincmd j')
command("help") command('help')
command("wincmd L") command('wincmd L')
command("autocmd BufEnter normal let g:bufentered = 1") command('autocmd BufEnter normal let g:bufentered = 1')
command("bw") command('bw')
eq(1, eval('bufnr("%")')) -- The cursor is back to the bottom window eq(1, eval('bufnr("%")')) -- The cursor is back to the bottom window
eq(0, eval("exists('g:bufentered')")) -- The autocmd hasn't been triggered eq(0, eval("exists('g:bufentered')")) -- The autocmd hasn't been triggered
end) end)
end) end)

View File

@@ -14,9 +14,9 @@ describe('BufModified', function()
let g:modified = 0 let g:modified = 0
autocmd BufModifiedSet * let g:modified += 1 autocmd BufModifiedSet * let g:modified += 1
]]) ]])
request("nvim_command", [[normal! aa\<Esc>]]) request('nvim_command', [[normal! aa\<Esc>]])
eq(1, eval('g:modified')) eq(1, eval('g:modified'))
request("nvim_command", [[normal! u]]) request('nvim_command', [[normal! u]])
eq(2, eval('g:modified')) eq(2, eval('g:modified'))
end) end)
end) end)

View File

@@ -15,7 +15,7 @@ describe('cmdline autocommands', function()
before_each(function() before_each(function()
clear() clear()
channel = meths.get_api_info()[1] channel = meths.get_api_info()[1]
meths.set_var("channel",channel) meths.set_var('channel', channel)
command("autocmd CmdlineEnter * call rpcnotify(g:channel, 'CmdlineEnter', v:event)") command("autocmd CmdlineEnter * call rpcnotify(g:channel, 'CmdlineEnter', v:event)")
command("autocmd CmdlineLeave * call rpcnotify(g:channel, 'CmdlineLeave', v:event)") command("autocmd CmdlineLeave * call rpcnotify(g:channel, 'CmdlineLeave', v:event)")
command("autocmd CmdWinEnter * call rpcnotify(g:channel, 'CmdWinEnter', v:event)") command("autocmd CmdWinEnter * call rpcnotify(g:channel, 'CmdWinEnter', v:event)")
@@ -24,23 +24,27 @@ describe('cmdline autocommands', function()
it('works', function() it('works', function()
feed(':') feed(':')
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
feed('redraw<cr>') feed('redraw<cr>')
eq({'notification', 'CmdlineLeave', eq(
{{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg()) { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } },
next_msg()
)
feed(':') feed(':')
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
-- note: feed('bork<c-c>') might not consume 'bork' -- note: feed('bork<c-c>') might not consume 'bork'
-- due to out-of-band interrupt handling -- due to out-of-band interrupt handling
feed('bork<esc>') feed('bork<esc>')
eq({'notification', 'CmdlineLeave', eq(
{{cmdtype=':', cmdlevel=1, abort=true}}}, next_msg()) { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = true } } },
next_msg()
)
end) end)
it('can abort cmdline', function() it('can abort cmdline', function()
command("autocmd CmdlineLeave * let v:event.abort= len(getcmdline())>15") command('autocmd CmdlineLeave * let v:event.abort= len(getcmdline())>15')
feed(":put! ='ok'<cr>") feed(":put! ='ok'<cr>")
expect([[ expect([[
ok ok
@@ -57,10 +61,10 @@ describe('cmdline autocommands', function()
local screen = Screen.new(72, 8) local screen = Screen.new(72, 8)
screen:attach() screen:attach()
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1}, [1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
[3] = {bold = true, foreground = Screen.colors.SeaGreen4}, [3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
[4] = {bold = true, reverse = true}, [4] = { bold = true, reverse = true },
}) })
command("autocmd CmdlineEnter * echoerr 'FAIL'") command("autocmd CmdlineEnter * echoerr 'FAIL'")
command("autocmd CmdlineLeave * echoerr 'very error'") command("autocmd CmdlineLeave * echoerr 'very error'")
@@ -99,7 +103,7 @@ describe('cmdline autocommands', function()
command("autocmd CmdlineChanged * echoerr 'change erreor'") command("autocmd CmdlineChanged * echoerr 'change erreor'")
-- history recall still works -- history recall still works
feed(":<c-p>") feed(':<c-p>')
screen:expect([[ screen:expect([[
| |
lorem ipsum | lorem ipsum |
@@ -111,7 +115,7 @@ describe('cmdline autocommands', function()
:put ='lorem ipsum'^ | :put ='lorem ipsum'^ |
]]) ]])
feed("<left>") feed('<left>')
screen:expect([[ screen:expect([[
| |
lorem ipsum | lorem ipsum |
@@ -124,7 +128,7 @@ describe('cmdline autocommands', function()
]]) ]])
-- edit still works -- edit still works
feed(".") feed('.')
screen:expect([[ screen:expect([[
{4: }| {4: }|
: | : |
@@ -161,62 +165,97 @@ describe('cmdline autocommands', function()
it('works with nested cmdline', function() it('works with nested cmdline', function()
feed(':') feed(':')
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
feed('<c-r>=') feed('<c-r>=')
eq({'notification', 'CmdlineEnter', {{cmdtype='=', cmdlevel=2}}}, next_msg()) eq({ 'notification', 'CmdlineEnter', { { cmdtype = '=', cmdlevel = 2 } } }, next_msg())
feed('<c-f>') feed('<c-f>')
eq({'notification', 'CmdWinEnter', {{}}}, next_msg()) eq({ 'notification', 'CmdWinEnter', { {} } }, next_msg())
feed(':') feed(':')
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=3}}}, next_msg()) eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 3 } } }, next_msg())
feed('<c-c>') feed('<c-c>')
eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=3, abort=true}}}, next_msg()) eq(
{ 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 3, abort = true } } },
next_msg()
)
feed('<c-c>') feed('<c-c>')
eq({'notification', 'CmdWinLeave', {{}}}, next_msg()) eq({ 'notification', 'CmdWinLeave', { {} } }, next_msg())
feed('1+2<cr>') feed('1+2<cr>')
eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg()) eq(
{ 'notification', 'CmdlineLeave', { { cmdtype = '=', cmdlevel = 2, abort = false } } },
next_msg()
)
end) end)
it('no crash with recursive use of v:event #19484', function() it('no crash with recursive use of v:event #19484', function()
command('autocmd CmdlineEnter * normal :') command('autocmd CmdlineEnter * normal :')
feed(':') feed(':')
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
feed('<CR>') feed('<CR>')
eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg()) eq(
{ 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } },
next_msg()
)
end) end)
it('supports CmdlineChanged' ,function() it('supports CmdlineChanged', function()
command("autocmd CmdlineChanged * call rpcnotify(g:channel, 'CmdlineChanged', v:event, getcmdline())") command(
"autocmd CmdlineChanged * call rpcnotify(g:channel, 'CmdlineChanged', v:event, getcmdline())"
)
feed(':') feed(':')
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
feed('l') feed('l')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "l"}}, next_msg()) eq({ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'l' } }, next_msg())
feed('e') feed('e')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "le"}}, next_msg()) eq({ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'le' } }, next_msg())
feed('t') feed('t')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let"}}, next_msg()) eq({ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let' } }, next_msg())
feed('<space>') feed('<space>')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let "}}, next_msg()) eq(
{ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let ' } },
next_msg()
)
feed('x') feed('x')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x"}}, next_msg()) eq(
{ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x' } },
next_msg()
)
feed('<space>') feed('<space>')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x "}}, next_msg()) eq(
{ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x ' } },
next_msg()
)
feed('=') feed('=')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x ="}}, next_msg()) eq(
{ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x =' } },
next_msg()
)
feed('<space>') feed('<space>')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x = "}}, next_msg()) eq(
{ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x = ' } },
next_msg()
)
feed('<c-r>=') feed('<c-r>=')
eq({'notification', 'CmdlineEnter', {{cmdtype='=', cmdlevel=2}}}, next_msg()) eq({ 'notification', 'CmdlineEnter', { { cmdtype = '=', cmdlevel = 2 } } }, next_msg())
feed('1') feed('1')
eq({'notification', 'CmdlineChanged', {{cmdtype='=', cmdlevel=2}, "1"}}, next_msg()) eq({ 'notification', 'CmdlineChanged', { { cmdtype = '=', cmdlevel = 2 }, '1' } }, next_msg())
feed('+') feed('+')
eq({'notification', 'CmdlineChanged', {{cmdtype='=', cmdlevel=2}, "1+"}}, next_msg()) eq({ 'notification', 'CmdlineChanged', { { cmdtype = '=', cmdlevel = 2 }, '1+' } }, next_msg())
feed('1') feed('1')
eq({'notification', 'CmdlineChanged', {{cmdtype='=', cmdlevel=2}, "1+1"}}, next_msg()) eq({ 'notification', 'CmdlineChanged', { { cmdtype = '=', cmdlevel = 2 }, '1+1' } }, next_msg())
feed('<cr>') feed('<cr>')
eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg()) eq(
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x = 2"}}, next_msg()) { 'notification', 'CmdlineLeave', { { cmdtype = '=', cmdlevel = 2, abort = false } } },
next_msg()
)
eq(
{ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x = 2' } },
next_msg()
)
feed('<cr>') feed('<cr>')
eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg()) eq(
{ 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } },
next_msg()
)
eq(2, eval('x')) eq(2, eval('x'))
end) end)
end) end)

View File

@@ -27,7 +27,7 @@ describe('CursorHold', function()
retry(10, nil, function() retry(10, nil, function()
ut = ut * 2 ut = ut * 2
meths.set_option_value('updatetime', ut, {}) meths.set_option_value('updatetime', ut, {})
feed('0') -- reset did_cursorhold feed('0') -- reset did_cursorhold
meths.set_var('cursorhold', 0) meths.set_var('cursorhold', 0)
sleep(ut / 4) sleep(ut / 4)
fn() fn()
@@ -44,15 +44,23 @@ describe('CursorHold', function()
local ignore_key = meths.replace_termcodes('<Ignore>', true, true, true) local ignore_key = meths.replace_termcodes('<Ignore>', true, true, true)
test_cursorhold(function() end, 1) test_cursorhold(function() end, 1)
test_cursorhold(function() feed('') end, 1) test_cursorhold(function()
test_cursorhold(function() meths.feedkeys('', 'n', true) end, 1) feed('')
test_cursorhold(function() feed('<Ignore>') end, 0) end, 1)
test_cursorhold(function() meths.feedkeys(ignore_key, 'n', true) end, 0) test_cursorhold(function()
meths.feedkeys('', 'n', true)
end, 1)
test_cursorhold(function()
feed('<Ignore>')
end, 0)
test_cursorhold(function()
meths.feedkeys(ignore_key, 'n', true)
end, 0)
end) end)
it("reducing 'updatetime' while waiting for CursorHold #20241", function() it("reducing 'updatetime' while waiting for CursorHold #20241", function()
meths.set_option_value('updatetime', 10000, {}) meths.set_option_value('updatetime', 10000, {})
feed('0') -- reset did_cursorhold feed('0') -- reset did_cursorhold
meths.set_var('cursorhold', 0) meths.set_var('cursorhold', 0)
sleep(50) sleep(50)
eq(0, meths.get_var('cursorhold')) eq(0, meths.get_var('cursorhold'))

View File

@@ -19,9 +19,9 @@ describe('CursorMoved', function()
]]) ]])
eq({}, eval('g:log')) eq({}, eval('g:log'))
command('new') command('new')
eq({'BufEnter2', 'CursorMoved2'}, eval('g:log')) eq({ 'BufEnter2', 'CursorMoved2' }, eval('g:log'))
command('wincmd w') command('wincmd w')
eq({'BufEnter2', 'CursorMoved2', 'BufEnter1', 'CursorMoved1'}, eval('g:log')) eq({ 'BufEnter2', 'CursorMoved2', 'BufEnter1', 'CursorMoved1' }, eval('g:log'))
end) end)
it('is not triggered by temporarily switching window', function() it('is not triggered by temporarily switching window', function()
@@ -41,13 +41,13 @@ describe('CursorMoved', function()
vsplit foo vsplit foo
autocmd CursorMoved * let g:cursormoved += 1 autocmd CursorMoved * let g:cursormoved += 1
]]) ]])
meths.buf_set_lines(eval('g:buf'), 0, -1, true, {'aaa'}) meths.buf_set_lines(eval('g:buf'), 0, -1, true, { 'aaa' })
eq(0, eval('g:cursormoved')) eq(0, eval('g:cursormoved'))
eq({'aaa'}, meths.buf_get_lines(eval('g:buf'), 0, -1, true)) eq({ 'aaa' }, meths.buf_get_lines(eval('g:buf'), 0, -1, true))
eq(0, eval('g:cursormoved')) eq(0, eval('g:cursormoved'))
end) end)
it("is not triggered by cursor movement prior to first CursorMoved instantiation", function() it('is not triggered by cursor movement prior to first CursorMoved instantiation', function()
source([[ source([[
let g:cursormoved = 0 let g:cursormoved = 0
autocmd! CursorMoved autocmd! CursorMoved

View File

@@ -21,41 +21,55 @@ describe('autocmd DirChanged and DirChangedPre', function()
curdir .. '\\XTEST-FUNCTIONAL-AUTOCMD-DIRCHANGED.DIR3', curdir .. '\\XTEST-FUNCTIONAL-AUTOCMD-DIRCHANGED.DIR3',
} }
setup(function() for _, dir in pairs(dirs) do helpers.mkdir(dir) end end) setup(function()
teardown(function() for _, dir in pairs(dirs) do helpers.rmdir(dir) end end) for _, dir in pairs(dirs) do
helpers.mkdir(dir)
end
end)
teardown(function()
for _, dir in pairs(dirs) do
helpers.rmdir(dir)
end
end)
before_each(function() before_each(function()
clear() clear()
command('autocmd DirChangedPre * let [g:evpre, g:amatchpre, g:cdprecount] ' command(
..'= [copy(v:event), expand("<amatch>"), 1 + get(g:, "cdprecount", 0)]') 'autocmd DirChangedPre * let [g:evpre, g:amatchpre, g:cdprecount] '
command('autocmd DirChanged * let [g:getcwd, g:ev, g:amatch, g:cdcount] ' .. '= [copy(v:event), expand("<amatch>"), 1 + get(g:, "cdprecount", 0)]'
..'= [getcwd(), copy(v:event), expand("<amatch>"), 1 + get(g:, "cdcount", 0)]') )
command(
'autocmd DirChanged * let [g:getcwd, g:ev, g:amatch, g:cdcount] '
.. '= [getcwd(), copy(v:event), expand("<amatch>"), 1 + get(g:, "cdcount", 0)]'
)
-- Normalize path separators. -- Normalize path separators.
command([[autocmd DirChangedPre * let g:evpre['directory'] = substitute(g:evpre['directory'], '\\', '/', 'g')]]) command(
[[autocmd DirChangedPre * let g:evpre['directory'] = substitute(g:evpre['directory'], '\\', '/', 'g')]]
)
command([[autocmd DirChanged * let g:ev['cwd'] = substitute(g:ev['cwd'], '\\', '/', 'g')]]) command([[autocmd DirChanged * let g:ev['cwd'] = substitute(g:ev['cwd'], '\\', '/', 'g')]])
command([[autocmd DirChanged * let g:getcwd = substitute(g:getcwd, '\\', '/', 'g')]]) command([[autocmd DirChanged * let g:getcwd = substitute(g:getcwd, '\\', '/', 'g')]])
end) end)
it('set v:event and <amatch>', function() it('set v:event and <amatch>', function()
command('lcd '..dirs[1]) command('lcd ' .. dirs[1])
eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[1], scope = 'window', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev'))
eq('window', eval('g:amatchpre')) eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch')) eq('window', eval('g:amatch'))
eq(1, eval('g:cdprecount')) eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount')) eq(1, eval('g:cdcount'))
command('tcd '..dirs[2]) command('tcd ' .. dirs[2])
eq({directory=dirs[2], scope='tabpage', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[2], scope = 'tabpage', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[2], scope='tabpage', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[2], scope = 'tabpage', changed_window = false }, eval('g:ev'))
eq('tabpage', eval('g:amatchpre')) eq('tabpage', eval('g:amatchpre'))
eq('tabpage', eval('g:amatch')) eq('tabpage', eval('g:amatch'))
eq(2, eval('g:cdprecount')) eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount')) eq(2, eval('g:cdcount'))
command('cd '..dirs[3]) command('cd ' .. dirs[3])
eq({directory=dirs[3], scope='global', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[3], scope = 'global', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[3], scope='global', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[3], scope = 'global', changed_window = false }, eval('g:ev'))
eq('global', eval('g:amatchpre')) eq('global', eval('g:amatchpre'))
eq('global', eval('g:amatch')) eq('global', eval('g:amatch'))
eq(3, eval('g:cdprecount')) eq(3, eval('g:cdprecount'))
@@ -63,22 +77,22 @@ describe('autocmd DirChanged and DirChangedPre', function()
end) end)
it('DirChanged set getcwd() during event #6260', function() it('DirChanged set getcwd() during event #6260', function()
command('lcd '..dirs[1]) command('lcd ' .. dirs[1])
eq(dirs[1], eval('g:getcwd')) eq(dirs[1], eval('g:getcwd'))
command('tcd '..dirs[2]) command('tcd ' .. dirs[2])
eq(dirs[2], eval('g:getcwd')) eq(dirs[2], eval('g:getcwd'))
command('cd '..dirs[3]) command('cd ' .. dirs[3])
eq(dirs[3], eval('g:getcwd')) eq(dirs[3], eval('g:getcwd'))
end) end)
it('disallow recursion', function() it('disallow recursion', function()
command('set shellslash') command('set shellslash')
-- Set up a _nested_ handler. -- Set up a _nested_ handler.
command('autocmd DirChanged * nested lcd '..dirs[3]) command('autocmd DirChanged * nested lcd ' .. dirs[3])
command('lcd '..dirs[1]) command('lcd ' .. dirs[1])
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev'))
eq(1, eval('g:cdcount')) eq(1, eval('g:cdcount'))
-- autocmd changed to dirs[3], but did NOT trigger another DirChanged. -- autocmd changed to dirs[3], but did NOT trigger another DirChanged.
eq(dirs[3], eval('getcwd()')) eq(dirs[3], eval('getcwd()'))
@@ -89,27 +103,36 @@ describe('autocmd DirChanged and DirChangedPre', function()
command('let g:cdcount = 0') command('let g:cdcount = 0')
local status1, err1 = pcall(function() local status1, err1 = pcall(function()
command('lcd '..dirs[1]..'/doesnotexist') command('lcd ' .. dirs[1] .. '/doesnotexist')
end) end)
eq({directory=dirs[1]..'/doesnotexist', scope='window', changed_window=false}, eval('g:evpre')) eq(
{ directory = dirs[1] .. '/doesnotexist', scope = 'window', changed_window = false },
eval('g:evpre')
)
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq('window', eval('g:amatchpre')) eq('window', eval('g:amatchpre'))
eq(1, eval('g:cdprecount')) eq(1, eval('g:cdprecount'))
eq(0, eval('g:cdcount')) eq(0, eval('g:cdcount'))
local status2, err2 = pcall(function() local status2, err2 = pcall(function()
command('lcd '..dirs[2]..'/doesnotexist') command('lcd ' .. dirs[2] .. '/doesnotexist')
end) end)
eq({directory=dirs[2]..'/doesnotexist', scope='window', changed_window=false}, eval('g:evpre')) eq(
{ directory = dirs[2] .. '/doesnotexist', scope = 'window', changed_window = false },
eval('g:evpre')
)
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq('window', eval('g:amatchpre')) eq('window', eval('g:amatchpre'))
eq(2, eval('g:cdprecount')) eq(2, eval('g:cdprecount'))
eq(0, eval('g:cdcount')) eq(0, eval('g:cdcount'))
local status3, err3 = pcall(function() local status3, err3 = pcall(function()
command('lcd '..dirs[3]..'/doesnotexist') command('lcd ' .. dirs[3] .. '/doesnotexist')
end) end)
eq({directory=dirs[3]..'/doesnotexist', scope='window', changed_window=false}, eval('g:evpre')) eq(
{ directory = dirs[3] .. '/doesnotexist', scope = 'window', changed_window = false },
eval('g:evpre')
)
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq('window', eval('g:amatchpre')) eq('window', eval('g:amatchpre'))
eq(3, eval('g:cdprecount')) eq(3, eval('g:cdprecount'))
@@ -119,93 +142,93 @@ describe('autocmd DirChanged and DirChangedPre', function()
eq(false, status2) eq(false, status2)
eq(false, status3) eq(false, status3)
eq('E344:', string.match(err1, "E%d*:")) eq('E344:', string.match(err1, 'E%d*:'))
eq('E344:', string.match(err2, "E%d*:")) eq('E344:', string.match(err2, 'E%d*:'))
eq('E344:', string.match(err3, "E%d*:")) eq('E344:', string.match(err3, 'E%d*:'))
end) end)
it("are triggered by 'autochdir'", function() it("are triggered by 'autochdir'", function()
command('set autochdir') command('set autochdir')
command('split '..dirs[1]..'/foo') command('split ' .. dirs[1] .. '/foo')
eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[1], scope = 'window', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev'))
eq('auto', eval('g:amatchpre')) eq('auto', eval('g:amatchpre'))
eq('auto', eval('g:amatch')) eq('auto', eval('g:amatch'))
eq(1, eval('g:cdprecount')) eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount')) eq(1, eval('g:cdcount'))
command('split '..dirs[2]..'/bar') command('split ' .. dirs[2] .. '/bar')
eq({directory=dirs[2], scope='window', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[2], scope = 'window', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[2], scope='window', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[2], scope = 'window', changed_window = false }, eval('g:ev'))
eq('auto', eval('g:amatch')) eq('auto', eval('g:amatch'))
eq(2, eval('g:cdprecount')) eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount')) eq(2, eval('g:cdcount'))
end) end)
it('do not trigger if directory has not changed', function() it('do not trigger if directory has not changed', function()
command('lcd '..dirs[1]) command('lcd ' .. dirs[1])
eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[1], scope = 'window', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev'))
eq('window', eval('g:amatchpre')) eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch')) eq('window', eval('g:amatch'))
eq(1, eval('g:cdprecount')) eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount')) eq(1, eval('g:cdcount'))
command('let g:evpre = {}') command('let g:evpre = {}')
command('let g:ev = {}') command('let g:ev = {}')
command('lcd '..dirs[1]) command('lcd ' .. dirs[1])
eq({}, eval('g:evpre')) eq({}, eval('g:evpre'))
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq(1, eval('g:cdprecount')) eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount')) eq(1, eval('g:cdcount'))
if is_os('win') then if is_os('win') then
command('lcd '..win_dirs[1]) command('lcd ' .. win_dirs[1])
eq({}, eval('g:evpre')) eq({}, eval('g:evpre'))
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq(1, eval('g:cdprecount')) eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount')) eq(1, eval('g:cdcount'))
end end
command('tcd '..dirs[2]) command('tcd ' .. dirs[2])
eq({directory=dirs[2], scope='tabpage', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[2], scope = 'tabpage', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[2], scope='tabpage', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[2], scope = 'tabpage', changed_window = false }, eval('g:ev'))
eq('tabpage', eval('g:amatchpre')) eq('tabpage', eval('g:amatchpre'))
eq('tabpage', eval('g:amatch')) eq('tabpage', eval('g:amatch'))
eq(2, eval('g:cdprecount')) eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount')) eq(2, eval('g:cdcount'))
command('let g:evpre = {}') command('let g:evpre = {}')
command('let g:ev = {}') command('let g:ev = {}')
command('tcd '..dirs[2]) command('tcd ' .. dirs[2])
eq({}, eval('g:evpre')) eq({}, eval('g:evpre'))
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq(2, eval('g:cdprecount')) eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount')) eq(2, eval('g:cdcount'))
if is_os('win') then if is_os('win') then
command('tcd '..win_dirs[2]) command('tcd ' .. win_dirs[2])
eq({}, eval('g:evpre')) eq({}, eval('g:evpre'))
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq(2, eval('g:cdprecount')) eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount')) eq(2, eval('g:cdcount'))
end end
command('cd '..dirs[3]) command('cd ' .. dirs[3])
eq({directory=dirs[3], scope='global', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[3], scope = 'global', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[3], scope='global', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[3], scope = 'global', changed_window = false }, eval('g:ev'))
eq('global', eval('g:amatch')) eq('global', eval('g:amatch'))
eq(3, eval('g:cdprecount')) eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount')) eq(3, eval('g:cdcount'))
command('let g:evpre = {}') command('let g:evpre = {}')
command('let g:ev = {}') command('let g:ev = {}')
command('cd '..dirs[3]) command('cd ' .. dirs[3])
eq({}, eval('g:evpre')) eq({}, eval('g:evpre'))
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq(3, eval('g:cdprecount')) eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount')) eq(3, eval('g:cdcount'))
if is_os('win') then if is_os('win') then
command('cd '..win_dirs[3]) command('cd ' .. win_dirs[3])
eq({}, eval('g:evpre')) eq({}, eval('g:evpre'))
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq(3, eval('g:cdprecount')) eq(3, eval('g:cdprecount'))
@@ -214,23 +237,23 @@ describe('autocmd DirChanged and DirChangedPre', function()
command('set autochdir') command('set autochdir')
command('split '..dirs[1]..'/foo') command('split ' .. dirs[1] .. '/foo')
eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[1], scope = 'window', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev'))
eq('auto', eval('g:amatchpre')) eq('auto', eval('g:amatchpre'))
eq('auto', eval('g:amatch')) eq('auto', eval('g:amatch'))
eq(4, eval('g:cdprecount')) eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount')) eq(4, eval('g:cdcount'))
command('let g:evpre = {}') command('let g:evpre = {}')
command('let g:ev = {}') command('let g:ev = {}')
command('split '..dirs[1]..'/bar') command('split ' .. dirs[1] .. '/bar')
eq({}, eval('g:evpre')) eq({}, eval('g:evpre'))
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq(4, eval('g:cdprecount')) eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount')) eq(4, eval('g:cdcount'))
if is_os('win') then if is_os('win') then
command('split '..win_dirs[1]..'/baz') command('split ' .. win_dirs[1] .. '/baz')
eq({}, eval('g:evpre')) eq({}, eval('g:evpre'))
eq({}, eval('g:ev')) eq({}, eval('g:ev'))
eq(4, eval('g:cdprecount')) eq(4, eval('g:cdprecount'))
@@ -238,93 +261,93 @@ describe('autocmd DirChanged and DirChangedPre', function()
end end
end) end)
it("are triggered by switching to win/tab with different CWD #6054", function() it('are triggered by switching to win/tab with different CWD #6054', function()
command('lcd '..dirs[3]) -- window 3 command('lcd ' .. dirs[3]) -- window 3
command('split '..dirs[2]..'/foo') -- window 2 command('split ' .. dirs[2] .. '/foo') -- window 2
command('lcd '..dirs[2]) command('lcd ' .. dirs[2])
command('split '..dirs[1]..'/bar') -- window 1 command('split ' .. dirs[1] .. '/bar') -- window 1
command('lcd '..dirs[1]) command('lcd ' .. dirs[1])
command('2wincmd w') -- window 2 command('2wincmd w') -- window 2
eq({directory=dirs[2], scope='window', changed_window=true}, eval('g:evpre')) eq({ directory = dirs[2], scope = 'window', changed_window = true }, eval('g:evpre'))
eq({cwd=dirs[2], scope='window', changed_window=true}, eval('g:ev')) eq({ cwd = dirs[2], scope = 'window', changed_window = true }, eval('g:ev'))
eq('window', eval('g:amatchpre')) eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch')) eq('window', eval('g:amatch'))
eq(4, eval('g:cdprecount')) eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount')) eq(4, eval('g:cdcount'))
command('tabnew') -- tab 2 (tab-local CWD) command('tabnew') -- tab 2 (tab-local CWD)
eq(4, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(4, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(4, eval('g:cdcount')) -- same CWD, no DirChanged event eq(4, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tcd '..dirs[3]) command('tcd ' .. dirs[3])
command('tabnext') -- tab 1 (no tab-local CWD) command('tabnext') -- tab 1 (no tab-local CWD)
eq({directory=dirs[2], scope='window', changed_window=true}, eval('g:evpre')) eq({ directory = dirs[2], scope = 'window', changed_window = true }, eval('g:evpre'))
eq({cwd=dirs[2], scope='window', changed_window=true}, eval('g:ev')) eq({ cwd = dirs[2], scope = 'window', changed_window = true }, eval('g:ev'))
eq('window', eval('g:amatchpre')) eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch')) eq('window', eval('g:amatch'))
command('tabnext') -- tab 2 command('tabnext') -- tab 2
eq({directory=dirs[3], scope='tabpage', changed_window=true}, eval('g:evpre')) eq({ directory = dirs[3], scope = 'tabpage', changed_window = true }, eval('g:evpre'))
eq({cwd=dirs[3], scope='tabpage', changed_window=true}, eval('g:ev')) eq({ cwd = dirs[3], scope = 'tabpage', changed_window = true }, eval('g:ev'))
eq('tabpage', eval('g:amatchpre')) eq('tabpage', eval('g:amatchpre'))
eq('tabpage', eval('g:amatch')) eq('tabpage', eval('g:amatch'))
eq(7, eval('g:cdprecount')) eq(7, eval('g:cdprecount'))
eq(7, eval('g:cdcount')) eq(7, eval('g:cdcount'))
command('tabnext') -- tab 1 command('tabnext') -- tab 1
command('3wincmd w') -- window 3 command('3wincmd w') -- window 3
eq(9, eval('g:cdprecount')) eq(9, eval('g:cdprecount'))
eq(9, eval('g:cdcount')) eq(9, eval('g:cdcount'))
command('tabnext') -- tab 2 (has the *same* CWD) command('tabnext') -- tab 2 (has the *same* CWD)
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
if is_os('win') then if is_os('win') then
command('tabnew') -- tab 3 command('tabnew') -- tab 3
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tcd '..win_dirs[3]) command('tcd ' .. win_dirs[3])
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 1 command('tabnext') -- tab 1
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 3 command('tabprevious') -- tab 3
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 2 command('tabprevious') -- tab 2
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 1 command('tabprevious') -- tab 1
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('lcd '..win_dirs[3]) -- window 3 command('lcd ' .. win_dirs[3]) -- window 3
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 2 command('tabnext') -- tab 2
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 3 command('tabnext') -- tab 3
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 1 command('tabnext') -- tab 1
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 3 command('tabprevious') -- tab 3
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
end end
end) end)
it('are triggered by nvim_set_current_dir()', function() it('are triggered by nvim_set_current_dir()', function()
request('nvim_set_current_dir', dirs[1]) request('nvim_set_current_dir', dirs[1])
eq({directory=dirs[1], scope='global', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[1], scope = 'global', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[1], scope='global', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[1], scope = 'global', changed_window = false }, eval('g:ev'))
eq(1, eval('g:cdprecount')) eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount')) eq(1, eval('g:cdcount'))
request('nvim_set_current_dir', dirs[2]) request('nvim_set_current_dir', dirs[2])
eq({directory=dirs[2], scope='global', changed_window=false}, eval('g:evpre')) eq({ directory = dirs[2], scope = 'global', changed_window = false }, eval('g:evpre'))
eq({cwd=dirs[2], scope='global', changed_window=false}, eval('g:ev')) eq({ cwd = dirs[2], scope = 'global', changed_window = false }, eval('g:ev'))
eq(2, eval('g:cdprecount')) eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount')) eq(2, eval('g:cdcount'))
@@ -333,7 +356,7 @@ describe('autocmd DirChanged and DirChangedPre', function()
end) end)
eq(false, status) eq(false, status)
eq('Failed to change directory', string.match(err, ': (.*)')) eq('Failed to change directory', string.match(err, ': (.*)'))
eq({directory='/doesnotexist', scope='global', changed_window=false}, eval('g:evpre')) eq({ directory = '/doesnotexist', scope = 'global', changed_window = false }, eval('g:evpre'))
eq(3, eval('g:cdprecount')) eq(3, eval('g:cdprecount'))
eq(2, eval('g:cdcount')) eq(2, eval('g:cdcount'))
end) end)
@@ -343,7 +366,7 @@ describe('autocmd DirChanged and DirChangedPre', function()
command('let g:triggered = 0') command('let g:triggered = 0')
command('autocmd DirChangedPre <buffer> let g:triggeredpre = 1') command('autocmd DirChangedPre <buffer> let g:triggeredpre = 1')
command('autocmd DirChanged <buffer> let g:triggered = 1') command('autocmd DirChanged <buffer> let g:triggered = 1')
command('cd '..dirs[1]) command('cd ' .. dirs[1])
eq(1, eval('g:triggeredpre')) eq(1, eval('g:triggeredpre'))
eq(1, eval('g:triggered')) eq(1, eval('g:triggered'))
end) end)

View File

@@ -5,13 +5,13 @@ local clear = helpers.clear
local command = helpers.command local command = helpers.command
describe('autocmd FileType', function() describe('autocmd FileType', function()
before_each(clear) before_each(clear)
it("is triggered by :help only once", function() it('is triggered by :help only once', function()
helpers.add_builddir_to_rtp() helpers.add_builddir_to_rtp()
command("let g:foo = 0") command('let g:foo = 0')
command("autocmd FileType help let g:foo = g:foo + 1") command('autocmd FileType help let g:foo = g:foo + 1')
command("help help") command('help help')
assert.same(1, eval('g:foo')) assert.same(1, eval('g:foo'))
end) end)
end) end)

View File

@@ -5,7 +5,9 @@ local clear = helpers.clear
local feed_command = helpers.feed_command local feed_command = helpers.feed_command
local feed_data = thelpers.feed_data local feed_data = thelpers.feed_data
if helpers.skip(helpers.is_os('win')) then return end if helpers.skip(helpers.is_os('win')) then
return
end
describe('autoread TUI FocusGained/FocusLost', function() describe('autoread TUI FocusGained/FocusLost', function()
local f1 = 'xtest-foo' local f1 = 'xtest-foo'
@@ -14,10 +16,14 @@ describe('autoread TUI FocusGained/FocusLost', function()
before_each(function() before_each(function()
clear() clear()
screen = thelpers.setup_child_nvim({ screen = thelpers.setup_child_nvim({
'-u', 'NONE', '-u',
'-i', 'NONE', 'NONE',
'--cmd', 'colorscheme vim', '-i',
'--cmd', 'set noswapfile noshowcmd noruler notermguicolors', 'NONE',
'--cmd',
'colorscheme vim',
'--cmd',
'set noswapfile noshowcmd noruler notermguicolors',
}) })
end) end)
@@ -38,36 +44,44 @@ describe('autoread TUI FocusGained/FocusLost', function()
local atime = os.time() - 10 local atime = os.time() - 10
luv.fs_utime(path, atime, atime) luv.fs_utime(path, atime, atime)
screen:expect{grid=[[ screen:expect {
grid = [[
{1: } | {1: } |
{4:~ }|*3 {4:~ }|*3
{5:[No Name] }| {5:[No Name] }|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]} ]],
feed_command('edit '..path) }
screen:expect{grid=[[ feed_command('edit ' .. path)
screen:expect {
grid = [[
{1: } | {1: } |
{4:~ }|*3 {4:~ }|*3
{5:xtest-foo }| {5:xtest-foo }|
:edit xtest-foo | :edit xtest-foo |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]} ]],
}
feed_data('\027[O') feed_data('\027[O')
feed_data('\027[O') feed_data('\027[O')
screen:expect{grid=[[ screen:expect {
grid = [[
{1: } | {1: } |
{4:~ }|*3 {4:~ }|*3
{5:xtest-foo }| {5:xtest-foo }|
:edit xtest-foo | :edit xtest-foo |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], unchanged=true} ]],
unchanged = true,
}
helpers.write_file(path, expected_addition) helpers.write_file(path, expected_addition)
feed_data('\027[I') feed_data('\027[I')
screen:expect{grid=[[ screen:expect {
grid = [[
{1:l}ine 1 | {1:l}ine 1 |
line 2 | line 2 |
line 3 | line 3 |
@@ -75,6 +89,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
{5:xtest-foo }| {5:xtest-foo }|
"xtest-foo" 4L, 28B | "xtest-foo" 4L, 28B |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]} ]],
}
end) end)
end) end)

View File

@@ -17,15 +17,15 @@ describe('ModeChanged', function()
feed('i') feed('i')
eq({ eq({
old_mode = 'nt', old_mode = 'nt',
new_mode = 't' new_mode = 't',
}, eval('g:event')) }, eval('g:event'))
feed('<c-\\><c-n>') feed('<c-\\><c-n>')
eq({ eq({
old_mode = 't', old_mode = 't',
new_mode = 'nt' new_mode = 'nt',
}, eval('g:event')) }, eval('g:event'))
eq(3, eval('g:count')) eq(3, eval('g:count'))
command("bd!") command('bd!')
-- v:event is cleared after the autocommand is done -- v:event is cleared after the autocommand is done
eq({}, eval('v:event')) eq({}, eval('v:event'))

View File

@@ -15,7 +15,8 @@ describe('autocmd SearchWrapped', function()
command('autocmd! SearchWrapped * let g:test += 1') command('autocmd! SearchWrapped * let g:test += 1')
curbufmeths.set_lines(0, 1, false, { curbufmeths.set_lines(0, 1, false, {
'The quick brown fox', 'The quick brown fox',
'jumps over the lazy dog'}) 'jumps over the lazy dog',
})
end) end)
it('gets triggered when search wraps the end', function() it('gets triggered when search wraps the end', function()

View File

@@ -10,24 +10,25 @@ local eval = helpers.eval
local exec = helpers.exec local exec = helpers.exec
local feed = helpers.feed local feed = helpers.feed
describe(":autocmd", function() describe(':autocmd', function()
before_each(function() before_each(function()
clear({'-u', 'NONE'}) clear({ '-u', 'NONE' })
end) end)
it("should not segfault when you just do autocmd", function() it('should not segfault when you just do autocmd', function()
command ":autocmd" command ':autocmd'
end) end)
it("should filter based on ++once", function() it('should filter based on ++once', function()
command "autocmd! BufEnter" command 'autocmd! BufEnter'
command "autocmd BufEnter * :echo 'Hello'" command "autocmd BufEnter * :echo 'Hello'"
command [[augroup TestingOne]] command [[augroup TestingOne]]
command [[ autocmd BufEnter * :echo "Line 1"]] command [[ autocmd BufEnter * :echo "Line 1"]]
command [[ autocmd BufEnter * :echo "Line 2"]] command [[ autocmd BufEnter * :echo "Line 2"]]
command [[augroup END]] command [[augroup END]]
eq(dedent([[ eq(
dedent([[
--- Autocommands --- --- Autocommands ---
BufEnter BufEnter
@@ -35,15 +36,16 @@ describe(":autocmd", function()
TestingOne BufEnter TestingOne BufEnter
* :echo "Line 1" * :echo "Line 1"
:echo "Line 2"]]), :echo "Line 2"]]),
funcs.execute('autocmd BufEnter')) funcs.execute('autocmd BufEnter')
)
end) end)
it('should not show group information if interrupted', function() it('should not show group information if interrupted', function()
local screen = Screen.new(50, 6) local screen = Screen.new(50, 6)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText [1] = { bold = true, foreground = Screen.colors.Blue1 }, -- NonText
[2] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg [2] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
[3] = {bold = true, foreground = Screen.colors.Magenta}, -- Title [3] = { bold = true, foreground = Screen.colors.Magenta }, -- Title
}) })
screen:attach() screen:attach()
exec([[ exec([[
@@ -109,7 +111,8 @@ describe(":autocmd", function()
autocmd User foo call Func() autocmd User foo call Func()
doautocmd User foo doautocmd User foo
]]) ]])
eq(dedent([[ eq(
dedent([[
--- Autocommands --- --- Autocommands ---
test_1 BufEnter test_1 BufEnter
@@ -119,7 +122,9 @@ describe(":autocmd", function()
test_3 BufEnter test_3 BufEnter
D echo 'D' D echo 'D'
E echo 'E' E echo 'E'
F echo 'F']]), eval('g:output')) F echo 'F']]),
eval('g:output')
)
end) end)
it('can filter by pattern #17973', function() it('can filter by pattern #17973', function()
@@ -145,7 +150,8 @@ describe(":autocmd", function()
autocmd User B echo "B3" autocmd User B echo "B3"
augroup END augroup END
]]) ]])
eq(dedent([[ eq(
dedent([[
--- Autocommands --- --- Autocommands ---
test_1 User test_1 User
@@ -153,8 +159,11 @@ describe(":autocmd", function()
test_2 User test_2 User
A echo "A2" A echo "A2"
test_3 User test_3 User
A echo "A3"]]), funcs.execute('autocmd User A')) A echo "A3"]]),
eq(dedent([[ funcs.execute('autocmd User A')
)
eq(
dedent([[
--- Autocommands --- --- Autocommands ---
test_1 BufEnter test_1 BufEnter
@@ -168,14 +177,19 @@ describe(":autocmd", function()
test_2 User test_2 User
B echo "B2" B echo "B2"
test_3 User test_3 User
B echo "B3"]]), funcs.execute('autocmd * B')) B echo "B3"]]),
eq(dedent([[ funcs.execute('autocmd * B')
)
eq(
dedent([[
--- Autocommands --- --- Autocommands ---
test_3 BufEnter test_3 BufEnter
B echo "B3" B echo "B3"
test_3 User test_3 User
B echo "B3"]]), funcs.execute('autocmd test_3 * B')) B echo "B3"]]),
funcs.execute('autocmd test_3 * B')
)
end) end)
it('should skip consecutive patterns', function() it('should skip consecutive patterns', function()
@@ -200,7 +214,8 @@ describe(":autocmd", function()
let g:output = execute('autocmd BufEnter') let g:output = execute('autocmd BufEnter')
]]) ]])
eq(dedent([[ eq(
dedent([[
--- Autocommands --- --- Autocommands ---
test_1 BufEnter test_1 BufEnter
@@ -216,6 +231,8 @@ describe(":autocmd", function()
echo 'C' echo 'C'
D echo 'D' D echo 'D'
echo 'E' echo 'E'
echo 'F']]), eval('g:output')) echo 'F']]),
eval('g:output')
)
end) end)
end) end)

View File

@@ -8,10 +8,12 @@ local next_msg = helpers.next_msg
local is_os = helpers.is_os local is_os = helpers.is_os
local skip = helpers.skip local skip = helpers.skip
if skip(is_os('win'), 'Only applies to POSIX systems') then return end if skip(is_os('win'), 'Only applies to POSIX systems') then
return
end
local function posix_kill(signame, pid) local function posix_kill(signame, pid)
os.execute('kill -s '..signame..' -- '..pid..' >/dev/null') os.execute('kill -s ' .. signame .. ' -- ' .. pid .. ' >/dev/null')
end end
describe('autocmd Signal', function() describe('autocmd Signal', function()
@@ -20,19 +22,19 @@ describe('autocmd Signal', function()
it('matches *', function() it('matches *', function()
command('autocmd Signal * call rpcnotify(1, "foo")') command('autocmd Signal * call rpcnotify(1, "foo")')
posix_kill('USR1', funcs.getpid()) posix_kill('USR1', funcs.getpid())
eq({'notification', 'foo', {}}, next_msg()) eq({ 'notification', 'foo', {} }, next_msg())
end) end)
it('matches SIGUSR1', function() it('matches SIGUSR1', function()
command('autocmd Signal SIGUSR1 call rpcnotify(1, "foo")') command('autocmd Signal SIGUSR1 call rpcnotify(1, "foo")')
posix_kill('USR1', funcs.getpid()) posix_kill('USR1', funcs.getpid())
eq({'notification', 'foo', {}}, next_msg()) eq({ 'notification', 'foo', {} }, next_msg())
end) end)
it('matches SIGWINCH', function() it('matches SIGWINCH', function()
command('autocmd Signal SIGWINCH call rpcnotify(1, "foo")') command('autocmd Signal SIGWINCH call rpcnotify(1, "foo")')
posix_kill('WINCH', funcs.getpid()) posix_kill('WINCH', funcs.getpid())
eq({'notification', 'foo', {}}, next_msg()) eq({ 'notification', 'foo', {} }, next_msg())
end) end)
it('does not match unknown patterns', function() it('does not match unknown patterns', function()

View File

@@ -7,62 +7,76 @@ describe('TabClosed', function()
describe('au TabClosed', function() describe('au TabClosed', function()
describe('with * as <afile>', function() describe('with * as <afile>', function()
it('matches when closing any tab', function() it('matches when closing any tab', function()
nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') nvim(
'command',
'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()'
)
repeat repeat
nvim('command', 'tabnew') nvim('command', 'tabnew')
until nvim('eval', 'tabpagenr()') == 6 -- current tab is now 6 until nvim('eval', 'tabpagenr()') == 6 -- current tab is now 6
eq("tabclosed:6:6:5", nvim('exec', 'tabclose', true)) -- close last 6, current tab is now 5 eq('tabclosed:6:6:5', nvim('exec', 'tabclose', true)) -- close last 6, current tab is now 5
eq("tabclosed:5:5:4", nvim('exec', 'close', true)) -- close last window on tab, closes tab eq('tabclosed:5:5:4', nvim('exec', 'close', true)) -- close last window on tab, closes tab
eq("tabclosed:2:2:3", nvim('exec', '2tabclose', true)) -- close tab 2, current tab is now 3 eq('tabclosed:2:2:3', nvim('exec', '2tabclose', true)) -- close tab 2, current tab is now 3
eq("tabclosed:1:1:2\ntabclosed:1:1:1", nvim('exec', 'tabonly', true)) -- close tabs 1 and 2 eq('tabclosed:1:1:2\ntabclosed:1:1:1', nvim('exec', 'tabonly', true)) -- close tabs 1 and 2
end) end)
it('is triggered when closing a window via bdelete from another tab', function() it('is triggered when closing a window via bdelete from another tab', function()
nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') nvim(
'command',
'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()'
)
nvim('command', '1tabedit Xtestfile') nvim('command', '1tabedit Xtestfile')
nvim('command', '1tabedit Xtestfile') nvim('command', '1tabedit Xtestfile')
nvim('command', 'normal! 1gt') nvim('command', 'normal! 1gt')
eq({1, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) eq({ 1, 3 }, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
eq("tabclosed:2:2:1\ntabclosed:2:2:1", nvim('exec', 'bdelete Xtestfile', true)) eq('tabclosed:2:2:1\ntabclosed:2:2:1', nvim('exec', 'bdelete Xtestfile', true))
eq({1, 1}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) eq({ 1, 1 }, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
end) end)
it('is triggered when closing a window via bdelete from current tab', function() it('is triggered when closing a window via bdelete from current tab', function()
nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') nvim(
'command',
'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()'
)
nvim('command', 'file Xtestfile1') nvim('command', 'file Xtestfile1')
nvim('command', '1tabedit Xtestfile2') nvim('command', '1tabedit Xtestfile2')
nvim('command', '1tabedit Xtestfile2') nvim('command', '1tabedit Xtestfile2')
-- Only one tab is closed, and the alternate file is used for the other. -- Only one tab is closed, and the alternate file is used for the other.
eq({2, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) eq({ 2, 3 }, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
eq("tabclosed:2:2:2", nvim('exec', 'bdelete Xtestfile2', true)) eq('tabclosed:2:2:2', nvim('exec', 'bdelete Xtestfile2', true))
eq('Xtestfile1', nvim('eval', 'bufname("")')) eq('Xtestfile1', nvim('eval', 'bufname("")'))
end) end)
end) end)
describe('with NR as <afile>', function() describe('with NR as <afile>', function()
it('matches when closing a tab whose index is NR', function() it('matches when closing a tab whose index is NR', function()
nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') nvim(
'command',
'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()'
)
nvim('command', 'au! TabClosed 2 echom "tabclosed:match"') nvim('command', 'au! TabClosed 2 echom "tabclosed:match"')
repeat repeat
nvim('command', 'tabnew') nvim('command', 'tabnew')
until nvim('eval', 'tabpagenr()') == 7 -- current tab is now 7 until nvim('eval', 'tabpagenr()') == 7 -- current tab is now 7
-- sanity check, we shouldn't match on tabs with numbers other than 2 -- sanity check, we shouldn't match on tabs with numbers other than 2
eq("tabclosed:7:7:6", nvim('exec', 'tabclose', true)) eq('tabclosed:7:7:6', nvim('exec', 'tabclose', true))
-- close tab page 2, current tab is now 5 -- close tab page 2, current tab is now 5
eq("tabclosed:2:2:5\ntabclosed:match", nvim('exec', '2tabclose', true)) eq('tabclosed:2:2:5\ntabclosed:match', nvim('exec', '2tabclose', true))
end) end)
end) end)
describe('with close', function() describe('with close', function()
it('is triggered', function() it('is triggered', function()
nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') nvim(
nvim('command', 'tabedit Xtestfile') 'command',
eq({2, 2}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()'
eq("tabclosed:2:2:1", nvim('exec', 'close', true)) )
eq({1, 1}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) nvim('command', 'tabedit Xtestfile')
eq({ 2, 2 }, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
eq('tabclosed:2:2:1', nvim('exec', 'close', true))
eq({ 1, 1 }, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
end) end)
end) end)
end) end)
end) end)

View File

@@ -15,16 +15,16 @@ describe('TabNewEntered', function()
it('matches when entering any new tab', function() it('matches when entering any new tab', function()
clear() clear()
nvim('command', 'au! TabNewEntered * echom "tabnewentered:".tabpagenr().":".bufnr("")') nvim('command', 'au! TabNewEntered * echom "tabnewentered:".tabpagenr().":".bufnr("")')
eq("tabnewentered:2:2", nvim('exec', 'tabnew', true)) eq('tabnewentered:2:2', nvim('exec', 'tabnew', true))
eq("tabnewentered:3:3", nvim('exec', 'tabnew test.x2', true)) eq('tabnewentered:3:3', nvim('exec', 'tabnew test.x2', true))
end) end)
end) end)
describe('with FILE as <afile>', function() describe('with FILE as <afile>', function()
it('matches when opening a new tab for FILE', function() it('matches when opening a new tab for FILE', function()
clear() clear()
nvim('command', 'au! TabNewEntered Xtest-tabnewentered echom "tabnewentered:match"') nvim('command', 'au! TabNewEntered Xtest-tabnewentered echom "tabnewentered:match"')
eq('tabnewentered:match', nvim('exec', 'tabnew Xtest-tabnewentered', true)) eq('tabnewentered:match', nvim('exec', 'tabnew Xtest-tabnewentered', true))
end) end)
end) end)
describe('with CTRL-W T', function() describe('with CTRL-W T', function()
it('works when opening a new tab with CTRL-W T', function() it('works when opening a new tab with CTRL-W T', function()
@@ -49,22 +49,22 @@ end)
describe('TabEnter', function() describe('TabEnter', function()
before_each(clear) before_each(clear)
it('has correct previous tab when entering any new tab', function() it('has correct previous tab when entering any new tab', function()
command('augroup TEMP') command('augroup TEMP')
nvim('command', 'au! TabEnter * echom "tabenter:".tabpagenr().":".tabpagenr(\'#\')') nvim('command', 'au! TabEnter * echom "tabenter:".tabpagenr().":".tabpagenr(\'#\')')
command('augroup END') command('augroup END')
eq("tabenter:2:1", nvim('exec', 'tabnew', true)) eq('tabenter:2:1', nvim('exec', 'tabnew', true))
eq("tabenter:3:2", nvim('exec', 'tabnew test.x2', true)) eq('tabenter:3:2', nvim('exec', 'tabnew test.x2', true))
command('augroup! TEMP') command('augroup! TEMP')
end) end)
it('has correct previous tab when entering any preexisting tab', function() it('has correct previous tab when entering any preexisting tab', function()
command('tabnew') command('tabnew')
command('tabnew') command('tabnew')
command('augroup TEMP') command('augroup TEMP')
nvim('command', 'au! TabEnter * echom "tabenter:".tabpagenr().":".tabpagenr(\'#\')') nvim('command', 'au! TabEnter * echom "tabenter:".tabpagenr().":".tabpagenr(\'#\')')
command('augroup END') command('augroup END')
eq("tabenter:1:3", nvim('exec', 'tabnext', true)) eq('tabenter:1:3', nvim('exec', 'tabnext', true))
eq("tabenter:2:1", nvim('exec', 'tabnext', true)) eq('tabenter:2:1', nvim('exec', 'tabnext', true))
command('augroup! TEMP') command('augroup! TEMP')
end) end)
end) end)
@@ -72,18 +72,19 @@ describe('tabpage/previous', function()
before_each(clear) before_each(clear)
local function switches_to_previous_after_new_tab_creation_at_end(characters) local function switches_to_previous_after_new_tab_creation_at_end(characters)
return function() return function()
-- Add three tabs for a total of four -- Add three tabs for a total of four
command('tabnew') command('tabnew')
command('tabnew') command('tabnew')
command('tabnew') command('tabnew')
-- The previous tab is now the third. -- The previous tab is now the third.
eq(3, eval('tabpagenr(\'#\')')) eq(3, eval("tabpagenr('#')"))
-- Switch to the previous (third) tab -- Switch to the previous (third) tab
feed(characters) feed(characters)
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
[No Name] [No Name]
@@ -93,18 +94,29 @@ describe('tabpage/previous', function()
> [No Name] > [No Name]
Tab page 4 Tab page 4
# [No Name]]=]), # [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
-- The previous tab is now the fourth. -- The previous tab is now the fourth.
eq(4, eval('tabpagenr(\'#\')')) eq(4, eval("tabpagenr('#')"))
end end
end end
it('switches to previous via g<Tab> after new tab creation at end', it(
switches_to_previous_after_new_tab_creation_at_end('g<Tab>')) 'switches to previous via g<Tab> after new tab creation at end',
it('switches to previous via <C-W>g<Tab>. after new tab creation at end', switches_to_previous_after_new_tab_creation_at_end('<C-W>g<Tab>')) switches_to_previous_after_new_tab_creation_at_end('g<Tab>')
it('switches to previous via <C-Tab>. after new tab creation at end', switches_to_previous_after_new_tab_creation_at_end('<C-Tab>')) )
it('switches to previous via :tabn #<CR>. after new tab creation at end', switches_to_previous_after_new_tab_creation_at_end(':tabn #<CR>')) it(
'switches to previous via <C-W>g<Tab>. after new tab creation at end',
switches_to_previous_after_new_tab_creation_at_end('<C-W>g<Tab>')
)
it(
'switches to previous via <C-Tab>. after new tab creation at end',
switches_to_previous_after_new_tab_creation_at_end('<C-Tab>')
)
it(
'switches to previous via :tabn #<CR>. after new tab creation at end',
switches_to_previous_after_new_tab_creation_at_end(':tabn #<CR>')
)
local function switches_to_previous_after_new_tab_creation_in_middle(characters) local function switches_to_previous_after_new_tab_creation_in_middle(characters)
return function() return function()
@@ -118,11 +130,12 @@ describe('tabpage/previous', function()
command('tabnew') command('tabnew')
-- The previous tab is now the second. -- The previous tab is now the second.
eq(2, eval('tabpagenr(\'#\')')) eq(2, eval("tabpagenr('#')"))
-- Switch to the previous (second) tab -- Switch to the previous (second) tab
feed(characters) feed(characters)
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
[No Name] [No Name]
@@ -134,21 +147,29 @@ describe('tabpage/previous', function()
[No Name] [No Name]
Tab page 5 Tab page 5
[No Name]]=]), [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
-- The previous tab is now the third. -- The previous tab is now the third.
eq(3, eval('tabpagenr(\'#\')')) eq(3, eval("tabpagenr('#')"))
end end
end end
it('switches to previous via g<Tab> after new tab creation in middle', it(
switches_to_previous_after_new_tab_creation_in_middle('g<Tab>')) 'switches to previous via g<Tab> after new tab creation in middle',
it('switches to previous via <C-W>g<Tab> after new tab creation in middle', switches_to_previous_after_new_tab_creation_in_middle('g<Tab>')
switches_to_previous_after_new_tab_creation_in_middle('<C-W>g<Tab>')) )
it('switches to previous via <C-Tab> after new tab creation in middle', it(
switches_to_previous_after_new_tab_creation_in_middle('<C-Tab>')) 'switches to previous via <C-W>g<Tab> after new tab creation in middle',
it('switches to previous via :tabn #<CR> after new tab creation in middle', switches_to_previous_after_new_tab_creation_in_middle('<C-W>g<Tab>')
switches_to_previous_after_new_tab_creation_in_middle(':tabn #<CR>')) )
it(
'switches to previous via <C-Tab> after new tab creation in middle',
switches_to_previous_after_new_tab_creation_in_middle('<C-Tab>')
)
it(
'switches to previous via :tabn #<CR> after new tab creation in middle',
switches_to_previous_after_new_tab_creation_in_middle(':tabn #<CR>')
)
local function switches_to_previous_after_switching_to_next_tab(characters) local function switches_to_previous_after_switching_to_next_tab(characters)
return function() return function()
@@ -160,12 +181,13 @@ describe('tabpage/previous', function()
command('tabnext') command('tabnext')
-- The previous tab is now the fourth. -- The previous tab is now the fourth.
eq(4, eval('tabpagenr(\'#\')')) eq(4, eval("tabpagenr('#')"))
-- Switch to the previous (fourth) tab -- Switch to the previous (fourth) tab
feed(characters) feed(characters)
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
# [No Name] # [No Name]
@@ -175,21 +197,29 @@ describe('tabpage/previous', function()
[No Name] [No Name]
Tab page 4 Tab page 4
> [No Name]]=]), > [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
-- The previous tab is now the first. -- The previous tab is now the first.
eq(1, eval('tabpagenr(\'#\')')) eq(1, eval("tabpagenr('#')"))
end end
end end
it('switches to previous via g<Tab> after switching to next tab', it(
switches_to_previous_after_switching_to_next_tab('g<Tab>')) 'switches to previous via g<Tab> after switching to next tab',
it('switches to previous via <C-W>g<Tab> after switching to next tab', switches_to_previous_after_switching_to_next_tab('g<Tab>')
switches_to_previous_after_switching_to_next_tab('<C-W>g<Tab>')) )
it('switches to previous via <C-Tab> after switching to next tab', it(
switches_to_previous_after_switching_to_next_tab('<C-Tab>')) 'switches to previous via <C-W>g<Tab> after switching to next tab',
it('switches to previous via :tabn #<CR> after switching to next tab', switches_to_previous_after_switching_to_next_tab('<C-W>g<Tab>')
switches_to_previous_after_switching_to_next_tab(':tabn #<CR>')) )
it(
'switches to previous via <C-Tab> after switching to next tab',
switches_to_previous_after_switching_to_next_tab('<C-Tab>')
)
it(
'switches to previous via :tabn #<CR> after switching to next tab',
switches_to_previous_after_switching_to_next_tab(':tabn #<CR>')
)
local function switches_to_previous_after_switching_to_last_tab(characters) local function switches_to_previous_after_switching_to_last_tab(characters)
return function() return function()
@@ -203,12 +233,13 @@ describe('tabpage/previous', function()
command('tablast') command('tablast')
-- The previous tab is now the second. -- The previous tab is now the second.
eq(1, eval('tabpagenr(\'#\')')) eq(1, eval("tabpagenr('#')"))
-- Switch to the previous (second) tab -- Switch to the previous (second) tab
feed(characters) feed(characters)
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
> [No Name] > [No Name]
@@ -218,21 +249,29 @@ describe('tabpage/previous', function()
[No Name] [No Name]
Tab page 4 Tab page 4
# [No Name]]=]), # [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
-- The previous tab is now the fourth. -- The previous tab is now the fourth.
eq(4, eval('tabpagenr(\'#\')')) eq(4, eval("tabpagenr('#')"))
end end
end end
it('switches to previous after switching to last tab', it(
switches_to_previous_after_switching_to_last_tab('g<Tab>')) 'switches to previous after switching to last tab',
it('switches to previous after switching to last tab', switches_to_previous_after_switching_to_last_tab('g<Tab>')
switches_to_previous_after_switching_to_last_tab('<C-W>g<Tab>')) )
it('switches to previous after switching to last tab', it(
switches_to_previous_after_switching_to_last_tab('<C-Tab>')) 'switches to previous after switching to last tab',
it('switches to previous after switching to last tab', switches_to_previous_after_switching_to_last_tab('<C-W>g<Tab>')
switches_to_previous_after_switching_to_last_tab(':tabn #<CR>')) )
it(
'switches to previous after switching to last tab',
switches_to_previous_after_switching_to_last_tab('<C-Tab>')
)
it(
'switches to previous after switching to last tab',
switches_to_previous_after_switching_to_last_tab(':tabn #<CR>')
)
local function switches_to_previous_after_switching_to_previous_tab(characters) local function switches_to_previous_after_switching_to_previous_tab(characters)
return function() return function()
@@ -244,12 +283,13 @@ describe('tabpage/previous', function()
command('tabprevious') command('tabprevious')
-- The previous tab is now the fourth. -- The previous tab is now the fourth.
eq(4, eval('tabpagenr(\'#\')')) eq(4, eval("tabpagenr('#')"))
-- Switch to the previous (fourth) tab -- Switch to the previous (fourth) tab
feed(characters) feed(characters)
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
[No Name] [No Name]
@@ -259,21 +299,29 @@ describe('tabpage/previous', function()
# [No Name] # [No Name]
Tab page 4 Tab page 4
> [No Name]]=]), > [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
-- The previous tab is now the third. -- The previous tab is now the third.
eq(3, eval('tabpagenr(\'#\')')) eq(3, eval("tabpagenr('#')"))
end end
end end
it('switches to previous via g<Tab> after switching to previous tab', it(
switches_to_previous_after_switching_to_previous_tab('g<Tab>')) 'switches to previous via g<Tab> after switching to previous tab',
it('switches to previous via <C-W>g<Tab> after switching to previous tab', switches_to_previous_after_switching_to_previous_tab('g<Tab>')
switches_to_previous_after_switching_to_previous_tab('<C-W>g<Tab>')) )
it('switches to previous via <C-Tab> after switching to previous tab', it(
switches_to_previous_after_switching_to_previous_tab('<C-Tab>')) 'switches to previous via <C-W>g<Tab> after switching to previous tab',
it('switches to previous via :tabn #<CR> after switching to previous tab', switches_to_previous_after_switching_to_previous_tab('<C-W>g<Tab>')
switches_to_previous_after_switching_to_previous_tab(':tabn #<CR>')) )
it(
'switches to previous via <C-Tab> after switching to previous tab',
switches_to_previous_after_switching_to_previous_tab('<C-Tab>')
)
it(
'switches to previous via :tabn #<CR> after switching to previous tab',
switches_to_previous_after_switching_to_previous_tab(':tabn #<CR>')
)
local function switches_to_previous_after_switching_to_first_tab(characters) local function switches_to_previous_after_switching_to_first_tab(characters)
return function() return function()
@@ -287,12 +335,13 @@ describe('tabpage/previous', function()
command('tabfirst') command('tabfirst')
-- The previous tab is now the third. -- The previous tab is now the third.
eq(3, eval('tabpagenr(\'#\')')) eq(3, eval("tabpagenr('#')"))
-- Switch to the previous (third) tab -- Switch to the previous (third) tab
feed(characters) feed(characters)
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
# [No Name] # [No Name]
@@ -302,21 +351,29 @@ describe('tabpage/previous', function()
> [No Name] > [No Name]
Tab page 4 Tab page 4
[No Name]]=]), [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
-- The previous tab is now the first. -- The previous tab is now the first.
eq(1, eval('tabpagenr(\'#\')')) eq(1, eval("tabpagenr('#')"))
end end
end end
it('switches to previous via g<Tab> after switching to first tab', it(
switches_to_previous_after_switching_to_first_tab('g<Tab>')) 'switches to previous via g<Tab> after switching to first tab',
it('switches to previous via <C-W>g<Tab> after switching to first tab', switches_to_previous_after_switching_to_first_tab('g<Tab>')
switches_to_previous_after_switching_to_first_tab('<C-W>g<Tab>')) )
it('switches to previous via <C-Tab> after switching to first tab', it(
switches_to_previous_after_switching_to_first_tab('<C-Tab>')) 'switches to previous via <C-W>g<Tab> after switching to first tab',
it('switches to previous via :tabn #<CR> after switching to first tab', switches_to_previous_after_switching_to_first_tab('<C-W>g<Tab>')
switches_to_previous_after_switching_to_first_tab(':tabn #<CR>')) )
it(
'switches to previous via <C-Tab> after switching to first tab',
switches_to_previous_after_switching_to_first_tab('<C-Tab>')
)
it(
'switches to previous via :tabn #<CR> after switching to first tab',
switches_to_previous_after_switching_to_first_tab(':tabn #<CR>')
)
local function switches_to_previous_after_numbered_tab_switch(characters) local function switches_to_previous_after_numbered_tab_switch(characters)
return function() return function()
@@ -328,12 +385,13 @@ describe('tabpage/previous', function()
command('tabnext 2') command('tabnext 2')
-- The previous tab is now the fourth. -- The previous tab is now the fourth.
eq(4, eval('tabpagenr(\'#\')')) eq(4, eval("tabpagenr('#')"))
-- Switch to the previous (fourth) tab -- Switch to the previous (fourth) tab
feed(characters) feed(characters)
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
[No Name] [No Name]
@@ -343,21 +401,29 @@ describe('tabpage/previous', function()
[No Name] [No Name]
Tab page 4 Tab page 4
> [No Name]]=]), > [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
-- The previous tab is now the second. -- The previous tab is now the second.
eq(2, eval('tabpagenr(\'#\')')) eq(2, eval("tabpagenr('#')"))
end end
end end
it('switches to previous via g<Tab> after numbered tab switch', it(
switches_to_previous_after_numbered_tab_switch('g<Tab>')) 'switches to previous via g<Tab> after numbered tab switch',
it('switches to previous via <C-W>g<Tab> after numbered tab switch', switches_to_previous_after_numbered_tab_switch('g<Tab>')
switches_to_previous_after_numbered_tab_switch('<C-W>g<Tab>')) )
it('switches to previous via <C-Tab> after numbered tab switch', it(
switches_to_previous_after_numbered_tab_switch('<C-Tab>')) 'switches to previous via <C-W>g<Tab> after numbered tab switch',
it('switches to previous via :tabn #<CR> after numbered tab switch', switches_to_previous_after_numbered_tab_switch('<C-W>g<Tab>')
switches_to_previous_after_numbered_tab_switch(':tabn #<CR>')) )
it(
'switches to previous via <C-Tab> after numbered tab switch',
switches_to_previous_after_numbered_tab_switch('<C-Tab>')
)
it(
'switches to previous via :tabn #<CR> after numbered tab switch',
switches_to_previous_after_numbered_tab_switch(':tabn #<CR>')
)
local function switches_to_previous_after_switching_to_previous(characters1, characters2) local function switches_to_previous_after_switching_to_previous(characters1, characters2)
return function() return function()
@@ -371,12 +437,13 @@ describe('tabpage/previous', function()
feed(characters1) feed(characters1)
-- The previous tab is now the second. -- The previous tab is now the second.
eq(2, eval('tabpagenr(\'#\')')) eq(2, eval("tabpagenr('#')"))
-- Switch to the previous (second) tab -- Switch to the previous (second) tab
feed(characters2) feed(characters2)
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
[No Name] [No Name]
@@ -386,45 +453,77 @@ describe('tabpage/previous', function()
[No Name] [No Name]
Tab page 4 Tab page 4
# [No Name]]=]), # [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
-- The previous tab is now the fourth. -- The previous tab is now the fourth.
eq(4, eval('tabpagenr(\'#\')')) eq(4, eval("tabpagenr('#')"))
end end
end end
it('switches to previous via g<Tab> after switching to previous via g<Tab>', it(
switches_to_previous_after_switching_to_previous('g<Tab>', 'g<Tab>')) 'switches to previous via g<Tab> after switching to previous via g<Tab>',
it('switches to previous via <C-W>g<Tab> after switching to previous via g<Tab>', switches_to_previous_after_switching_to_previous('g<Tab>', 'g<Tab>')
switches_to_previous_after_switching_to_previous('g<Tab>', '<C-W>g<Tab>')) )
it('switches to previous via <C-Tab> after switching to previous via g<Tab>', it(
switches_to_previous_after_switching_to_previous('g<Tab>', '<C-Tab>')) 'switches to previous via <C-W>g<Tab> after switching to previous via g<Tab>',
it('switches to previous via :tabn #<CR> after switching to previous via g<Tab>', switches_to_previous_after_switching_to_previous('g<Tab>', '<C-W>g<Tab>')
switches_to_previous_after_switching_to_previous('g<Tab>', ':tabn #<CR>')) )
it('switches to previous via g<Tab> after switching to previous via <C-W>g<Tab>', it(
switches_to_previous_after_switching_to_previous('<C-W>g<Tab>', 'g<Tab>')) 'switches to previous via <C-Tab> after switching to previous via g<Tab>',
it('switches to previous via <C-W>g<Tab> after switching to previous via <C-W>g<Tab>', switches_to_previous_after_switching_to_previous('g<Tab>', '<C-Tab>')
switches_to_previous_after_switching_to_previous('<C-W>g<Tab>', '<C-W>g<Tab>')) )
it('switches to previous via <C-Tab> after switching to previous via <C-W>g<Tab>', it(
switches_to_previous_after_switching_to_previous('<C-W>g<Tab>', '<C-Tab>')) 'switches to previous via :tabn #<CR> after switching to previous via g<Tab>',
it('switches to previous via :tabn #<CR> after switching to previous via <C-W>g<Tab>', switches_to_previous_after_switching_to_previous('g<Tab>', ':tabn #<CR>')
switches_to_previous_after_switching_to_previous('<C-W>g<Tab>', ':tabn #<CR>')) )
it('switches to previous via g<Tab> after switching to previous via <C-Tab>', it(
switches_to_previous_after_switching_to_previous('<C-Tab>', 'g<Tab>')) 'switches to previous via g<Tab> after switching to previous via <C-W>g<Tab>',
it('switches to previous via <C-W>g<Tab> after switching to previous via <C-Tab>', switches_to_previous_after_switching_to_previous('<C-W>g<Tab>', 'g<Tab>')
switches_to_previous_after_switching_to_previous('<C-Tab>', '<C-W>g<Tab>')) )
it('switches to previous via <C-Tab> after switching to previous via <C-Tab>', it(
switches_to_previous_after_switching_to_previous('<C-Tab>', '<C-Tab>')) 'switches to previous via <C-W>g<Tab> after switching to previous via <C-W>g<Tab>',
it('switches to previous via :tabn #<CR> after switching to previous via <C-Tab>', switches_to_previous_after_switching_to_previous('<C-W>g<Tab>', '<C-W>g<Tab>')
switches_to_previous_after_switching_to_previous('<C-Tab>', ':tabn #<CR>')) )
it('switches to previous via g<Tab> after switching to previous via :tabn #<CR>', it(
switches_to_previous_after_switching_to_previous(':tabn #<CR>', 'g<Tab>')) 'switches to previous via <C-Tab> after switching to previous via <C-W>g<Tab>',
it('switches to previous via <C-W>g<Tab> after switching to previous via :tabn #<CR>', switches_to_previous_after_switching_to_previous('<C-W>g<Tab>', '<C-Tab>')
switches_to_previous_after_switching_to_previous(':tabn #<CR>', '<C-W>g<Tab>')) )
it('switches to previous via <C-Tab> after switching to previous via <C-Tab>', it(
switches_to_previous_after_switching_to_previous(':tabn #<CR>', '<C-Tab>')) 'switches to previous via :tabn #<CR> after switching to previous via <C-W>g<Tab>',
it('switches to previous via :tabn #<CR> after switching to previous via :tabn #<CR>', switches_to_previous_after_switching_to_previous('<C-W>g<Tab>', ':tabn #<CR>')
switches_to_previous_after_switching_to_previous(':tabn #<CR>', ':tabn #<CR>')) )
it(
'switches to previous via g<Tab> after switching to previous via <C-Tab>',
switches_to_previous_after_switching_to_previous('<C-Tab>', 'g<Tab>')
)
it(
'switches to previous via <C-W>g<Tab> after switching to previous via <C-Tab>',
switches_to_previous_after_switching_to_previous('<C-Tab>', '<C-W>g<Tab>')
)
it(
'switches to previous via <C-Tab> after switching to previous via <C-Tab>',
switches_to_previous_after_switching_to_previous('<C-Tab>', '<C-Tab>')
)
it(
'switches to previous via :tabn #<CR> after switching to previous via <C-Tab>',
switches_to_previous_after_switching_to_previous('<C-Tab>', ':tabn #<CR>')
)
it(
'switches to previous via g<Tab> after switching to previous via :tabn #<CR>',
switches_to_previous_after_switching_to_previous(':tabn #<CR>', 'g<Tab>')
)
it(
'switches to previous via <C-W>g<Tab> after switching to previous via :tabn #<CR>',
switches_to_previous_after_switching_to_previous(':tabn #<CR>', '<C-W>g<Tab>')
)
it(
'switches to previous via <C-Tab> after switching to previous via <C-Tab>',
switches_to_previous_after_switching_to_previous(':tabn #<CR>', '<C-Tab>')
)
it(
'switches to previous via :tabn #<CR> after switching to previous via :tabn #<CR>',
switches_to_previous_after_switching_to_previous(':tabn #<CR>', ':tabn #<CR>')
)
local function does_not_switch_to_previous_after_closing_current_tab(characters) local function does_not_switch_to_previous_after_closing_current_tab(characters)
return function() return function()
@@ -436,13 +535,14 @@ describe('tabpage/previous', function()
command('wincmd c') command('wincmd c')
-- The previous tab is now the "zeroth" -- there isn't one. -- The previous tab is now the "zeroth" -- there isn't one.
eq(0, eval('tabpagenr(\'#\')')) eq(0, eval("tabpagenr('#')"))
-- At this point, switching to the "previous" (i.e. fourth) tab would mean -- At this point, switching to the "previous" (i.e. fourth) tab would mean
-- switching to either a dangling or a null pointer. -- switching to either a dangling or a null pointer.
feed(characters) feed(characters)
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
[No Name] [No Name]
@@ -450,21 +550,29 @@ describe('tabpage/previous', function()
[No Name] [No Name]
Tab page 3 Tab page 3
> [No Name]]=]), > [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
-- The previous tab is now the "zero". -- The previous tab is now the "zero".
eq(0, eval('tabpagenr(\'#\')')) eq(0, eval("tabpagenr('#')"))
end end
end end
it('does not switch to previous via g<Tab> after closing current tab', it(
does_not_switch_to_previous_after_closing_current_tab('g<Tab>')) 'does not switch to previous via g<Tab> after closing current tab',
it('does not switch to previous via <C-W>g<Tab> after closing current tab', does_not_switch_to_previous_after_closing_current_tab('g<Tab>')
does_not_switch_to_previous_after_closing_current_tab('<C-W>g<Tab>')) )
it('does not switch to previous via <C-Tab> after closing current tab', it(
does_not_switch_to_previous_after_closing_current_tab('<C-Tab>')) 'does not switch to previous via <C-W>g<Tab> after closing current tab',
it('does not switch to previous via :tabn #<CR> after closing current tab', does_not_switch_to_previous_after_closing_current_tab('<C-W>g<Tab>')
does_not_switch_to_previous_after_closing_current_tab(':tabn #<CR>')) )
it(
'does not switch to previous via <C-Tab> after closing current tab',
does_not_switch_to_previous_after_closing_current_tab('<C-Tab>')
)
it(
'does not switch to previous via :tabn #<CR> after closing current tab',
does_not_switch_to_previous_after_closing_current_tab(':tabn #<CR>')
)
local function does_not_switch_to_previous_after_entering_operator_pending(characters) local function does_not_switch_to_previous_after_entering_operator_pending(characters)
return function() return function()
@@ -474,7 +582,7 @@ describe('tabpage/previous', function()
command('tabnew') command('tabnew')
-- The previous tab is now the third. -- The previous tab is now the third.
eq(3, eval('tabpagenr(\'#\')')) eq(3, eval("tabpagenr('#')"))
-- Enter operator pending mode. -- Enter operator pending mode.
feed('d') feed('d')
@@ -491,11 +599,13 @@ describe('tabpage/previous', function()
eq(4, eval('tabpagenr()')) eq(4, eval('tabpagenr()'))
-- The previous tab is still the third. -- The previous tab is still the third.
eq(3, eval('tabpagenr(\'#\')')) eq(3, eval("tabpagenr('#')"))
end end
end end
it('does not switch to previous via g<Tab> after entering operator pending', it(
does_not_switch_to_previous_after_entering_operator_pending('g<Tab>')) 'does not switch to previous via g<Tab> after entering operator pending',
does_not_switch_to_previous_after_entering_operator_pending('g<Tab>')
)
-- NOTE: When in operator pending mode, attempting to switch to previous has -- NOTE: When in operator pending mode, attempting to switch to previous has
-- the following effect: -- the following effect:
-- - Ctrl-W exits operator pending mode -- - Ctrl-W exits operator pending mode
@@ -506,8 +616,10 @@ describe('tabpage/previous', function()
-- be the same as the normal mode command to switch to the previous tab. -- be the same as the normal mode command to switch to the previous tab.
-- it('does not switch to previous via <C-W>g<Tab> after entering operator pending', -- it('does not switch to previous via <C-W>g<Tab> after entering operator pending',
-- does_not_switch_to_previous_after_entering_operator_pending('<C-W>g<Tab>')) -- does_not_switch_to_previous_after_entering_operator_pending('<C-W>g<Tab>'))
it('does not switch to previous via <C-Tab> after entering operator pending', it(
does_not_switch_to_previous_after_entering_operator_pending('<C-Tab>')) 'does not switch to previous via <C-Tab> after entering operator pending',
does_not_switch_to_previous_after_entering_operator_pending('<C-Tab>')
)
-- NOTE: When in operator pending mode, pressing : leaves operator pending -- NOTE: When in operator pending mode, pressing : leaves operator pending
-- mode and enters command mode, so :tabn #<CR> does in fact switch -- mode and enters command mode, so :tabn #<CR> does in fact switch
-- tabs. -- tabs.
@@ -522,7 +634,7 @@ describe('tabpage/previous', function()
command('tabnew') command('tabnew')
-- The previous tab is now the third. -- The previous tab is now the third.
eq(3, eval('tabpagenr(\'#\')')) eq(3, eval("tabpagenr('#')"))
-- Edit : command line in command-line window -- Edit : command line in command-line window
feed('q:') feed('q:')
@@ -540,31 +652,34 @@ describe('tabpage/previous', function()
eq(4, eval('tabpagenr()')) eq(4, eval('tabpagenr()'))
-- The previous tab is still the third. -- The previous tab is still the third.
eq(3, eval('tabpagenr(\'#\')')) eq(3, eval("tabpagenr('#')"))
end end
end end
it('cmdline-win prevents tab switch via g<Tab>', it('cmdline-win prevents tab switch via g<Tab>', cmdline_win_prevents_tab_switch('g<Tab>', 0))
cmdline_win_prevents_tab_switch('g<Tab>', 0)) it(
it('cmdline-win prevents tab switch via <C-W>g<Tab>', 'cmdline-win prevents tab switch via <C-W>g<Tab>',
cmdline_win_prevents_tab_switch('<C-W>g<Tab>', 1)) cmdline_win_prevents_tab_switch('<C-W>g<Tab>', 1)
it('cmdline-win prevents tab switch via <C-Tab>', )
cmdline_win_prevents_tab_switch('<C-Tab>', 0)) it('cmdline-win prevents tab switch via <C-Tab>', cmdline_win_prevents_tab_switch('<C-Tab>', 0))
it('cmdline-win prevents tab switch via :tabn #<CR>', it(
cmdline_win_prevents_tab_switch(':tabn #<CR>', 0)) 'cmdline-win prevents tab switch via :tabn #<CR>',
cmdline_win_prevents_tab_switch(':tabn #<CR>', 0)
)
it(':tabs indicates correct prevtab curwin', function() it(':tabs indicates correct prevtab curwin', function()
-- Add three tabs for a total of four -- Add three tabs for a total of four
command('tabnew') command('tabnew')
command('tabnew') command('tabnew')
command('split') command('split')
command('vsplit') command('vsplit')
feed('<C-w>p') feed('<C-w>p')
command('tabnew') command('tabnew')
-- The previous tab is now the three. -- The previous tab is now the three.
eq(3, eval('tabpagenr(\'#\')')) eq(3, eval("tabpagenr('#')"))
eq(dedent([=[ eq(
dedent([=[
Tab page 1 Tab page 1
[No Name] [No Name]
@@ -576,7 +691,7 @@ describe('tabpage/previous', function()
[No Name] [No Name]
Tab page 4 Tab page 4
> [No Name]]=]), > [No Name]]=]),
exec_capture('tabs') exec_capture('tabs')
) )
end) end)
end) end)

View File

@@ -2,10 +2,8 @@ local luv = require('luv')
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers') local thelpers = require('test.functional.terminal.helpers')
local clear, command, nvim, testprg = local clear, command, nvim, testprg = helpers.clear, helpers.command, helpers.nvim, helpers.testprg
helpers.clear, helpers.command, helpers.nvim, helpers.testprg local eval, eq, neq, retry = helpers.eval, helpers.eq, helpers.neq, helpers.retry
local eval, eq, neq, retry =
helpers.eval, helpers.eq, helpers.neq, helpers.retry
local matches = helpers.matches local matches = helpers.matches
local ok = helpers.ok local ok = helpers.ok
local feed = helpers.feed local feed = helpers.feed
@@ -27,8 +25,10 @@ describe('autocmd TermClose', function()
nvim('set_option_value', 'shell', string.format('"%s" INTERACT', testprg('shell-test')), {}) nvim('set_option_value', 'shell', string.format('"%s" INTERACT', testprg('shell-test')), {})
command('autocmd TermClose * bdelete!') command('autocmd TermClose * bdelete!')
command('terminal') command('terminal')
matches('^TermClose Autocommands for "%*": Vim%(bdelete%):E937: Attempt to delete a buffer that is in use: term://', matches(
pcall_err(command, 'bdelete!')) '^TermClose Autocommands for "%*": Vim%(bdelete%):E937: Attempt to delete a buffer that is in use: term://',
pcall_err(command, 'bdelete!')
)
assert_alive() assert_alive()
end end
@@ -46,8 +46,12 @@ describe('autocmd TermClose', function()
command('autocmd TermClose * let g:test_termclose = 23') command('autocmd TermClose * let g:test_termclose = 23')
command('terminal') command('terminal')
-- shell-test exits immediately. -- shell-test exits immediately.
retry(nil, nil, function() neq(-1, eval('jobwait([&channel], 0)[0]')) end) retry(nil, nil, function()
retry(nil, nil, function() eq(23, eval('g:test_termclose')) end) neq(-1, eval('jobwait([&channel], 0)[0]'))
end)
retry(nil, nil, function()
eq(23, eval('g:test_termclose'))
end)
end) end)
it('triggers when long-running terminal job gets stopped', function() it('triggers when long-running terminal job gets stopped', function()
@@ -56,48 +60,62 @@ describe('autocmd TermClose', function()
command('autocmd TermClose * let g:test_termclose = 23') command('autocmd TermClose * let g:test_termclose = 23')
command('terminal') command('terminal')
command('call jobstop(b:terminal_job_id)') command('call jobstop(b:terminal_job_id)')
retry(nil, nil, function() eq(23, eval('g:test_termclose')) end) retry(nil, nil, function()
eq(23, eval('g:test_termclose'))
end)
end) end)
it('kills job trapping SIGTERM', function() it('kills job trapping SIGTERM', function()
skip(is_os('win')) skip(is_os('win'))
nvim('set_option_value', 'shell', 'sh', {}) nvim('set_option_value', 'shell', 'sh', {})
nvim('set_option_value', 'shellcmdflag', '-c', {}) nvim('set_option_value', 'shellcmdflag', '-c', {})
command([[ let g:test_job = jobstart('trap "" TERM && echo 1 && sleep 60', { ]] command(
.. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]] [[ let g:test_job = jobstart('trap "" TERM && echo 1 && sleep 60', { ]]
.. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]]) .. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]]
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_started", 0)')) end) .. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]]
)
retry(nil, nil, function()
eq(1, eval('get(g:, "test_job_started", 0)'))
end)
luv.update_time() luv.update_time()
local start = luv.now() local start = luv.now()
command('call jobstop(g:test_job)') command('call jobstop(g:test_job)')
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end) retry(nil, nil, function()
eq(1, eval('get(g:, "test_job_exited", 0)'))
end)
luv.update_time() luv.update_time()
local duration = luv.now() - start local duration = luv.now() - start
-- Nvim begins SIGTERM after KILL_TIMEOUT_MS. -- Nvim begins SIGTERM after KILL_TIMEOUT_MS.
ok(duration >= 2000) ok(duration >= 2000)
ok(duration <= 4000) -- Epsilon for slow CI ok(duration <= 4000) -- Epsilon for slow CI
end) end)
it('kills PTY job trapping SIGHUP and SIGTERM', function() it('kills PTY job trapping SIGHUP and SIGTERM', function()
skip(is_os('win')) skip(is_os('win'))
nvim('set_option_value', 'shell', 'sh', {}) nvim('set_option_value', 'shell', 'sh', {})
nvim('set_option_value', 'shellcmdflag', '-c', {}) nvim('set_option_value', 'shellcmdflag', '-c', {})
command([[ let g:test_job = jobstart('trap "" HUP TERM && echo 1 && sleep 60', { ]] command(
.. [[ 'pty': 1,]] [[ let g:test_job = jobstart('trap "" HUP TERM && echo 1 && sleep 60', { ]]
.. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]] .. [[ 'pty': 1,]]
.. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]]) .. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]]
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_started", 0)')) end) .. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]]
)
retry(nil, nil, function()
eq(1, eval('get(g:, "test_job_started", 0)'))
end)
luv.update_time() luv.update_time()
local start = luv.now() local start = luv.now()
command('call jobstop(g:test_job)') command('call jobstop(g:test_job)')
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end) retry(nil, nil, function()
eq(1, eval('get(g:, "test_job_exited", 0)'))
end)
luv.update_time() luv.update_time()
local duration = luv.now() - start local duration = luv.now() - start
-- Nvim begins SIGKILL after (2 * KILL_TIMEOUT_MS). -- Nvim begins SIGKILL after (2 * KILL_TIMEOUT_MS).
ok(duration >= 4000) ok(duration >= 4000)
ok(duration <= 7000) -- Epsilon for slow CI ok(duration <= 7000) -- Epsilon for slow CI
end) end)
it('reports the correct <abuf>', function() it('reports the correct <abuf>', function()
@@ -109,13 +127,19 @@ describe('autocmd TermClose', function()
eq(2, eval('bufnr("%")')) eq(2, eval('bufnr("%")'))
command('terminal ls') command('terminal ls')
retry(nil, nil, function() eq(3, eval('bufnr("%")')) end) retry(nil, nil, function()
eq(3, eval('bufnr("%")'))
end)
command('buffer 1') command('buffer 1')
retry(nil, nil, function() eq(1, eval('bufnr("%")')) end) retry(nil, nil, function()
eq(1, eval('bufnr("%")'))
end)
command('3bdelete!') command('3bdelete!')
retry(nil, nil, function() eq('3', eval('g:abuf')) end) retry(nil, nil, function()
eq('3', eval('g:abuf'))
end)
feed('<c-c>:qa!<cr>') feed('<c-c>:qa!<cr>')
end) end)
@@ -124,10 +148,14 @@ describe('autocmd TermClose', function()
command('autocmd TermClose * let g:status = v:event.status') command('autocmd TermClose * let g:status = v:event.status')
command('terminal 0') command('terminal 0')
retry(nil, nil, function() eq(0, eval('g:status')) end) retry(nil, nil, function()
eq(0, eval('g:status'))
end)
command('terminal 42') command('terminal 42')
retry(nil, nil, function() eq(42, eval('g:status')) end) retry(nil, nil, function()
eq(42, eval('g:status'))
end)
end) end)
end) end)
@@ -141,27 +169,30 @@ it('autocmd TermEnter, TermLeave', function()
command('terminal') command('terminal')
feed('i') feed('i')
eq({ {'TermOpen', 'n'}, {'TermEnter', 't'}, }, eval('g:evs')) eq({ { 'TermOpen', 'n' }, { 'TermEnter', 't' } }, eval('g:evs'))
feed([[<C-\><C-n>]]) feed([[<C-\><C-n>]])
feed('A') feed('A')
eq({ {'TermOpen', 'n'}, {'TermEnter', 't'}, {'TermLeave', 'n'}, {'TermEnter', 't'}, }, eval('g:evs')) eq(
{ { 'TermOpen', 'n' }, { 'TermEnter', 't' }, { 'TermLeave', 'n' }, { 'TermEnter', 't' } },
eval('g:evs')
)
-- TermLeave is also triggered by :quit. -- TermLeave is also triggered by :quit.
command('split foo') command('split foo')
feed('<Ignore>') -- Add input to separate two RPC requests feed('<Ignore>') -- Add input to separate two RPC requests
command('wincmd w') command('wincmd w')
feed('i') feed('i')
command('q!') command('q!')
feed('<Ignore>') -- Add input to separate two RPC requests feed('<Ignore>') -- Add input to separate two RPC requests
eq({ eq({
{'TermOpen', 'n'}, { 'TermOpen', 'n' },
{'TermEnter', 't'}, { 'TermEnter', 't' },
{'TermLeave', 'n'}, { 'TermLeave', 'n' },
{'TermEnter', 't'}, { 'TermEnter', 't' },
{'TermLeave', 'n'}, { 'TermLeave', 'n' },
{'TermEnter', 't'}, { 'TermEnter', 't' },
{'TermClose', 't'}, { 'TermClose', 't' },
{'TermLeave', 'n'}, { 'TermLeave', 'n' },
}, eval('g:evs')) }, eval('g:evs'))
end) end)
@@ -172,13 +203,15 @@ describe('autocmd TextChangedT', function()
it('works', function() it('works', function()
command('autocmd TextChangedT * ++once let g:called = 1') command('autocmd TextChangedT * ++once let g:called = 1')
thelpers.feed_data('a') thelpers.feed_data('a')
retry(nil, nil, function() eq(1, meths.get_var('called')) end) retry(nil, nil, function()
eq(1, meths.get_var('called'))
end)
end) end)
it('cannot delete terminal buffer', function() it('cannot delete terminal buffer', function()
command([[autocmd TextChangedT * call nvim_input('<CR>') | bwipe!]]) command([[autocmd TextChangedT * call nvim_input('<CR>') | bwipe!]])
thelpers.feed_data('a') thelpers.feed_data('a')
screen:expect({any = 'E937: '}) screen:expect({ any = 'E937: ' })
matches('^E937: Attempt to delete a buffer that is in use: term://', meths.get_vvar('errmsg')) matches('^E937: Attempt to delete a buffer that is in use: term://', meths.get_vvar('errmsg'))
end) end)
end) end)

View File

@@ -88,7 +88,7 @@ it('TextChangedI and TextChangedP autocommands', function()
eq('IIPPPP', eval('g:autocmd')) eq('IIPPPP', eval('g:autocmd'))
feed('<esc>') feed('<esc>')
eq({'foo', 'bar', 'foobar', 'foo'}, eval('getline(1, "$")')) eq({ 'foo', 'bar', 'foobar', 'foo' }, eval('getline(1, "$")'))
end) end)
-- oldtest: Test_TextChangedI_with_setline() -- oldtest: Test_TextChangedI_with_setline()
@@ -172,11 +172,11 @@ it('TextChangedI and TextChanged', function()
eq('', eval('g:autocmd_n')) eq('', eval('g:autocmd_n'))
end end
validate_mixed_textchangedi({'o', '<esc>'}) validate_mixed_textchangedi({ 'o', '<esc>' })
validate_mixed_textchangedi({'O', '<esc>'}) validate_mixed_textchangedi({ 'O', '<esc>' })
validate_mixed_textchangedi({'ciw', '<esc>'}) validate_mixed_textchangedi({ 'ciw', '<esc>' })
validate_mixed_textchangedi({'cc', '<esc>'}) validate_mixed_textchangedi({ 'cc', '<esc>' })
validate_mixed_textchangedi({'C', '<esc>'}) validate_mixed_textchangedi({ 'C', '<esc>' })
validate_mixed_textchangedi({'s', '<esc>'}) validate_mixed_textchangedi({ 's', '<esc>' })
validate_mixed_textchangedi({'S', '<esc>'}) validate_mixed_textchangedi({ 'S', '<esc>' })
end) end)

View File

@@ -28,7 +28,7 @@ describe('TextYankPost', function()
regcontents = { 'foo\nbar' }, regcontents = { 'foo\nbar' },
regname = '', regname = '',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(1, eval('g:count')) eq(1, eval('g:count'))
@@ -42,7 +42,7 @@ describe('TextYankPost', function()
regcontents = { 'baz ' }, regcontents = { 'baz ' },
regname = '', regname = '',
regtype = 'v', regtype = 'v',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(2, eval('g:count')) eq(2, eval('g:count'))
@@ -52,8 +52,8 @@ describe('TextYankPost', function()
operator = 'y', operator = 'y',
regcontents = { 'foo', 'baz' }, regcontents = { 'foo', 'baz' },
regname = '', regname = '',
regtype = "\0223", -- ^V + block width regtype = '\0223', -- ^V + block width
visual = true visual = true,
}, eval('g:event')) }, eval('g:event'))
eq(3, eval('g:count')) eq(3, eval('g:count'))
end) end)
@@ -66,25 +66,25 @@ describe('TextYankPost', function()
regcontents = { 'foo\nbar' }, regcontents = { 'foo\nbar' },
regname = '', regname = '',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
command('set debug=msg') command('set debug=msg')
-- the regcontents should not be changed without copy. -- the regcontents should not be changed without copy.
local status, err = pcall(command,'call extend(g:event.regcontents, ["more text"])') local status, err = pcall(command, 'call extend(g:event.regcontents, ["more text"])')
eq(status,false) eq(status, false)
neq(nil, string.find(err, ':E742:')) neq(nil, string.find(err, ':E742:'))
-- can't mutate keys inside the autocommand -- can't mutate keys inside the autocommand
command('autocmd! TextYankPost * let v:event.regcontents = 0') command('autocmd! TextYankPost * let v:event.regcontents = 0')
status, err = pcall(command,'normal yy') status, err = pcall(command, 'normal yy')
eq(status,false) eq(status, false)
neq(nil, string.find(err, ':E46:')) neq(nil, string.find(err, ':E46:'))
-- can't add keys inside the autocommand -- can't add keys inside the autocommand
command('autocmd! TextYankPost * let v:event.mykey = 0') command('autocmd! TextYankPost * let v:event.mykey = 0')
status, err = pcall(command,'normal yy') status, err = pcall(command, 'normal yy')
eq(status,false) eq(status, false)
neq(nil, string.find(err, ':E742:')) neq(nil, string.find(err, ':E742:'))
end) end)
@@ -97,10 +97,10 @@ describe('TextYankPost', function()
regcontents = { 'foo\nbar' }, regcontents = { 'foo\nbar' },
regname = '', regname = '',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(1, eval('g:count')) eq(1, eval('g:count'))
eq({ 'foo\nbar' }, funcs.getreg('+',1,1)) eq({ 'foo\nbar' }, funcs.getreg('+', 1, 1))
end) end)
it('is executed after delete and change', function() it('is executed after delete and change', function()
@@ -111,7 +111,7 @@ describe('TextYankPost', function()
regcontents = { 'foo' }, regcontents = { 'foo' },
regname = '', regname = '',
regtype = 'v', regtype = 'v',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(1, eval('g:count')) eq(1, eval('g:count'))
@@ -122,7 +122,7 @@ describe('TextYankPost', function()
regcontents = { '\nbar' }, regcontents = { '\nbar' },
regname = '', regname = '',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(2, eval('g:count')) eq(2, eval('g:count'))
@@ -133,7 +133,7 @@ describe('TextYankPost', function()
regcontents = { 'baz' }, regcontents = { 'baz' },
regname = '', regname = '',
regtype = 'v', regtype = 'v',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(3, eval('g:count')) eq(3, eval('g:count'))
end) end)
@@ -162,7 +162,7 @@ describe('TextYankPost', function()
regcontents = { 'bar' }, regcontents = { 'bar' },
regname = 'b', regname = 'b',
regtype = 'v', regtype = 'v',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
feed('"*yy') feed('"*yy')
@@ -172,10 +172,10 @@ describe('TextYankPost', function()
regcontents = { 'foo\nbar' }, regcontents = { 'foo\nbar' },
regname = '*', regname = '*',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
command("set clipboard=unnamed") command('set clipboard=unnamed')
-- regname still shows the name the user requested -- regname still shows the name the user requested
feed('yy') feed('yy')
@@ -185,7 +185,7 @@ describe('TextYankPost', function()
regcontents = { 'foo\nbar' }, regcontents = { 'foo\nbar' },
regname = '', regname = '',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
feed('"*yy') feed('"*yy')
@@ -195,7 +195,7 @@ describe('TextYankPost', function()
regcontents = { 'foo\nbar' }, regcontents = { 'foo\nbar' },
regname = '*', regname = '*',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
end) end)
@@ -207,7 +207,7 @@ describe('TextYankPost', function()
regcontents = { 'foo\nbar' }, regcontents = { 'foo\nbar' },
regname = '+', regname = '+',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(1, eval('g:count')) eq(1, eval('g:count'))
@@ -218,7 +218,7 @@ describe('TextYankPost', function()
regcontents = { 'baz text' }, regcontents = { 'baz text' },
regname = '', regname = '',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(2, eval('g:count')) eq(2, eval('g:count'))
@@ -229,7 +229,7 @@ describe('TextYankPost', function()
regcontents = { 'baz ' }, regcontents = { 'baz ' },
regname = '', regname = '',
regtype = 'v', regtype = 'v',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(3, eval('g:count')) eq(3, eval('g:count'))
@@ -240,7 +240,7 @@ describe('TextYankPost', function()
regcontents = { 'baz text' }, regcontents = { 'baz text' },
regname = '', regname = '',
regtype = 'V', regtype = 'V',
visual = false visual = false,
}, eval('g:event')) }, eval('g:event'))
eq(4, eval('g:count')) eq(4, eval('g:count'))
end) end)

View File

@@ -32,12 +32,12 @@ describe('WinResized', function()
-- increase window height, two windows will be reported -- increase window height, two windows will be reported
feed('<C-W>+') feed('<C-W>+')
eq(1, eval('g:resized')) eq(1, eval('g:resized'))
eq({windows = {1002, 1001}}, eval('g:v_event')) eq({ windows = { 1002, 1001 } }, eval('g:v_event'))
-- increase window width, three windows will be reported -- increase window width, three windows will be reported
feed('<C-W>>') feed('<C-W>>')
eq(2, eval('g:resized')) eq(2, eval('g:resized'))
eq({windows = {1002, 1001, 1000}}, eval('g:v_event')) eq({ windows = { 1002, 1001, 1000 } }, eval('g:v_event'))
end) end)
end) end)
@@ -63,22 +63,22 @@ describe('WinScrolled', function()
end) end)
it('is triggered by scrolling vertically', function() it('is triggered by scrolling vertically', function()
local lines = {'123', '123'} local lines = { '123', '123' }
meths.buf_set_lines(0, 0, -1, true, lines) meths.buf_set_lines(0, 0, -1, true, lines)
eq(0, eval('g:scrolled')) eq(0, eval('g:scrolled'))
feed('<C-E>') feed('<C-E>')
eq(1, eval('g:scrolled')) eq(1, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('<C-Y>') feed('<C-Y>')
eq(2, eval('g:scrolled')) eq(2, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 0, topline = -1, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 0, topline = -1, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
end) end)
@@ -86,58 +86,58 @@ describe('WinScrolled', function()
command('set nowrap') command('set nowrap')
local width = meths.win_get_width(0) local width = meths.win_get_width(0)
local line = '123' .. ('*'):rep(width * 2) local line = '123' .. ('*'):rep(width * 2)
local lines = {line, line} local lines = { line, line }
meths.buf_set_lines(0, 0, -1, true, lines) meths.buf_set_lines(0, 0, -1, true, lines)
eq(0, eval('g:scrolled')) eq(0, eval('g:scrolled'))
feed('zl') feed('zl')
eq(1, eval('g:scrolled')) eq(1, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('zh') feed('zh')
eq(2, eval('g:scrolled')) eq(2, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = -1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = -1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
end) end)
it('is triggered by horizontal scrolling from cursor move', function() it('is triggered by horizontal scrolling from cursor move', function()
command('set nowrap') command('set nowrap')
local lines = {'', '', 'Foo'} local lines = { '', '', 'Foo' }
meths.buf_set_lines(0, 0, -1, true, lines) meths.buf_set_lines(0, 0, -1, true, lines)
meths.win_set_cursor(0, {3, 0}) meths.win_set_cursor(0, { 3, 0 })
eq(0, eval('g:scrolled')) eq(0, eval('g:scrolled'))
feed('zl') feed('zl')
eq(1, eval('g:scrolled')) eq(1, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('zl') feed('zl')
eq(2, eval('g:scrolled')) eq(2, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('h') feed('h')
eq(3, eval('g:scrolled')) eq(3, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = -1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = -1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('zh') feed('zh')
eq(4, eval('g:scrolled')) eq(4, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = -1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = -1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
end) end)
@@ -145,22 +145,22 @@ describe('WinScrolled', function()
it('is triggered by scrolling on a long wrapped line #19968', function() it('is triggered by scrolling on a long wrapped line #19968', function()
local height = meths.win_get_height(0) local height = meths.win_get_height(0)
local width = meths.win_get_width(0) local width = meths.win_get_width(0)
meths.buf_set_lines(0, 0, -1, true, {('foo'):rep(height * width)}) meths.buf_set_lines(0, 0, -1, true, { ('foo'):rep(height * width) })
meths.win_set_cursor(0, {1, height * width - 1}) meths.win_set_cursor(0, { 1, height * width - 1 })
eq(0, eval('g:scrolled')) eq(0, eval('g:scrolled'))
feed('gj') feed('gj')
eq(1, eval('g:scrolled')) eq(1, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = width}, all = { leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = width },
['1000'] = {leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = width}, ['1000'] = { leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = width },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('0') feed('0')
eq(2, eval('g:scrolled')) eq(2, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = width}, all = { leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = width },
['1000'] = {leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = -width}, ['1000'] = { leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = -width },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('$') feed('$')
@@ -181,15 +181,15 @@ describe('WinScrolled', function()
feed('i<C-X><C-E><Esc>') feed('i<C-X><C-E><Esc>')
eq(1, eval('g:scrolled')) eq(1, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('i<C-X><C-Y><Esc>') feed('i<C-X><C-Y><Esc>')
eq(2, eval('g:scrolled')) eq(2, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 0, topline = -1, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 0, topline = -1, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('L') feed('L')
@@ -198,8 +198,8 @@ describe('WinScrolled', function()
feed('A<CR><Esc>') feed('A<CR><Esc>')
eq(3, eval('g:scrolled')) eq(3, eval('g:scrolled'))
eq({ eq({
all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
end) end)
end) end)
@@ -257,30 +257,30 @@ describe('WinScrolled', function()
feed('<C-E>') feed('<C-E>')
eq({ eq({
all = {leftcol = 0, topline = 1, topfill = 1, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 1, topfill = 1, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1001'] = {leftcol = 0, topline = 0, topfill = -1, width = 0, height = 0, skipcol = 0}, ['1001'] = { leftcol = 0, topline = 0, topfill = -1, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('2<C-E>') feed('2<C-E>')
eq({ eq({
all = {leftcol = 0, topline = 2, topfill = 2, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 2, topfill = 2, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 0, topline = 2, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 0, topline = 2, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1001'] = {leftcol = 0, topline = 0, topfill = -2, width = 0, height = 0, skipcol = 0}, ['1001'] = { leftcol = 0, topline = 0, topfill = -2, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('<C-E>') feed('<C-E>')
eq({ eq({
all = {leftcol = 0, topline = 2, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 2, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1001'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1001'] = { leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
feed('2<C-Y>') feed('2<C-Y>')
eq({ eq({
all = {leftcol = 0, topline = 3, topfill = 1, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 3, topfill = 1, width = 0, height = 0, skipcol = 0 },
['1000'] = {leftcol = 0, topline = -2, topfill = 0, width = 0, height = 0, skipcol = 0}, ['1000'] = { leftcol = 0, topline = -2, topfill = 0, width = 0, height = 0, skipcol = 0 },
['1001'] = {leftcol = 0, topline = -1, topfill = 1, width = 0, height = 0, skipcol = 0}, ['1001'] = { leftcol = 0, topline = -1, topfill = 1, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
end) end)
@@ -297,14 +297,20 @@ describe('WinScrolled', function()
eq(0, eval('g:scrolled')) eq(0, eval('g:scrolled'))
local buf = meths.create_buf(true, true) local buf = meths.create_buf(true, true)
meths.buf_set_lines(buf, 0, -1, false, {'@', 'b', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n'}) meths.buf_set_lines(
buf,
0,
-1,
false,
{ '@', 'b', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n' }
)
local win = meths.open_win(buf, false, { local win = meths.open_win(buf, false, {
height = 5, height = 5,
width = 10, width = 10,
col = 0, col = 0,
row = 1, row = 1,
relative = 'editor', relative = 'editor',
style = 'minimal' style = 'minimal',
}) })
screen:expect({ any = '@' }) screen:expect({ any = '@' })
local winid_str = tostring(win.id) local winid_str = tostring(win.id)
@@ -315,16 +321,16 @@ describe('WinScrolled', function()
eq(1, eval('g:scrolled')) eq(1, eval('g:scrolled'))
eq(winid_str, eval('g:amatch')) eq(winid_str, eval('g:amatch'))
eq({ eq({
all = {leftcol = 0, topline = 3, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 3, topfill = 0, width = 0, height = 0, skipcol = 0 },
[winid_str] = {leftcol = 0, topline = 3, topfill = 0, width = 0, height = 0, skipcol = 0}, [winid_str] = { leftcol = 0, topline = 3, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
meths.input_mouse('wheel', 'up', '', 0, 3, 3) meths.input_mouse('wheel', 'up', '', 0, 3, 3)
eq(2, eval('g:scrolled')) eq(2, eval('g:scrolled'))
eq(tostring(win.id), eval('g:amatch')) eq(tostring(win.id), eval('g:amatch'))
eq({ eq({
all = {leftcol = 0, topline = 3, topfill = 0, width = 0, height = 0, skipcol = 0}, all = { leftcol = 0, topline = 3, topfill = 0, width = 0, height = 0, skipcol = 0 },
[winid_str] = {leftcol = 0, topline = -3, topfill = 0, width = 0, height = 0, skipcol = 0}, [winid_str] = { leftcol = 0, topline = -3, topfill = 0, width = 0, height = 0, skipcol = 0 },
}, eval('g:v_event')) }, eval('g:v_event'))
end) end)
end) end)

View File

@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local clear, eq, eval, next_msg, ok, source = helpers.clear, helpers.eq, local clear, eq, eval, next_msg, ok, source =
helpers.eval, helpers.next_msg, helpers.ok, helpers.source helpers.clear, helpers.eq, helpers.eval, helpers.next_msg, helpers.ok, helpers.source
local command, funcs, meths = helpers.command, helpers.funcs, helpers.meths local command, funcs, meths = helpers.command, helpers.funcs, helpers.meths
local sleep = helpers.sleep local sleep = helpers.sleep
local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv
@@ -40,7 +40,7 @@ describe('channels', function()
meths.set_var('address', address) meths.set_var('address', address)
command("let g:id = sockconnect('pipe', address, {'on_data':'OnEvent'})") command("let g:id = sockconnect('pipe', address, {'on_data':'OnEvent'})")
local id = eval("g:id") local id = eval('g:id')
ok(id > 0) ok(id > 0)
command("call chansend(g:id, msgpackdump([[2,'nvim_set_var',['code',23]]]))") command("call chansend(g:id, msgpackdump([[2,'nvim_set_var',['code',23]]]))")
@@ -52,12 +52,11 @@ describe('channels', function()
command("call chansend(g:id, msgpackdump([[0,0,'nvim_eval',['2+3']]]))") command("call chansend(g:id, msgpackdump([[0,0,'nvim_eval',['2+3']]]))")
local res = eval('msgpackdump([[1,0,v:null,5]])')
local res = eval("msgpackdump([[1,0,v:null,5]])") eq({ '\148\001\n\192\005' }, res)
eq({"\148\001\n\192\005"}, res) eq({ 'notification', 'data', { id, res } }, next_msg())
eq({'notification', 'data', {id, res}}, next_msg())
command("call chansend(g:id, msgpackdump([[2,'nvim_command',['quit']]]))") command("call chansend(g:id, msgpackdump([[2,'nvim_command',['quit']]]))")
eq({'notification', 'data', {id, {''}}}, next_msg()) eq({ 'notification', 'data', { id, { '' } } }, next_msg())
end) end)
it('can use stdio channel', function() it('can use stdio channel', function()
@@ -68,8 +67,10 @@ describe('channels', function()
\ 'on_exit': function('OnEvent'), \ 'on_exit': function('OnEvent'),
\ } \ }
]]) ]])
meths.set_var("nvim_prog", nvim_prog) meths.set_var('nvim_prog', nvim_prog)
meths.set_var("code", [[ meths.set_var(
'code',
[[
function! OnEvent(id, data, event) dict function! OnEvent(id, data, event) dict
let text = string([a:id, a:data, a:event]) let text = string([a:id, a:data, a:event])
call chansend(g:x, text) call chansend(g:x, text)
@@ -81,25 +82,31 @@ describe('channels', function()
endfunction endfunction
let g:x = stdioopen({'on_stdin':'OnEvent'}) let g:x = stdioopen({'on_stdin':'OnEvent'})
call chansend(x, "hello") call chansend(x, "hello")
]]) ]]
command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)") )
local id = eval("g:id") command(
"let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)"
)
local id = eval('g:id')
ok(id > 0) ok(id > 0)
eq({ "notification", "stdout", {id, { "hello" } } }, next_msg()) eq({ 'notification', 'stdout', { id, { 'hello' } } }, next_msg())
command("call chansend(id, 'howdy')") command("call chansend(id, 'howdy')")
eq({"notification", "stdout", {id, {"[1, ['howdy'], 'stdin']"}}}, next_msg()) eq({ 'notification', 'stdout', { id, { "[1, ['howdy'], 'stdin']" } } }, next_msg())
command("call chansend(id, 0z686f6c61)") command('call chansend(id, 0z686f6c61)')
eq({"notification", "stdout", {id, {"[1, ['hola'], 'stdin']"}}}, next_msg()) eq({ 'notification', 'stdout', { id, { "[1, ['hola'], 'stdin']" } } }, next_msg())
command("call chanclose(id, 'stdin')") command("call chanclose(id, 'stdin')")
expect_twostreams({{"notification", "stdout", {id, {"[1, [''], 'stdin']"}}}, expect_twostreams({
{'notification', 'stdout', {id, {''}}}}, { 'notification', 'stdout', { id, { "[1, [''], 'stdin']" } } },
{{"notification", "stderr", {id, {"*dies*"}}}, { 'notification', 'stdout', { id, { '' } } },
{'notification', 'stderr', {id, {''}}}}) }, {
eq({"notification", "exit", {3,0}}, next_msg()) { 'notification', 'stderr', { id, { '*dies*' } } },
{ 'notification', 'stderr', { id, { '' } } },
})
eq({ 'notification', 'exit', { 3, 0 } }, next_msg())
end) end)
it('can use stdio channel and on_print callback', function() it('can use stdio channel and on_print callback', function()
@@ -110,8 +117,10 @@ describe('channels', function()
\ 'on_exit': function('OnEvent'), \ 'on_exit': function('OnEvent'),
\ } \ }
]]) ]])
meths.set_var("nvim_prog", nvim_prog) meths.set_var('nvim_prog', nvim_prog)
meths.set_var("code", [[ meths.set_var(
'code',
[[
function! OnStdin(id, data, event) dict function! OnStdin(id, data, event) dict
echo string([a:id, a:data, a:event]) echo string([a:id, a:data, a:event])
if a:data == [''] if a:data == ['']
@@ -123,24 +132,27 @@ describe('channels', function()
endfunction endfunction
let g:x = stdioopen({'on_stdin': funcref('OnStdin'), 'on_print':'OnPrint'}) let g:x = stdioopen({'on_stdin': funcref('OnStdin'), 'on_print':'OnPrint'})
call chansend(x, "hello") call chansend(x, "hello")
]]) ]]
command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)") )
local id = eval("g:id") command(
"let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)"
)
local id = eval('g:id')
ok(id > 0) ok(id > 0)
eq({ "notification", "stdout", {id, { "hello" } } }, next_msg()) eq({ 'notification', 'stdout', { id, { 'hello' } } }, next_msg())
command("call chansend(id, 'howdy')") command("call chansend(id, 'howdy')")
eq({"notification", "stdout", {id, {"OnPrint:[1, ['howdy'], 'stdin']"}}}, next_msg()) eq({ 'notification', 'stdout', { id, { "OnPrint:[1, ['howdy'], 'stdin']" } } }, next_msg())
end) end)
local function expect_twoline(id, stream, line1, line2, nobr) local function expect_twoline(id, stream, line1, line2, nobr)
local msg = next_msg() local msg = next_msg()
local joined = nobr and {line1..line2} or {line1, line2} local joined = nobr and { line1 .. line2 } or { line1, line2 }
if not pcall(eq, {"notification", stream, {id, joined}}, msg) then if not pcall(eq, { 'notification', stream, { id, joined } }, msg) then
local sep = (not nobr) and "" or nil local sep = (not nobr) and '' or nil
eq({"notification", stream, {id, {line1, sep}}}, msg) eq({ 'notification', stream, { id, { line1, sep } } }, msg)
eq({"notification", stream, {id, {line2}}}, next_msg()) eq({ 'notification', stream, { id, { line2 } } }, next_msg())
end end
end end
@@ -153,50 +165,52 @@ describe('channels', function()
\ 'pty': v:true, \ 'pty': v:true,
\ } \ }
]]) ]])
meths.set_var("nvim_prog", nvim_prog) meths.set_var('nvim_prog', nvim_prog)
meths.set_var("code", [[ meths.set_var(
'code',
[[
function! OnEvent(id, data, event) dict function! OnEvent(id, data, event) dict
let text = string([a:id, a:data, a:event]) let text = string([a:id, a:data, a:event])
call chansend(g:x, text) call chansend(g:x, text)
endfunction endfunction
let g:x = stdioopen({'on_stdin':'OnEvent'}) let g:x = stdioopen({'on_stdin':'OnEvent'})
]]) ]]
command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)") )
local id = eval("g:id") command(
"let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)"
)
local id = eval('g:id')
ok(id > 0) ok(id > 0)
command("call chansend(id, 'TEXT\n')") command("call chansend(id, 'TEXT\n')")
expect_twoline(id, "stdout", "TEXT\r", "[1, ['TEXT', ''], 'stdin']") expect_twoline(id, 'stdout', 'TEXT\r', "[1, ['TEXT', ''], 'stdin']")
command("call chansend(id, 0z426c6f6273210a)") command('call chansend(id, 0z426c6f6273210a)')
expect_twoline(id, "stdout", "Blobs!\r", "[1, ['Blobs!', ''], 'stdin']") expect_twoline(id, 'stdout', 'Blobs!\r', "[1, ['Blobs!', ''], 'stdin']")
command("call chansend(id, 'neovan')") command("call chansend(id, 'neovan')")
eq({"notification", "stdout", {id, {"neovan"}}}, next_msg()) eq({ 'notification', 'stdout', { id, { 'neovan' } } }, next_msg())
command("call chansend(id, '\127\127im\n')") command("call chansend(id, '\127\127im\n')")
expect_twoline(id, "stdout", "\b \b\b \bim\r", "[1, ['neovim', ''], 'stdin']") expect_twoline(id, 'stdout', '\b \b\b \bim\r', "[1, ['neovim', ''], 'stdin']")
command("call chansend(id, 'incomplet\004')") command("call chansend(id, 'incomplet\004')")
local bsdlike = is_os('bsd') or is_os('mac') local bsdlike = is_os('bsd') or is_os('mac')
local extra = bsdlike and "^D\008\008" or "" local extra = bsdlike and '^D\008\008' or ''
expect_twoline(id, "stdout", expect_twoline(id, 'stdout', 'incomplet' .. extra, "[1, ['incomplet'], 'stdin']", true)
"incomplet"..extra, "[1, ['incomplet'], 'stdin']", true)
command("call chansend(id, '\004')") command("call chansend(id, '\004')")
if bsdlike then if bsdlike then
expect_twoline(id, "stdout", extra, "[1, [''], 'stdin']", true) expect_twoline(id, 'stdout', extra, "[1, [''], 'stdin']", true)
else else
eq({"notification", "stdout", {id, {"[1, [''], 'stdin']"}}}, next_msg()) eq({ 'notification', 'stdout', { id, { "[1, [''], 'stdin']" } } }, next_msg())
end end
-- channel is still open -- channel is still open
command("call chansend(id, 'hi again!\n')") command("call chansend(id, 'hi again!\n')")
eq({"notification", "stdout", {id, {"hi again!\r", ""}}}, next_msg()) eq({ 'notification', 'stdout', { id, { 'hi again!\r', '' } } }, next_msg())
end) end)
it('stdio channel can use rpc and stderr simultaneously', function() it('stdio channel can use rpc and stderr simultaneously', function()
skip(is_os('win')) skip(is_os('win'))
source([[ source([[
@@ -206,27 +220,33 @@ describe('channels', function()
\ 'rpc': v:true, \ 'rpc': v:true,
\ } \ }
]]) ]])
meths.set_var("nvim_prog", nvim_prog) meths.set_var('nvim_prog', nvim_prog)
meths.set_var("code", [[ meths.set_var(
'code',
[[
let id = stdioopen({'rpc':v:true}) let id = stdioopen({'rpc':v:true})
call rpcnotify(id,"nvim_call_function", "rpcnotify", [1, "message", "hi there!", id]) call rpcnotify(id,"nvim_call_function", "rpcnotify", [1, "message", "hi there!", id])
call chansend(v:stderr, "trouble!") call chansend(v:stderr, "trouble!")
]]) ]]
command("let id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)") )
eq({"notification", "message", {"hi there!", 1}}, next_msg()) command(
eq({"notification", "stderr", {3, {"trouble!"}}}, next_msg()) "let id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)"
)
eq({ 'notification', 'message', { 'hi there!', 1 } }, next_msg())
eq({ 'notification', 'stderr', { 3, { 'trouble!' } } }, next_msg())
eq(30, eval("rpcrequest(id, 'nvim_eval', '[chansend(v:stderr, \"math??\"), 5*6][1]')")) eq(30, eval("rpcrequest(id, 'nvim_eval', '[chansend(v:stderr, \"math??\"), 5*6][1]')"))
eq({"notification", "stderr", {3, {"math??"}}}, next_msg()) eq({ 'notification', 'stderr', { 3, { 'math??' } } }, next_msg())
local _, err = pcall(command,"call rpcrequest(id, 'nvim_command', 'call chanclose(v:stderr, \"stdin\")')") local _, err =
ok(string.find(err,"E906: invalid stream for channel") ~= nil) pcall(command, "call rpcrequest(id, 'nvim_command', 'call chanclose(v:stderr, \"stdin\")')")
ok(string.find(err, 'E906: invalid stream for channel') ~= nil)
eq(1, eval("rpcrequest(id, 'nvim_eval', 'chanclose(v:stderr, \"stderr\")')")) eq(1, eval("rpcrequest(id, 'nvim_eval', 'chanclose(v:stderr, \"stderr\")')"))
eq({"notification", "stderr", {3, {""}}}, next_msg()) eq({ 'notification', 'stderr', { 3, { '' } } }, next_msg())
command("call rpcnotify(id, 'nvim_command', 'quit')") command("call rpcnotify(id, 'nvim_command', 'quit')")
eq({"notification", "exit", {3, 0}}, next_msg()) eq({ 'notification', 'exit', { 3, 0 } }, next_msg())
end) end)
it('can use buffered output mode', function() it('can use buffered output mode', function()
@@ -239,27 +259,29 @@ describe('channels', function()
\ } \ }
]]) ]])
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)") command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
local id = eval("g:id") local id = eval('g:id')
command([[call chansend(id, "stuff\n10 PRINT \"NVIM\"\nxx")]]) command([[call chansend(id, "stuff\n10 PRINT \"NVIM\"\nxx")]])
sleep(10) sleep(10)
command([[call chansend(id, "xx\n20 GOTO 10\nzz\n")]]) command([[call chansend(id, "xx\n20 GOTO 10\nzz\n")]])
command("call chanclose(id, 'stdin')") command("call chanclose(id, 'stdin')")
eq({"notification", "stdout", {id, {'10 PRINT "NVIM"', eq({
'20 GOTO 10', ''}}}, next_msg()) 'notification',
eq({"notification", "exit", {id, 0}}, next_msg()) 'stdout',
{ id, { '10 PRINT "NVIM"', '20 GOTO 10', '' } },
}, next_msg())
eq({ 'notification', 'exit', { id, 0 } }, next_msg())
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)") command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
id = eval("g:id") id = eval('g:id')
command([[call chansend(id, "is no number\nnot at all")]]) command([[call chansend(id, "is no number\nnot at all")]])
command("call chanclose(id, 'stdin')") command("call chanclose(id, 'stdin')")
-- works correctly with no output -- works correctly with no output
eq({"notification", "stdout", {id, {''}}}, next_msg()) eq({ 'notification', 'stdout', { id, { '' } } }, next_msg())
eq({"notification", "exit", {id, 1}}, next_msg()) eq({ 'notification', 'exit', { id, 1 } }, next_msg())
end) end)
it('can use buffered output mode with no stream callback', function() it('can use buffered output mode with no stream callback', function()
@@ -274,31 +296,40 @@ describe('channels', function()
\ } \ }
]]) ]])
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)") command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
local id = eval("g:id") local id = eval('g:id')
command([[call chansend(id, "stuff\n10 PRINT \"NVIM\"\nxx")]]) command([[call chansend(id, "stuff\n10 PRINT \"NVIM\"\nxx")]])
sleep(10) sleep(10)
command([[call chansend(id, "xx\n20 GOTO 10\nzz\n")]]) command([[call chansend(id, "xx\n20 GOTO 10\nzz\n")]])
command("call chanclose(id, 'stdin')") command("call chanclose(id, 'stdin')")
eq({"notification", "exit", {id, 0, {'10 PRINT "NVIM"', eq({
'20 GOTO 10', ''}}}, next_msg()) 'notification',
'exit',
{ id, 0, { '10 PRINT "NVIM"', '20 GOTO 10', '' } },
}, next_msg())
-- if dict is reused the new value is not stored, -- if dict is reused the new value is not stored,
-- but nvim also does not crash -- but nvim also does not crash
command("let id = jobstart(['cat'], g:job_opts)") command("let id = jobstart(['cat'], g:job_opts)")
id = eval("g:id") id = eval('g:id')
command([[call chansend(id, "cat text\n")]]) command([[call chansend(id, "cat text\n")]])
sleep(10) sleep(10)
command("call chanclose(id, 'stdin')") command("call chanclose(id, 'stdin')")
-- old value was not overwritten -- old value was not overwritten
eq({"notification", "exit", {id, 0, {'10 PRINT "NVIM"', eq({
'20 GOTO 10', ''}}}, next_msg()) 'notification',
'exit',
{ id, 0, { '10 PRINT "NVIM"', '20 GOTO 10', '' } },
}, next_msg())
-- and an error was thrown. -- and an error was thrown.
eq("E5210: dict key 'stdout' already set for buffered stream in channel "..id, eval('v:errmsg')) eq(
"E5210: dict key 'stdout' already set for buffered stream in channel " .. id,
eval('v:errmsg')
)
-- reset dictionary -- reset dictionary
source([[ source([[
@@ -308,13 +339,13 @@ describe('channels', function()
\ } \ }
]]) ]])
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)") command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
id = eval("g:id") id = eval('g:id')
command([[call chansend(id, "is no number\nnot at all")]]) command([[call chansend(id, "is no number\nnot at all")]])
command("call chanclose(id, 'stdin')") command("call chanclose(id, 'stdin')")
-- works correctly with no output -- works correctly with no output
eq({"notification", "exit", {id, 1, {''}}}, next_msg()) eq({ 'notification', 'exit', { id, 1, { '' } } }, next_msg())
end) end)
end) end)
@@ -325,8 +356,10 @@ describe('loopback', function()
end) end)
it('does not crash when sending raw data', function() it('does not crash when sending raw data', function()
eq("Vim(call):Can't send raw data to rpc channel", eq(
pcall_err(command, "call chansend(chan, 'test')")) "Vim(call):Can't send raw data to rpc channel",
pcall_err(command, "call chansend(chan, 'test')")
)
assert_alive() assert_alive()
end) end)

View File

@@ -27,8 +27,8 @@ describe('v:exiting', function()
local function test_exiting(setup_fn) local function test_exiting(setup_fn)
local function on_setup() local function on_setup()
command('autocmd VimLeavePre * call rpcrequest('..cid..', "exit", "VimLeavePre")') command('autocmd VimLeavePre * call rpcrequest(' .. cid .. ', "exit", "VimLeavePre")')
command('autocmd VimLeave * call rpcrequest('..cid..', "exit", "VimLeave")') command('autocmd VimLeave * call rpcrequest(' .. cid .. ', "exit", "VimLeave")')
setup_fn() setup_fn()
end end
local requests_args = {} local requests_args = {}
@@ -39,7 +39,7 @@ describe('v:exiting', function()
return '' return ''
end end
run(on_request, nil, on_setup) run(on_request, nil, on_setup)
eq({{'VimLeavePre'}, {'VimLeave'}}, requests_args) eq({ { 'VimLeavePre' }, { 'VimLeave' } }, requests_args)
end end
it('is 0 on normal exit', function() it('is 0 on normal exit', function()
@@ -59,11 +59,16 @@ end)
describe(':cquit', function() describe(':cquit', function()
local function test_cq(cmdline, exit_code, redir_msg) local function test_cq(cmdline, exit_code, redir_msg)
if redir_msg then if redir_msg then
eq(redir_msg, pcall_err(function() return exec_capture(cmdline) end)) eq(
redir_msg,
pcall_err(function()
return exec_capture(cmdline)
end)
)
poke_eventloop() poke_eventloop()
assert_alive() assert_alive()
else else
funcs.system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', cmdline}) funcs.system({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', cmdline })
eq(exit_code, eval('v:shell_error')) eq(exit_code, eval('v:shell_error'))
end end
end end

View File

@@ -34,8 +34,7 @@ local spawn = helpers.spawn
local set_session = helpers.set_session local set_session = helpers.set_session
describe('fileio', function() describe('fileio', function()
before_each(function() before_each(function() end)
end)
after_each(function() after_each(function()
check_close() check_close()
os.remove('Xtest_startup_shada') os.remove('Xtest_startup_shada')
@@ -51,25 +50,25 @@ describe('fileio', function()
rmdir('Xtest_backupdir with spaces') rmdir('Xtest_backupdir with spaces')
end) end)
local args = { nvim_prog, '--clean', '--cmd', 'set nofsync directory=Xtest_startup_swapdir', } local args = { nvim_prog, '--clean', '--cmd', 'set nofsync directory=Xtest_startup_swapdir' }
--- Starts a new nvim session and returns an attached screen. --- Starts a new nvim session and returns an attached screen.
local function startup(extra_args) local function startup(extra_args)
extra_args = extra_args or {} extra_args = extra_args or {}
local argv = vim.tbl_flatten({args, '--embed', extra_args}) local argv = vim.tbl_flatten({ args, '--embed', extra_args })
local screen_nvim = spawn(argv) local screen_nvim = spawn(argv)
set_session(screen_nvim) set_session(screen_nvim)
local screen = Screen.new(70, 10) local screen = Screen.new(70, 10)
screen:attach() screen:attach()
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {foreground = Screen.colors.NvimDarkGrey4}; [1] = { foreground = Screen.colors.NvimDarkGrey4 },
[2] = {background = Screen.colors.NvimDarkGrey1, foreground = Screen.colors.NvimLightGrey3}; [2] = { background = Screen.colors.NvimDarkGrey1, foreground = Screen.colors.NvimLightGrey3 },
[3] = {foreground = Screen.colors.NvimLightCyan}; [3] = { foreground = Screen.colors.NvimLightCyan },
}) })
return screen return screen
end end
it("fsync() with 'nofsync' #8304", function() it("fsync() with 'nofsync' #8304", function()
clear({ args={ '--cmd', 'set nofsync directory=Xtest_startup_swapdir', } }) clear({ args = { '--cmd', 'set nofsync directory=Xtest_startup_swapdir' } })
-- These cases ALWAYS force fsync (regardless of 'fsync' option): -- These cases ALWAYS force fsync (regardless of 'fsync' option):
@@ -80,8 +79,8 @@ describe('fileio', function()
eq(0, request('nvim__stats').fsync) eq(0, request('nvim__stats').fsync)
command('set swapfile') command('set swapfile')
command('set updatetime=1') command('set updatetime=1')
feed('Azub<esc>h') -- File is 'modified'. feed('Azub<esc>h') -- File is 'modified'.
sleep(3) -- Allow 'updatetime' to expire. sleep(3) -- Allow 'updatetime' to expire.
retry(3, nil, function() retry(3, nil, function()
eq(1, request('nvim__stats').fsync) eq(1, request('nvim__stats').fsync)
end) end)
@@ -101,21 +100,26 @@ describe('fileio', function()
eq('foozubbaz', trim(read_file('Xtest_startup_file1'))) eq('foozubbaz', trim(read_file('Xtest_startup_file1')))
-- 4. Exit caused by deadly signal (+ 'swapfile'). -- 4. Exit caused by deadly signal (+ 'swapfile').
local j = funcs.jobstart(vim.tbl_flatten({args, '--embed'}), {rpc=true}) local j = funcs.jobstart(vim.tbl_flatten({ args, '--embed' }), { rpc = true })
funcs.rpcrequest(j, 'nvim_exec2', [[ funcs.rpcrequest(
j,
'nvim_exec2',
[[
set nofsync directory=Xtest_startup_swapdir set nofsync directory=Xtest_startup_swapdir
edit Xtest_startup_file2 edit Xtest_startup_file2
write write
put ='fsyncd text' put ='fsyncd text'
]], {}) ]],
{}
)
eq('Xtest_startup_swapdir', funcs.rpcrequest(j, 'nvim_eval', '&directory')) eq('Xtest_startup_swapdir', funcs.rpcrequest(j, 'nvim_eval', '&directory'))
funcs.jobstop(j) -- Send deadly signal. funcs.jobstop(j) -- Send deadly signal.
local screen = startup() local screen = startup()
feed(':recover Xtest_startup_file2<cr>') feed(':recover Xtest_startup_file2<cr>')
screen:expect({any = [[Using swap file "Xtest_startup_swapdir[/\]Xtest_startup_file2%.swp"]]}) screen:expect({ any = [[Using swap file "Xtest_startup_swapdir[/\]Xtest_startup_file2%.swp"]] })
feed('<cr>') feed('<cr>')
screen:expect({any = 'fsyncd text'}) screen:expect({ any = 'fsyncd text' })
-- 5. SIGPWR signal. -- 5. SIGPWR signal.
-- oldtest: Test_signal_PWR() -- oldtest: Test_signal_PWR()
@@ -123,8 +127,14 @@ describe('fileio', function()
it('backup #9709', function() it('backup #9709', function()
skip(is_ci('cirrus')) skip(is_ci('cirrus'))
clear({ args={ '-i', 'Xtest_startup_shada', clear({
'--cmd', 'set directory=Xtest_startup_swapdir' } }) args = {
'-i',
'Xtest_startup_shada',
'--cmd',
'set directory=Xtest_startup_swapdir',
},
})
command('write Xtest_startup_file1') command('write Xtest_startup_file1')
feed('ifoo<esc>') feed('ifoo<esc>')
@@ -137,8 +147,8 @@ describe('fileio', function()
local foobar_contents = trim(read_file('Xtest_startup_file1')) local foobar_contents = trim(read_file('Xtest_startup_file1'))
local bar_contents = trim(read_file('Xtest_startup_file1~')) local bar_contents = trim(read_file('Xtest_startup_file1~'))
eq('foobar', foobar_contents); eq('foobar', foobar_contents)
eq('foo', bar_contents); eq('foo', bar_contents)
end) end)
it('backup with full path #11214', function() it('backup with full path #11214', function()
@@ -154,13 +164,16 @@ describe('fileio', function()
command('write') command('write')
-- Backup filename = fullpath, separators replaced with "%". -- Backup filename = fullpath, separators replaced with "%".
local backup_file_name = string.gsub(currentdir()..'/Xtest_startup_file1', local backup_file_name = string.gsub(
is_os('win') and '[:/\\]' or '/', '%%') .. '~' currentdir() .. '/Xtest_startup_file1',
local foo_contents = trim(read_file('Xtest_backupdir/'..backup_file_name)) is_os('win') and '[:/\\]' or '/',
'%%'
) .. '~'
local foo_contents = trim(read_file('Xtest_backupdir/' .. backup_file_name))
local foobar_contents = trim(read_file('Xtest_startup_file1')) local foobar_contents = trim(read_file('Xtest_startup_file1'))
eq('foobar', foobar_contents); eq('foobar', foobar_contents)
eq('foo', foo_contents); eq('foo', foo_contents)
end) end)
it('backup with full path with spaces', function() it('backup with full path with spaces', function()
@@ -176,13 +189,16 @@ describe('fileio', function()
command('write') command('write')
-- Backup filename = fullpath, separators replaced with "%". -- Backup filename = fullpath, separators replaced with "%".
local backup_file_name = string.gsub(currentdir()..'/Xtest_startup_file1', local backup_file_name = string.gsub(
is_os('win') and '[:/\\]' or '/', '%%') .. '~' currentdir() .. '/Xtest_startup_file1',
local foo_contents = trim(read_file('Xtest_backupdir with spaces/'..backup_file_name)) is_os('win') and '[:/\\]' or '/',
'%%'
) .. '~'
local foo_contents = trim(read_file('Xtest_backupdir with spaces/' .. backup_file_name))
local foobar_contents = trim(read_file('Xtest_startup_file1')) local foobar_contents = trim(read_file('Xtest_startup_file1'))
eq('foobar', foobar_contents); eq('foobar', foobar_contents)
eq('foo', foo_contents); eq('foo', foo_contents)
end) end)
it('backup symlinked files #11349', function() it('backup symlinked files #11349', function()
@@ -202,11 +218,10 @@ describe('fileio', function()
command('write') command('write')
local backup_raw = read_file(backup_file_name) local backup_raw = read_file(backup_file_name)
neq(nil, backup_raw, "Expected backup file " .. backup_file_name .. "to exist but did not") neq(nil, backup_raw, 'Expected backup file ' .. backup_file_name .. 'to exist but did not')
eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents') eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents')
end) end)
it('backup symlinked files in first available backupdir #11349', function() it('backup symlinked files in first available backupdir #11349', function()
skip(is_ci('cirrus')) skip(is_ci('cirrus'))
clear() clear()
@@ -228,7 +243,7 @@ describe('fileio', function()
command('write') command('write')
local backup_raw = read_file(backup_file_name) local backup_raw = read_file(backup_file_name)
neq(nil, backup_raw, "Expected backup file " .. backup_file_name .. " to exist but did not") neq(nil, backup_raw, 'Expected backup file ' .. backup_file_name .. ' to exist but did not')
eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents') eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents')
end) end)
@@ -247,7 +262,7 @@ describe('fileio', function()
table.insert(text, '') table.insert(text, '')
eq(text, funcs.readfile(fname, 'b')) eq(text, funcs.readfile(fname, 'b'))
end) end)
it('read invalid u8 over INT_MAX doesn\'t segfault', function() it("read invalid u8 over INT_MAX doesn't segfault", function()
clear() clear()
command('call writefile(0zFFFFFFFF, "Xtest-u8-int-max")') command('call writefile(0zFFFFFFFF, "Xtest-u8-int-max")')
-- This should not segfault -- This should not segfault
@@ -257,18 +272,18 @@ describe('fileio', function()
it(':w! does not show "file has been changed" warning', function() it(':w! does not show "file has been changed" warning', function()
clear() clear()
write_file("Xtest-overwrite-forced", 'foobar') write_file('Xtest-overwrite-forced', 'foobar')
command('set nofixendofline') command('set nofixendofline')
local screen = Screen.new(40,4) local screen = Screen.new(40, 4)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1}, [1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
[3] = {bold = true, foreground = Screen.colors.SeaGreen4} [3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
}) })
screen:attach() screen:attach()
command("set shortmess-=F") command('set shortmess-=F')
command("e Xtest-overwrite-forced") command('e Xtest-overwrite-forced')
screen:expect([[ screen:expect([[
^foobar | ^foobar |
{1:~ }|*2 {1:~ }|*2
@@ -276,14 +291,14 @@ describe('fileio', function()
]]) ]])
-- Get current unix time. -- Get current unix time.
local cur_unix_time = os.time(os.date("!*t")) local cur_unix_time = os.time(os.date('!*t'))
local future_time = cur_unix_time + 999999 local future_time = cur_unix_time + 999999
-- Set the file's access/update time to be -- Set the file's access/update time to be
-- greater than the time at which it was created. -- greater than the time at which it was created.
local uv = require("luv") local uv = require('luv')
uv.fs_utime('Xtest-overwrite-forced', future_time, future_time) uv.fs_utime('Xtest-overwrite-forced', future_time, future_time)
-- use async feed_command because nvim basically hangs on the prompt -- use async feed_command because nvim basically hangs on the prompt
feed_command("w") feed_command('w')
screen:expect([[ screen:expect([[
{2:WARNING: The file has been changed since}| {2:WARNING: The file has been changed since}|
{2: reading it!!!} | {2: reading it!!!} |
@@ -291,15 +306,15 @@ describe('fileio', function()
^ | ^ |
]]) ]])
feed("n") feed('n')
feed("<cr>") feed('<cr>')
screen:expect([[ screen:expect([[
^foobar | ^foobar |
{1:~ }|*2 {1:~ }|*2
| |
]]) ]])
-- Use a screen test because the warning does not set v:errmsg. -- Use a screen test because the warning does not set v:errmsg.
command("w!") command('w!')
screen:expect([[ screen:expect([[
^foobar | ^foobar |
{1:~ }|*2 {1:~ }|*2
@@ -333,7 +348,7 @@ describe('tmpdir', function()
end end
it('failure modes', function() it('failure modes', function()
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } })
assert_nolog('tempdir is not a directory', testlog) assert_nolog('tempdir is not a directory', testlog)
assert_nolog('tempdir has invalid permissions', testlog) assert_nolog('tempdir has invalid permissions', testlog)
@@ -344,9 +359,9 @@ describe('tmpdir', function()
-- "…/nvim.<user>/" is not a directory: -- "…/nvim.<user>/" is not a directory:
expect_exit(command, ':qall!') expect_exit(command, ':qall!')
rmdir(tmproot) rmdir(tmproot)
write_file(tmproot, '') -- Not a directory, vim_mktempdir() should skip it. write_file(tmproot, '') -- Not a directory, vim_mktempdir() should skip it.
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
-- Assert that broken tmpdir root was handled. -- Assert that broken tmpdir root was handled.
assert_log('tempdir root not a directory', testlog, 100) assert_log('tempdir root not a directory', testlog, 100)
@@ -355,9 +370,9 @@ describe('tmpdir', function()
os.remove(testlog) os.remove(testlog)
os.remove(tmproot) os.remove(tmproot)
mkdir(tmproot) mkdir(tmproot)
funcs.setfperm(tmproot, 'rwxr--r--') -- Invalid permissions, vim_mktempdir() should skip it. funcs.setfperm(tmproot, 'rwxr--r--') -- Invalid permissions, vim_mktempdir() should skip it.
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
-- Assert that broken tmpdir root was handled. -- Assert that broken tmpdir root was handled.
assert_log('tempdir root has invalid permissions', testlog, 100) assert_log('tempdir root has invalid permissions', testlog, 100)
end) end)
@@ -365,14 +380,14 @@ describe('tmpdir', function()
it('too long', function() it('too long', function()
local bigname = ('%s/%s'):format(os_tmpdir, ('x'):rep(666)) local bigname = ('%s/%s'):format(os_tmpdir, ('x'):rep(666))
mkdir(bigname) mkdir(bigname)
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=bigname, } }) clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = bigname } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
local len = (funcs.tempname()):len() local len = (funcs.tempname()):len()
ok(len > 4 and len < 256, '4 < len < 256', tostring(len)) ok(len > 4 and len < 256, '4 < len < 256', tostring(len))
end) end)
it('disappeared #1432', function() it('disappeared #1432', function()
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } })
assert_nolog('tempdir disappeared', testlog) assert_nolog('tempdir disappeared', testlog)
local function rm_tmpdir() local function rm_tmpdir()
@@ -406,12 +421,13 @@ describe('tmpdir', function()
end) end)
it('$NVIM_APPNAME relative path', function() it('$NVIM_APPNAME relative path', function()
clear({ env={ clear({
NVIM_APPNAME='a/b', env = {
NVIM_LOG_FILE=testlog, NVIM_APPNAME = 'a/b',
TMPDIR=os_tmpdir, NVIM_LOG_FILE = testlog,
} }) TMPDIR = os_tmpdir,
},
})
matches([=[.*[/\\]a%%b%.[^/\\]+]=], funcs.tempname()) matches([=[.*[/\\]a%%b%.[^/\\]+]=], funcs.tempname())
end) end)
end) end)

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@ describe('log', function()
-- calls, that needs investigation. -- calls, that needs investigation.
clear() clear()
eq(0, request('nvim__stats').log_skip) eq(0, request('nvim__stats').log_skip)
clear{env={CDPATH='~doesnotexist'}} clear { env = { CDPATH = '~doesnotexist' } }
assert(request('nvim__stats').log_skip <= 13) assert(request('nvim__stats').log_skip <= 13)
end) end)
@@ -32,14 +32,16 @@ describe('log', function()
-- ERR 2022-05-29T12:30:03.800 T2 log_init:110: test log message -- ERR 2022-05-29T12:30:03.800 T2 log_init:110: test log message
-- ERR 2022-05-29T12:30:03.814 T2/child log_init:110: test log message -- ERR 2022-05-29T12:30:03.814 T2/child log_init:110: test log message
clear({env={ clear({
NVIM_LOG_FILE=testlog, env = {
-- TODO: remove this after nvim_log #7062 is merged. NVIM_LOG_FILE = testlog,
__NVIM_TEST_LOG='1' -- TODO: remove this after nvim_log #7062 is merged.
}}) __NVIM_TEST_LOG = '1',
},
})
local tid = _G._nvim_test_id local tid = _G._nvim_test_id
assert_log(tid..'%.%d+%.%d +server_init:%d+: test log message', testlog, 100) assert_log(tid .. '%.%d+%.%d +server_init:%d+: test log message', testlog, 100)
exec_lua([[ exec_lua([[
local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1', '+foochild', '+qa!' }, vim.empty_dict()) local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1', '+foochild', '+qa!' }, vim.empty_dict())

View File

@@ -33,27 +33,44 @@ describe('command-line option', function()
it('treats - as stdin', function() it('treats - as stdin', function()
eq(nil, luv.fs_stat(fname)) eq(nil, luv.fs_stat(fname))
funcs.system( funcs.system({
{nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', '--headless', nvim_prog_abs(),
'--cmd', 'set noswapfile shortmess+=IFW fileformats=unix', '-u',
'-s', '-', fname}, 'NONE',
{':call setline(1, "42")', ':wqall!', ''}) '-i',
'NONE',
'--headless',
'--cmd',
'set noswapfile shortmess+=IFW fileformats=unix',
'-s',
'-',
fname,
}, { ':call setline(1, "42")', ':wqall!', '' })
eq(0, eval('v:shell_error')) eq(0, eval('v:shell_error'))
local attrs = luv.fs_stat(fname) local attrs = luv.fs_stat(fname)
eq(#('42\n'), attrs.size) eq(#'42\n', attrs.size)
end) end)
it('does not expand $VAR', function() it('does not expand $VAR', function()
eq(nil, luv.fs_stat(fname)) eq(nil, luv.fs_stat(fname))
eq(true, not not dollar_fname:find('%$%w+')) eq(true, not not dollar_fname:find('%$%w+'))
write_file(dollar_fname, ':call setline(1, "100500")\n:wqall!\n') write_file(dollar_fname, ':call setline(1, "100500")\n:wqall!\n')
funcs.system( funcs.system({
{nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', '--headless', nvim_prog_abs(),
'--cmd', 'set noswapfile shortmess+=IFW fileformats=unix', '-u',
'-s', dollar_fname, fname}) 'NONE',
'-i',
'NONE',
'--headless',
'--cmd',
'set noswapfile shortmess+=IFW fileformats=unix',
'-s',
dollar_fname,
fname,
})
eq(0, eval('v:shell_error')) eq(0, eval('v:shell_error'))
local attrs = luv.fs_stat(fname) local attrs = luv.fs_stat(fname)
eq(#('100500\n'), attrs.size) eq(#'100500\n', attrs.size)
end) end)
it('does not crash after reading from stdin in non-headless mode', function() it('does not crash after reading from stdin in non-headless mode', function()
@@ -61,24 +78,33 @@ describe('command-line option', function()
local screen = Screen.new(40, 8) local screen = Screen.new(40, 8)
screen:attach() screen:attach()
local args = { local args = {
nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', nvim_prog_abs(),
'--cmd', '"set noswapfile shortmess+=IFW fileformats=unix notermguicolors"', '-u',
'-s', '-' 'NONE',
'-i',
'NONE',
'--cmd',
'"set noswapfile shortmess+=IFW fileformats=unix notermguicolors"',
'-s',
'-',
} }
-- Need to explicitly pipe to stdin so that the embedded Nvim instance doesn't try to read -- Need to explicitly pipe to stdin so that the embedded Nvim instance doesn't try to read
-- data from the terminal #18181 -- data from the terminal #18181
funcs.termopen(string.format([[echo "" | %s]], table.concat(args, " ")), { funcs.termopen(string.format([[echo "" | %s]], table.concat(args, ' ')), {
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) })
screen:expect([[ screen:expect(
[[
^ | ^ |
~ |*4 ~ |*4
{1:[No Name] 0,0-1 All}| {1:[No Name] 0,0-1 All}|
|*2 |*2
]], { ]],
[1] = {reverse = true}; {
}) [1] = { reverse = true },
}
)
feed('i:cq<CR>') feed('i:cq<CR>')
screen:expect([[ screen:expect([[
| |
@@ -101,12 +127,22 @@ describe('command-line option', function()
it('errors out when trying to use nonexistent file with -s', function() it('errors out when trying to use nonexistent file with -s', function()
eq( eq(
'Cannot open for reading: "'..nonexistent_fname..'": no such file or directory\n', 'Cannot open for reading: "' .. nonexistent_fname .. '": no such file or directory\n',
funcs.system( funcs.system({
{nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', '--headless', nvim_prog_abs(),
'--cmd', 'set noswapfile shortmess+=IFW fileformats=unix', '-u',
'--cmd', 'language C', 'NONE',
'-s', nonexistent_fname})) '-i',
'NONE',
'--headless',
'--cmd',
'set noswapfile shortmess+=IFW fileformats=unix',
'--cmd',
'language C',
'-s',
nonexistent_fname,
})
)
eq(2, eval('v:shell_error')) eq(2, eval('v:shell_error'))
end) end)
@@ -114,12 +150,25 @@ describe('command-line option', function()
write_file(fname, ':call setline(1, "1")\n:wqall!\n') write_file(fname, ':call setline(1, "1")\n:wqall!\n')
write_file(dollar_fname, ':call setline(1, "2")\n:wqall!\n') write_file(dollar_fname, ':call setline(1, "2")\n:wqall!\n')
eq( eq(
'Attempt to open script file again: "-s '..dollar_fname..'"\n', 'Attempt to open script file again: "-s ' .. dollar_fname .. '"\n',
funcs.system( funcs.system({
{nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', '--headless', nvim_prog_abs(),
'--cmd', 'set noswapfile shortmess+=IFW fileformats=unix', '-u',
'--cmd', 'language C', 'NONE',
'-s', fname, '-s', dollar_fname, fname_2})) '-i',
'NONE',
'--headless',
'--cmd',
'set noswapfile shortmess+=IFW fileformats=unix',
'--cmd',
'language C',
'-s',
fname,
'-s',
dollar_fname,
fname_2,
})
)
eq(2, eval('v:shell_error')) eq(2, eval('v:shell_error'))
eq(nil, luv.fs_stat(fname_2)) eq(nil, luv.fs_stat(fname_2))
end) end)
@@ -128,7 +177,7 @@ describe('command-line option', function()
it('nvim -v, :version', function() it('nvim -v, :version', function()
matches('Run ":verbose version"', funcs.execute(':version')) matches('Run ":verbose version"', funcs.execute(':version'))
matches('Compilation: .*Run :checkhealth', funcs.execute(':verbose version')) matches('Compilation: .*Run :checkhealth', funcs.execute(':verbose version'))
matches('Run "nvim %-V1 %-v"', funcs.system({nvim_prog_abs(), '-v'})) matches('Run "nvim %-V1 %-v"', funcs.system({ nvim_prog_abs(), '-v' }))
matches('Compilation: .*Run :checkhealth', funcs.system({nvim_prog_abs(), '-V1', '-v'})) matches('Compilation: .*Run :checkhealth', funcs.system({ nvim_prog_abs(), '-V1', '-v' }))
end) end)
end) end)

View File

@@ -13,7 +13,7 @@ local write_file = helpers.write_file
local function join_path(...) local function join_path(...)
local pathsep = (is_os('win') and '\\' or '/') local pathsep = (is_os('win') and '\\' or '/')
return table.concat({...}, pathsep) return table.concat({ ... }, pathsep)
end end
describe('path collapse', function() describe('path collapse', function()
@@ -23,40 +23,40 @@ describe('path collapse', function()
before_each(function() before_each(function()
targetdir = join_path('test', 'functional', 'fixtures') targetdir = join_path('test', 'functional', 'fixtures')
clear() clear()
command('edit '..join_path(targetdir, 'tty-test.c')) command('edit ' .. join_path(targetdir, 'tty-test.c'))
expected_path = eval('expand("%:p")') expected_path = eval('expand("%:p")')
end) end)
it('with /./ segment #7117', function() it('with /./ segment #7117', function()
command('edit '..join_path(targetdir, '.', 'tty-test.c')) command('edit ' .. join_path(targetdir, '.', 'tty-test.c'))
eq(expected_path, eval('expand("%:p")')) eq(expected_path, eval('expand("%:p")'))
end) end)
it('with ./ prefix #7117', function() it('with ./ prefix #7117', function()
command('edit '..join_path('.', targetdir, 'tty-test.c')) command('edit ' .. join_path('.', targetdir, 'tty-test.c'))
eq(expected_path, eval('expand("%:p")')) eq(expected_path, eval('expand("%:p")'))
end) end)
it('with ./ prefix, after directory change #7117', function() it('with ./ prefix, after directory change #7117', function()
command('edit '..join_path('.', targetdir, 'tty-test.c')) command('edit ' .. join_path('.', targetdir, 'tty-test.c'))
command('cd test') command('cd test')
eq(expected_path, eval('expand("%:p")')) eq(expected_path, eval('expand("%:p")'))
end) end)
it('with /../ segment #7117', function() it('with /../ segment #7117', function()
command('edit '..join_path(targetdir, '..', 'fixtures', 'tty-test.c')) command('edit ' .. join_path(targetdir, '..', 'fixtures', 'tty-test.c'))
eq(expected_path, eval('expand("%:p")')) eq(expected_path, eval('expand("%:p")'))
end) end)
it('with ../ and different starting directory #7117', function() it('with ../ and different starting directory #7117', function()
command('cd test') command('cd test')
command('edit '..join_path('..', targetdir, 'tty-test.c')) command('edit ' .. join_path('..', targetdir, 'tty-test.c'))
eq(expected_path, eval('expand("%:p")')) eq(expected_path, eval('expand("%:p")'))
end) end)
it('with ./../ and different starting directory #7117', function() it('with ./../ and different starting directory #7117', function()
command('cd test') command('cd test')
command('edit '..join_path('.', '..', targetdir, 'tty-test.c')) command('edit ' .. join_path('.', '..', targetdir, 'tty-test.c'))
eq(expected_path, eval('expand("%:p")')) eq(expected_path, eval('expand("%:p")'))
end) end)
end) end)
@@ -67,16 +67,16 @@ describe('expand wildcard', function()
it('with special characters #24421', function() it('with special characters #24421', function()
local folders = is_os('win') and { local folders = is_os('win') and {
'{folder}', '{folder}',
'folder$name' 'folder$name',
} or { } or {
'folder-name', 'folder-name',
'folder#name' 'folder#name',
} }
for _, folder in ipairs(folders) do for _, folder in ipairs(folders) do
mkdir(folder) mkdir(folder)
local file = join_path(folder, 'file.txt') local file = join_path(folder, 'file.txt')
write_file(file, '') write_file(file, '')
eq(file, eval('expand("'..folder..'/*")')) eq(file, eval('expand("' .. folder .. '/*")'))
rmdir(folder) rmdir(folder)
end end
end) end)
@@ -131,14 +131,30 @@ describe('file search', function()
test_cfile([[c:foo]], [[c]]) test_cfile([[c:foo]], [[c]])
-- Examples from: https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#example-ways-to-refer-to-the-same-file -- Examples from: https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#example-ways-to-refer-to-the-same-file
test_cfile([[c:\temp\test-file.txt]], [[c:]], [[c:\temp\test-file.txt]]) test_cfile([[c:\temp\test-file.txt]], [[c:]], [[c:\temp\test-file.txt]])
test_cfile([[\\127.0.0.1\c$\temp\test-file.txt]], [[127.0.0.1]], [[\\127.0.0.1\c$\temp\test-file.txt]]) test_cfile(
test_cfile([[\\LOCALHOST\c$\temp\test-file.txt]], [[LOCALHOST]], [[\\LOCALHOST\c$\temp\test-file.txt]]) [[\\127.0.0.1\c$\temp\test-file.txt]],
[[127.0.0.1]],
[[\\127.0.0.1\c$\temp\test-file.txt]]
)
test_cfile(
[[\\LOCALHOST\c$\temp\test-file.txt]],
[[LOCALHOST]],
[[\\LOCALHOST\c$\temp\test-file.txt]]
)
-- not supported yet -- not supported yet
test_cfile([[\\.\c:\temp\test-file.txt]], [[.]], [[\\.\c]]) test_cfile([[\\.\c:\temp\test-file.txt]], [[.]], [[\\.\c]])
-- not supported yet -- not supported yet
test_cfile([[\\?\c:\temp\test-file.txt]], [[c:]], [[\\]]) test_cfile([[\\?\c:\temp\test-file.txt]], [[c:]], [[\\]])
test_cfile([[\\.\UNC\LOCALHOST\c$\temp\test-file.txt]], [[.]], [[\\.\UNC\LOCALHOST\c$\temp\test-file.txt]]) test_cfile(
test_cfile([[\\127.0.0.1\c$\temp\test-file.txt]], [[127.0.0.1]], [[\\127.0.0.1\c$\temp\test-file.txt]]) [[\\.\UNC\LOCALHOST\c$\temp\test-file.txt]],
[[.]],
[[\\.\UNC\LOCALHOST\c$\temp\test-file.txt]]
)
test_cfile(
[[\\127.0.0.1\c$\temp\test-file.txt]],
[[127.0.0.1]],
[[\\127.0.0.1\c$\temp\test-file.txt]]
)
end) end)
---@param funcname 'finddir' | 'findfile' ---@param funcname 'finddir' | 'findfile'

View File

@@ -51,7 +51,10 @@ describe('Remote', function()
local client_starter = spawn(new_argv(), false, nil, true) local client_starter = spawn(new_argv(), false, nil, true)
set_session(client_starter) set_session(client_starter)
-- Call jobstart() and jobwait() in the same RPC request to reduce flakiness. -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness.
eq({ 0 }, exec_lua([[return vim.fn.jobwait({ vim.fn.jobstart({...}, { eq(
{ 0 },
exec_lua(
[[return vim.fn.jobwait({ vim.fn.jobstart({...}, {
stdout_buffered = true, stdout_buffered = true,
stderr_buffered = true, stderr_buffered = true,
on_stdout = function(_, data, _) on_stdout = function(_, data, _)
@@ -60,7 +63,15 @@ describe('Remote', function()
on_stderr = function(_, data, _) on_stderr = function(_, data, _)
_G.Remote_stderr = table.concat(data, '\n') _G.Remote_stderr = table.concat(data, '\n')
end, end,
}) })]], nvim_prog, '--clean', '--headless', '--server', addr, ...)) }) })]],
nvim_prog,
'--clean',
'--headless',
'--server',
addr,
...
)
)
local res = exec_lua([[return { _G.Remote_stdout, _G.Remote_stderr }]]) local res = exec_lua([[return { _G.Remote_stdout, _G.Remote_stderr }]])
client_starter:close() client_starter:close()
set_session(server) set_session(server)
@@ -95,7 +106,7 @@ describe('Remote', function()
end) end)
it('send keys', function() it('send keys', function()
eq({ '', '' }, run_remote('--remote-send', ':edit '..fname..'<CR><C-W>v')) eq({ '', '' }, run_remote('--remote-send', ':edit ' .. fname .. '<CR><C-W>v'))
expect(contents) expect(contents)
eq(2, #funcs.getwininfo()) eq(2, #funcs.getwininfo())
-- Only a single buffer as we're using edit and not drop like --remote does -- Only a single buffer as we're using edit and not drop like --remote does

View File

@@ -25,6 +25,7 @@ describe('spellfile', function()
local spellheader = 'VIMspell\050' local spellheader = 'VIMspell\050'
it('errors out when prefcond section is truncated', function() it('errors out when prefcond section is truncated', function()
meths.set_option_value('runtimepath', testdir, {}) meths.set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl', write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_PREFCOND) -- ┌ Section identifier (#SN_PREFCOND)
-- │ ┌ Section flags (#SNF_REQUIRED or zero) -- │ ┌ Section flags (#SNF_REQUIRED or zero)
@@ -35,11 +36,11 @@ describe('spellfile', function()
-- │ │ ┌ Condition regex (missing!) -- │ │ ┌ Condition regex (missing!)
.. '\000\001\001') .. '\000\001\001')
meths.set_option_value('spelllang', 'en', {}) meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E758: Truncated spell file', eq('Vim(set):E758: Truncated spell file', exc_exec('set spell'))
exc_exec('set spell'))
end) end)
it('errors out when prefcond regexp contains NUL byte', function() it('errors out when prefcond regexp contains NUL byte', function()
meths.set_option_value('runtimepath', testdir, {}) meths.set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl', write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_PREFCOND) -- ┌ Section identifier (#SN_PREFCOND)
-- │ ┌ Section flags (#SNF_REQUIRED or zero) -- │ ┌ Section flags (#SNF_REQUIRED or zero)
@@ -55,11 +56,11 @@ describe('spellfile', function()
-- │ │ ┌ PREFIXTREE tree length -- │ │ ┌ PREFIXTREE tree length
.. '\000\000\000\000\000\000\000\000\000\000\000\000') .. '\000\000\000\000\000\000\000\000\000\000\000\000')
meths.set_option_value('spelllang', 'en', {}) meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E759: Format error in spell file', eq('Vim(set):E759: Format error in spell file', exc_exec('set spell'))
exc_exec('set spell'))
end) end)
it('errors out when region contains NUL byte', function() it('errors out when region contains NUL byte', function()
meths.set_option_value('runtimepath', testdir, {}) meths.set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl', write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_REGION) -- ┌ Section identifier (#SN_REGION)
-- │ ┌ Section flags (#SNF_REQUIRED or zero) -- │ ┌ Section flags (#SNF_REQUIRED or zero)
@@ -72,11 +73,11 @@ describe('spellfile', function()
-- │ │ ┌ PREFIXTREE tree length -- │ │ ┌ PREFIXTREE tree length
.. '\000\000\000\000\000\000\000\000\000\000\000\000') .. '\000\000\000\000\000\000\000\000\000\000\000\000')
meths.set_option_value('spelllang', 'en', {}) meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E759: Format error in spell file', eq('Vim(set):E759: Format error in spell file', exc_exec('set spell'))
exc_exec('set spell'))
end) end)
it('errors out when SAL section contains NUL byte', function() it('errors out when SAL section contains NUL byte', function()
meths.set_option_value('runtimepath', testdir, {}) meths.set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl', write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_SAL) -- ┌ Section identifier (#SN_SAL)
-- │ ┌ Section flags (#SNF_REQUIRED or zero) -- │ ┌ Section flags (#SNF_REQUIRED or zero)
@@ -96,15 +97,12 @@ describe('spellfile', function()
-- │ │ ┌ PREFIXTREE tree length -- │ │ ┌ PREFIXTREE tree length
.. '\000\000\000\000\000\000\000\000\000\000\000\000') .. '\000\000\000\000\000\000\000\000\000\000\000\000')
meths.set_option_value('spelllang', 'en', {}) meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E759: Format error in spell file', eq('Vim(set):E759: Format error in spell file', exc_exec('set spell'))
exc_exec('set spell'))
end) end)
it('errors out when spell header contains NUL bytes', function() it('errors out when spell header contains NUL bytes', function()
meths.set_option_value('runtimepath', testdir, {}) meths.set_option_value('runtimepath', testdir, {})
write_file(testdir .. '/spell/en.ascii.spl', write_file(testdir .. '/spell/en.ascii.spl', spellheader:sub(1, -3) .. '\000\000')
spellheader:sub(1, -3) .. '\000\000')
meths.set_option_value('spelllang', 'en', {}) meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E757: This does not look like a spell file', eq('Vim(set):E757: This does not look like a spell file', exc_exec('set spell'))
exc_exec('set spell'))
end) end)
end) end)

File diff suppressed because it is too large Load Diff

View File

@@ -30,13 +30,15 @@ describe('K', function()
set keywordprg=echo\ fnord>>]]) set keywordprg=echo\ fnord>>]])
-- K on the text "K_spec_out" resolves to `!echo fnord >> K_spec_out`. -- K on the text "K_spec_out" resolves to `!echo fnord >> K_spec_out`.
feed('i'..test_file..'<ESC>K') feed('i' .. test_file .. '<ESC>K')
retry(nil, nil, function() eq(1, eval('filereadable("'..test_file..'")')) end) retry(nil, nil, function()
eq({'fnord'}, eval("readfile('"..test_file.."')")) eq(1, eval('filereadable("' .. test_file .. '")'))
end)
eq({ 'fnord' }, eval("readfile('" .. test_file .. "')"))
-- Confirm that Neovim is still in terminal mode after K is pressed (#16692). -- Confirm that Neovim is still in terminal mode after K is pressed (#16692).
helpers.sleep(500) helpers.sleep(500)
eq('t', eval('mode()')) eq('t', eval('mode()'))
feed('<space>') -- Any key, not just <space>, can be used here to escape. feed('<space>') -- Any key, not just <space>, can be used here to escape.
eq('n', eval('mode()')) eq('n', eval('mode()'))
end) end)
@@ -60,9 +62,8 @@ describe('K', function()
it('empty string falls back to :help #19298', function() it('empty string falls back to :help #19298', function()
meths.set_option_value('keywordprg', '', {}) meths.set_option_value('keywordprg', '', {})
meths.buf_set_lines(0, 0, -1, true, {'doesnotexist'}) meths.buf_set_lines(0, 0, -1, true, { 'doesnotexist' })
feed('K') feed('K')
eq('E149: Sorry, no help for doesnotexist', meths.get_vvar('errmsg')) eq('E149: Sorry, no help for doesnotexist', meths.get_vvar('errmsg'))
end) end)
end) end)

View File

@@ -18,17 +18,17 @@ describe('completion', function()
screen = Screen.new(60, 8) screen = Screen.new(60, 8)
screen:attach() screen:attach()
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[0] = {bold=true, foreground=Screen.colors.Blue}, [0] = { bold = true, foreground = Screen.colors.Blue },
[1] = {background = Screen.colors.LightMagenta}, [1] = { background = Screen.colors.LightMagenta },
[2] = {background = Screen.colors.Grey}, [2] = { background = Screen.colors.Grey },
[3] = {bold = true}, [3] = { bold = true },
[4] = {bold = true, foreground = Screen.colors.SeaGreen}, [4] = { bold = true, foreground = Screen.colors.SeaGreen },
[5] = {foreground = Screen.colors.Red}, [5] = { foreground = Screen.colors.Red },
[6] = {background = Screen.colors.Black}, [6] = { background = Screen.colors.Black },
[7] = {foreground = Screen.colors.White, background = Screen.colors.Red}, [7] = { foreground = Screen.colors.White, background = Screen.colors.Red },
[8] = {reverse = true}, [8] = { reverse = true },
[9] = {bold = true, reverse = true}, [9] = { bold = true, reverse = true },
[10] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow}, [10] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow },
}) })
end) end)
@@ -57,9 +57,10 @@ describe('completion', function()
it('returns expected dict in normal completion', function() it('returns expected dict in normal completion', function()
feed('ifoo<ESC>o<C-x><C-n>') feed('ifoo<ESC>o<C-x><C-n>')
eq('foo', eval('getline(2)')) eq('foo', eval('getline(2)'))
eq({word = 'foo', abbr = '', menu = '', eq(
info = '', kind = '', user_data = ''}, { word = 'foo', abbr = '', menu = '', info = '', kind = '', user_data = '' },
eval('v:completed_item')) eval('v:completed_item')
)
end) end)
it('is readonly', function() it('is readonly', function()
screen:try_resize(80, 8) screen:try_resize(80, 8)
@@ -107,9 +108,14 @@ describe('completion', function()
{0:~ }|*4 {0:~ }|*4
{3:-- Omni completion (^O^N^P) }{4:match 1 of 2} | {3:-- Omni completion (^O^N^P) }{4:match 1 of 2} |
]]) ]])
eq({word = 'foo', abbr = 'bar', menu = 'baz', eq({
info = 'foobar', kind = 'foobaz', user_data = ''}, word = 'foo',
eval('v:completed_item')) abbr = 'bar',
menu = 'baz',
info = 'foobar',
kind = 'foobaz',
user_data = '',
}, eval('v:completed_item'))
end) end)
end) end)
@@ -286,8 +292,8 @@ describe('completion', function()
end) end)
local tests = { local tests = {
['<up>, <down>, <cr>'] = {'<down><cr>', '<up><cr>'}, ['<up>, <down>, <cr>'] = { '<down><cr>', '<up><cr>' },
['<c-n>, <c-p>, <c-y>'] = {'<c-n><c-y>', '<c-p><c-y>'}, ['<c-n>, <c-p>, <c-y>'] = { '<c-n><c-y>', '<c-p><c-y>' },
} }
for name, seq in pairs(tests) do for name, seq in pairs(tests) do
@@ -303,13 +309,13 @@ describe('completion', function()
feed('A<right><esc>A<right><esc>') feed('A<right><esc>A<right><esc>')
local expected = { local expected = {
{'foo', 'bar', 'foo'}, { 'foo', 'bar', 'foo' },
{'foo', 'bar', 'ccc'}, { 'foo', 'bar', 'ccc' },
{'foo', 'bar'}, { 'foo', 'bar' },
{'foo', 'bbb'}, { 'foo', 'bbb' },
{'foo'}, { 'foo' },
{'aaa'}, { 'aaa' },
{''}, { '' },
} }
for i = 1, #expected do for i = 1, #expected do
@@ -329,7 +335,7 @@ describe('completion', function()
end end
end) end)
describe("refresh:always", function() describe('refresh:always', function()
before_each(function() before_each(function()
source([[ source([[
function! TestCompletion(findstart, base) abort function! TestCompletion(findstart, base) abort
@@ -354,9 +360,9 @@ describe('completion', function()
set completeopt=menuone,noselect set completeopt=menuone,noselect
set completefunc=TestCompletion set completefunc=TestCompletion
]]) ]])
end ) end)
it('completes on each input char', function () it('completes on each input char', function()
feed('i<C-x><C-u>') feed('i<C-x><C-u>')
screen:expect([[ screen:expect([[
^ | ^ |
@@ -402,7 +408,7 @@ describe('completion', function()
expect('August') expect('August')
end) end)
it("repeats correctly after backspace #2674", function () it('repeats correctly after backspace #2674', function()
feed('o<C-x><C-u>Ja') feed('o<C-x><C-u>Ja')
screen:expect([[ screen:expect([[
| |
@@ -471,10 +477,10 @@ describe('completion', function()
return '' return ''
endfunction endfunction
]]) ]])
feed_command("set completeopt=menuone,noselect") feed_command('set completeopt=menuone,noselect')
end) end)
it("works", function() it('works', function()
feed('i<C-r>=TestComplete()<CR>') feed('i<C-r>=TestComplete()<CR>')
screen:expect([[ screen:expect([[
^ | ^ |
@@ -630,7 +636,7 @@ describe('completion', function()
end) end)
end) end)
it("does not indent until an item is selected #8345", function () it('does not indent until an item is selected #8345', function()
-- Indents on "ind", unindents on "unind". -- Indents on "ind", unindents on "unind".
source([[ source([[
function! TestIndent() function! TestIndent()
@@ -649,14 +655,14 @@ describe('completion', function()
]]) ]])
-- Give some words to complete. -- Give some words to complete.
feed("iinc uninc indent unindent<CR>") feed('iinc uninc indent unindent<CR>')
-- Does not indent when "ind" is typed. -- Does not indent when "ind" is typed.
feed("in<C-X><C-N>") feed('in<C-X><C-N>')
-- Completion list is generated incorrectly if we send everything at once -- Completion list is generated incorrectly if we send everything at once
-- via nvim_input(). So poke_eventloop() before sending <BS>. #8480 -- via nvim_input(). So poke_eventloop() before sending <BS>. #8480
poke_eventloop() poke_eventloop()
feed("<BS>d") feed('<BS>d')
screen:expect([[ screen:expect([[
inc uninc indent unindent | inc uninc indent unindent |
@@ -667,7 +673,7 @@ describe('completion', function()
]]) ]])
-- Indents when the item is selected -- Indents when the item is selected
feed("<C-Y>") feed('<C-Y>')
screen:expect([[ screen:expect([[
inc uninc indent unindent | inc uninc indent unindent |
indent^ | indent^ |
@@ -675,7 +681,7 @@ describe('completion', function()
{3:-- INSERT --} | {3:-- INSERT --} |
]]) ]])
-- Indents when completion is exited using ESC. -- Indents when completion is exited using ESC.
feed("<CR>in<C-N><BS>d<Esc>") feed('<CR>in<C-N><BS>d<Esc>')
screen:expect([[ screen:expect([[
inc uninc indent unindent | inc uninc indent unindent |
indent | indent |
@@ -684,9 +690,9 @@ describe('completion', function()
| |
]]) ]])
-- Works for unindenting too. -- Works for unindenting too.
feed("ounin<C-X><C-N>") feed('ounin<C-X><C-N>')
helpers.poke_eventloop() helpers.poke_eventloop()
feed("<BS>d") feed('<BS>d')
screen:expect([[ screen:expect([[
inc uninc indent unindent | inc uninc indent unindent |
indent | indent |
@@ -697,7 +703,7 @@ describe('completion', function()
{3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} |
]]) ]])
-- Works when going back and forth. -- Works when going back and forth.
feed("<BS>c") feed('<BS>c')
screen:expect([[ screen:expect([[
inc uninc indent unindent | inc uninc indent unindent |
indent | indent |
@@ -707,7 +713,7 @@ describe('completion', function()
{0:~ }|*2 {0:~ }|*2
{3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} |
]]) ]])
feed("<BS>d") feed('<BS>d')
screen:expect([[ screen:expect([[
inc uninc indent unindent | inc uninc indent unindent |
indent | indent |
@@ -717,7 +723,7 @@ describe('completion', function()
{0:~ }|*2 {0:~ }|*2
{3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} |
]]) ]])
feed("<C-N><C-N><C-Y><Esc>") feed('<C-N><C-N><C-Y><Esc>')
screen:expect([[ screen:expect([[
inc uninc indent unindent | inc uninc indent unindent |
indent | indent |
@@ -728,8 +734,8 @@ describe('completion', function()
]]) ]])
end) end)
it('disables folding during completion', function () it('disables folding during completion', function()
feed_command("set foldmethod=indent") feed_command('set foldmethod=indent')
feed('i<Tab>foo<CR><Tab>bar<Esc>gg') feed('i<Tab>foo<CR><Tab>bar<Esc>gg')
screen:expect([[ screen:expect([[
^foo | ^foo |
@@ -747,8 +753,8 @@ describe('completion', function()
eq(-1, eval('foldclosed(1)')) eq(-1, eval('foldclosed(1)'))
end) end)
it('popupmenu is not interrupted by events', function () it('popupmenu is not interrupted by events', function()
feed_command("set complete=.") feed_command('set complete=.')
feed('ifoobar fooegg<cr>f<c-p>') feed('ifoobar fooegg<cr>f<c-p>')
screen:expect([[ screen:expect([[
@@ -762,14 +768,17 @@ describe('completion', function()
assert_alive() assert_alive()
-- popupmenu still visible -- popupmenu still visible
screen:expect{grid=[[ screen:expect {
grid = [[
foobar fooegg | foobar fooegg |
fooegg^ | fooegg^ |
{1:foobar }{0: }| {1:foobar }{0: }|
{2:fooegg }{0: }| {2:fooegg }{0: }|
{0:~ }|*3 {0:~ }|*3
{3:-- Keyword completion (^N^P) }{4:match 1 of 2} | {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
]], unchanged=true} ]],
unchanged = true,
}
feed('<c-p>') feed('<c-p>')
-- Didn't restart completion: old matches still used -- Didn't restart completion: old matches still used
@@ -787,47 +796,52 @@ describe('completion', function()
it('expands when there is only one match', function() it('expands when there is only one match', function()
feed(':lua CURRENT_TESTING_VAR = 1<CR>') feed(':lua CURRENT_TESTING_VAR = 1<CR>')
feed(':lua CURRENT_TESTING_<TAB>') feed(':lua CURRENT_TESTING_<TAB>')
screen:expect{grid=[[ screen:expect {
grid = [[
| |
{0:~ }|*6 {0:~ }|*6
:lua CURRENT_TESTING_VAR^ | :lua CURRENT_TESTING_VAR^ |
]]} ]],
}
end) end)
it('expands when there is only one match', function() it('expands when there is only one match', function()
feed(':lua CURRENT_TESTING_FOO = 1<CR>') feed(':lua CURRENT_TESTING_FOO = 1<CR>')
feed(':lua CURRENT_TESTING_BAR = 1<CR>') feed(':lua CURRENT_TESTING_BAR = 1<CR>')
feed(':lua CURRENT_TESTING_<TAB>') feed(':lua CURRENT_TESTING_<TAB>')
screen:expect{ grid = [[ screen:expect {
grid = [[
| |
{0:~ }|*5 {0:~ }|*5
{10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }| {10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }|
:lua CURRENT_TESTING_BAR^ | :lua CURRENT_TESTING_BAR^ |
]], unchanged = true } ]],
unchanged = true,
}
end) end)
it('provides completion from `getcompletion()`', function() it('provides completion from `getcompletion()`', function()
eq({'vim'}, funcs.getcompletion('vi', 'lua')) eq({ 'vim' }, funcs.getcompletion('vi', 'lua'))
eq({'api'}, funcs.getcompletion('vim.ap', 'lua')) eq({ 'api' }, funcs.getcompletion('vim.ap', 'lua'))
eq({'tbl_filter'}, funcs.getcompletion('vim.tbl_fil', 'lua')) eq({ 'tbl_filter' }, funcs.getcompletion('vim.tbl_fil', 'lua'))
eq({'vim'}, funcs.getcompletion('print(vi', 'lua')) eq({ 'vim' }, funcs.getcompletion('print(vi', 'lua'))
-- fuzzy completion is not supported, so the result should be the same -- fuzzy completion is not supported, so the result should be the same
command('set wildoptions+=fuzzy') command('set wildoptions+=fuzzy')
eq({'vim'}, funcs.getcompletion('vi', 'lua')) eq({ 'vim' }, funcs.getcompletion('vi', 'lua'))
end) end)
end) end)
it('cmdline completion supports various string options', function() it('cmdline completion supports various string options', function()
eq('auto', funcs.getcompletion('set foldcolumn=', 'cmdline')[2]) eq('auto', funcs.getcompletion('set foldcolumn=', 'cmdline')[2])
eq({'nosplit', 'split'}, funcs.getcompletion('set inccommand=', 'cmdline')) eq({ 'nosplit', 'split' }, funcs.getcompletion('set inccommand=', 'cmdline'))
eq({'ver:3,hor:6', 'hor:', 'ver:'}, funcs.getcompletion('set mousescroll=', 'cmdline')) eq({ 'ver:3,hor:6', 'hor:', 'ver:' }, funcs.getcompletion('set mousescroll=', 'cmdline'))
eq('BS', funcs.getcompletion('set termpastefilter=', 'cmdline')[2]) eq('BS', funcs.getcompletion('set termpastefilter=', 'cmdline')[2])
eq('SpecialKey', funcs.getcompletion('set winhighlight=', 'cmdline')[1]) eq('SpecialKey', funcs.getcompletion('set winhighlight=', 'cmdline')[1])
eq('SpecialKey', funcs.getcompletion('set winhighlight=NonText:', 'cmdline')[1]) eq('SpecialKey', funcs.getcompletion('set winhighlight=NonText:', 'cmdline')[1])
end) end)
describe('from the commandline window', function() describe('from the commandline window', function()
it('is cleared after CTRL-C', function () it('is cleared after CTRL-C', function()
feed('q:') feed('q:')
feed('ifoo faa fee f') feed('ifoo faa fee f')
screen:expect([[ screen:expect([[
@@ -837,7 +851,7 @@ describe('completion', function()
{0:~ }|*3 {0:~ }|*3
{9:[Command Line] }| {9:[Command Line] }|
{3:-- INSERT --} | {3:-- INSERT --} |
]] ) ]])
feed('<c-x><c-n>') feed('<c-x><c-n>')
screen:expect([[ screen:expect([[
| |
@@ -870,16 +884,18 @@ describe('completion', function()
endfunction endfunction
]]) ]])
meths.set_option_value('completeopt', 'menuone,noselect', {}) meths.set_option_value('completeopt', 'menuone,noselect', {})
meths.set_var('_complist', {{ meths.set_var('_complist', {
word=0, {
abbr=1, word = 0,
menu=2, abbr = 1,
kind=3, menu = 2,
info=4, kind = 3,
icase=5, info = 4,
dup=6, icase = 5,
empty=7, dup = 6,
}}) empty = 7,
},
})
end) end)
it('shows correct variant as word', function() it('shows correct variant as word', function()
@@ -897,7 +913,8 @@ describe('completion', function()
feed_command('set ignorecase infercase') feed_command('set ignorecase infercase')
feed_command('edit runtime/doc/backers.txt') feed_command('edit runtime/doc/backers.txt')
feed('oX<C-X><C-N>') feed('oX<C-X><C-N>')
screen:expect{grid=[[ screen:expect {
grid = [[
*backers.txt* Nvim | *backers.txt* Nvim |
Xnull^ | Xnull^ |
{2:Xnull }{6: } | {2:Xnull }{6: } |
@@ -906,11 +923,12 @@ describe('completion', function()
{1:Xpayn }{2: } | {1:Xpayn }{2: } |
{1:Xinity }{2: } | {1:Xinity }{2: } |
{3:-- Keyword Local completion (^N^P) }{4:match 1 of 7} | {3:-- Keyword Local completion (^N^P) }{4:match 1 of 7} |
]]} ]],
}
end) end)
it('CompleteChanged autocommand', function() it('CompleteChanged autocommand', function()
curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar', ''}) curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar', '' })
source([[ source([[
set complete=. completeopt=noinsert,noselect,menuone set complete=. completeopt=noinsert,noselect,menuone
function! OnPumChange() function! OnPumChange()
@@ -925,39 +943,45 @@ describe('completion', function()
-- v:event.size should be set with ext_popupmenu #20646 -- v:event.size should be set with ext_popupmenu #20646
screen:set_option('ext_popupmenu', true) screen:set_option('ext_popupmenu', true)
feed('Sf<C-N>') feed('Sf<C-N>')
screen:expect({grid = [[ screen:expect({
grid = [[
foo | foo |
bar | bar |
foobar | foobar |
f^ | f^ |
{0:~ }|*3 {0:~ }|*3
{3:-- Keyword completion (^N^P) }{5:Back at original} | {3:-- Keyword completion (^N^P) }{5:Back at original} |
]], popupmenu = { ]],
anchor = { 1, 3, 0 }, popupmenu = {
items = { { "foo", "", "", "" }, { "foobar", "", "", "" } }, anchor = { 1, 3, 0 },
pos = -1 items = { { 'foo', '', '', '' }, { 'foobar', '', '', '' } },
}}) pos = -1,
eq({completed_item = {}, width = 0, },
height = 2, size = 2, })
col = 0, row = 4, scrollbar = false}, eq(
eval('g:event')) { completed_item = {}, width = 0, height = 2, size = 2, col = 0, row = 4, scrollbar = false },
eval('g:event')
)
feed('oob') feed('oob')
screen:expect({grid = [[ screen:expect({
grid = [[
foo | foo |
bar | bar |
foobar | foobar |
foob^ | foob^ |
{0:~ }|*3 {0:~ }|*3
{3:-- Keyword completion (^N^P) }{5:Back at original} | {3:-- Keyword completion (^N^P) }{5:Back at original} |
]], popupmenu = { ]],
anchor = { 1, 3, 0 }, popupmenu = {
items = { { "foobar", "", "", "" } }, anchor = { 1, 3, 0 },
pos = -1 items = { { 'foobar', '', '', '' } },
}}) pos = -1,
eq({completed_item = {}, width = 0, },
height = 1, size = 1, })
col = 0, row = 4, scrollbar = false}, eq(
eval('g:event')) { completed_item = {}, width = 0, height = 1, size = 1, col = 0, row = 4, scrollbar = false },
eval('g:event')
)
feed('<Esc>') feed('<Esc>')
screen:set_option('ext_popupmenu', false) screen:set_option('ext_popupmenu', false)
@@ -972,10 +996,10 @@ describe('completion', function()
{0:~ }| {0:~ }|
{3:-- Keyword completion (^N^P) }{5:Back at original} | {3:-- Keyword completion (^N^P) }{5:Back at original} |
]]) ]])
eq({completed_item = {}, width = 15, eq(
height = 2, size = 2, { completed_item = {}, width = 15, height = 2, size = 2, col = 0, row = 4, scrollbar = false },
col = 0, row = 4, scrollbar = false}, eval('g:event')
eval('g:event')) )
feed('<C-N>') feed('<C-N>')
screen:expect([[ screen:expect([[
foo | foo |
@@ -1028,7 +1052,7 @@ describe('completion', function()
end) end)
it('is stopped by :stopinsert from timer #12976', function() it('is stopped by :stopinsert from timer #12976', function()
screen:try_resize(32,14) screen:try_resize(32, 14)
command([[call setline(1, ['hello', 'hullo', 'heeee', ''])]]) command([[call setline(1, ['hello', 'hullo', 'heeee', ''])]])
feed('Gah<c-x><c-n>') feed('Gah<c-x><c-n>')
screen:expect([[ screen:expect([[
@@ -1044,7 +1068,7 @@ describe('completion', function()
]]) ]])
command([[call timer_start(100, { -> execute('stopinsert') })]]) command([[call timer_start(100, { -> execute('stopinsert') })]])
helpers.sleep(200) helpers.sleep(200)
feed('k') -- cursor should move up in Normal mode feed('k') -- cursor should move up in Normal mode
screen:expect([[ screen:expect([[
hello | hello |
hullo | hullo |
@@ -1084,7 +1108,8 @@ describe('completion', function()
screen:try_resize(20, 9) screen:try_resize(20, 9)
command('set complete+=f | edit foo | edit bar |edit foa |edit .hidden') command('set complete+=f | edit foo | edit bar |edit foa |edit .hidden')
feed('i<C-n>') feed('i<C-n>')
screen:expect{grid=[[ screen:expect {
grid = [[
foo^ | foo^ |
{2:foo }{0: }| {2:foo }{0: }|
{1:bar }{0: }| {1:bar }{0: }|
@@ -1092,15 +1117,18 @@ describe('completion', function()
{1:.hidden }{0: }| {1:.hidden }{0: }|
{0:~ }|*3 {0:~ }|*3
{3:-- }{4:match 1 of 4} | {3:-- }{4:match 1 of 4} |
]]} ]],
}
feed('<Esc>ccf<C-n>') feed('<Esc>ccf<C-n>')
screen:expect{grid=[[ screen:expect {
grid = [[
foo^ | foo^ |
{2:foo }{0: }| {2:foo }{0: }|
{1:foa }{0: }| {1:foa }{0: }|
{0:~ }|*5 {0:~ }|*5
{3:-- }{4:match 1 of 2} | {3:-- }{4:match 1 of 2} |
]]} ]],
}
end) end)
it('restores extmarks if original text is restored #23653', function() it('restores extmarks if original text is restored #23653', function()

View File

@@ -5,7 +5,7 @@ local command = helpers.command
local poke_eventloop = helpers.poke_eventloop local poke_eventloop = helpers.poke_eventloop
local sleep = helpers.sleep local sleep = helpers.sleep
describe("CTRL-C (mapped)", function() describe('CTRL-C (mapped)', function()
local screen local screen
before_each(function() before_each(function()
@@ -14,7 +14,7 @@ describe("CTRL-C (mapped)", function()
screen:attach() screen:attach()
end) end)
it("interrupts :global", function() it('interrupts :global', function()
-- Crashes luajit. -- Crashes luajit.
if helpers.skip_fragile(pending) then if helpers.skip_fragile(pending) then
return return
@@ -25,7 +25,7 @@ describe("CTRL-C (mapped)", function()
nnoremap <C-C> <NOP> nnoremap <C-C> <NOP>
]]) ]])
command("silent edit! test/functional/fixtures/bigfile.txt") command('silent edit! test/functional/fixtures/bigfile.txt')
screen:expect([[ screen:expect([[
^0000;<control>;Cc;0;BN;;;;;N;NULL;;;; | ^0000;<control>;Cc;0;BN;;;;;N;NULL;;;; |
@@ -37,19 +37,21 @@ describe("CTRL-C (mapped)", function()
]]) ]])
local function test_ctrl_c(ms) local function test_ctrl_c(ms)
feed(":global/^/p<CR>") feed(':global/^/p<CR>')
screen:sleep(ms) screen:sleep(ms)
feed("<C-C>") feed('<C-C>')
screen:expect{any="Interrupt"} screen:expect { any = 'Interrupt' }
end end
-- The test is time-sensitive. Try different sleep values. -- The test is time-sensitive. Try different sleep values.
local ms_values = {100, 1000, 10000} local ms_values = { 100, 1000, 10000 }
for i, ms in ipairs(ms_values) do for i, ms in ipairs(ms_values) do
if i < #ms_values then if i < #ms_values then
local status, _ = pcall(test_ctrl_c, ms) local status, _ = pcall(test_ctrl_c, ms)
if status then break end if status then
else -- Call the last attempt directly. break
end
else -- Call the last attempt directly.
test_ctrl_c(ms) test_ctrl_c(ms)
end end
end end
@@ -58,9 +60,9 @@ describe("CTRL-C (mapped)", function()
it('interrupts :sleep', function() it('interrupts :sleep', function()
command('nnoremap <C-C> <Nop>') command('nnoremap <C-C> <Nop>')
feed(':sleep 100<CR>') feed(':sleep 100<CR>')
poke_eventloop() -- wait for :sleep to start poke_eventloop() -- wait for :sleep to start
feed('foo<C-C>') feed('foo<C-C>')
poke_eventloop() -- wait for input buffer to be flushed poke_eventloop() -- wait for input buffer to be flushed
feed('i') feed('i')
screen:expect([[ screen:expect([[
^ | ^ |
@@ -73,9 +75,9 @@ describe("CTRL-C (mapped)", function()
command('nnoremap <C-C> <Nop>') command('nnoremap <C-C> <Nop>')
command('nmap <F2> <Ignore><F2>') command('nmap <F2> <Ignore><F2>')
feed('<F2>') feed('<F2>')
sleep(10) -- wait for the key to enter typeahead sleep(10) -- wait for the key to enter typeahead
feed('foo<C-C>') feed('foo<C-C>')
poke_eventloop() -- wait for input buffer to be flushed poke_eventloop() -- wait for input buffer to be flushed
feed('i') feed('i')
screen:expect([[ screen:expect([[
^ | ^ |

View File

@@ -13,8 +13,12 @@ describe('Folds', function()
local tempfname = 'Xtest-fold.txt' local tempfname = 'Xtest-fold.txt'
setup(clear) setup(clear)
before_each(function() command('bwipe! | new') end) before_each(function()
after_each(function() os.remove(tempfname) end) command('bwipe! | new')
end)
after_each(function()
os.remove(tempfname)
end)
it('manual folding adjusts with filter', function() it('manual folding adjusts with filter', function()
insert([[ insert([[
@@ -94,7 +98,8 @@ describe('Folds', function()
end end
it('neither closes nor corrupts folds', function() it('neither closes nor corrupts folds', function()
test_move_indent([[ test_move_indent(
[[
a a
a a
a a
@@ -112,7 +117,9 @@ a
a a
a a
a a
a]], '7,12m0') a]],
'7,12m0'
)
expect([[ expect([[
a a
a a
@@ -133,7 +140,7 @@ a
a a
a]]) a]])
-- lines are not closed, folds are correct -- lines are not closed, folds are correct
for i = 1,funcs.line('$') do for i = 1, funcs.line('$') do
eq(-1, funcs.foldclosed(i)) eq(-1, funcs.foldclosed(i))
if i == 1 or i == 7 or i == 13 then if i == 1 or i == 7 or i == 13 then
eq(0, funcs.foldlevel(i)) eq(0, funcs.foldlevel(i))
@@ -151,7 +158,8 @@ a
end) end)
it("doesn't split a fold when the move is within it", function() it("doesn't split a fold when the move is within it", function()
test_move_indent([[ test_move_indent(
[[
a a
a a
a a
@@ -161,24 +169,30 @@ a
a a
a a
a a
a]], '5m6') a]],
eq({0, 1, 1, 2, 2, 2, 2, 1, 1, 0}, get_folds()) '5m6'
)
eq({ 0, 1, 1, 2, 2, 2, 2, 1, 1, 0 }, get_folds())
end) end)
it('truncates folds that end in the moved range', function() it('truncates folds that end in the moved range', function()
test_move_indent([[ test_move_indent(
[[
a a
a a
a a
a a
a a
a a
a]], '4,5m6') a]],
eq({0, 1, 2, 0, 0, 0, 0}, get_folds()) '4,5m6'
)
eq({ 0, 1, 2, 0, 0, 0, 0 }, get_folds())
end) end)
it('moves folds that start between moved range and destination', function() it('moves folds that start between moved range and destination', function()
test_move_indent([[ test_move_indent(
[[
a a
a a
a a
@@ -191,12 +205,15 @@ a
a a
a a
a a
a]], '3,4m$') a]],
eq({0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1, 0, 0}, get_folds()) '3,4m$'
)
eq({ 0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1, 0, 0 }, get_folds())
end) end)
it('does not affect folds outside changed lines', function() it('does not affect folds outside changed lines', function()
test_move_indent([[ test_move_indent(
[[
a a
a a
a a
@@ -205,12 +222,15 @@ a
a a
a a
a a
a]], '4m5') a]],
eq({1, 1, 1, 0, 0, 0, 1, 1, 1}, get_folds()) '4m5'
)
eq({ 1, 1, 1, 0, 0, 0, 1, 1, 1 }, get_folds())
end) end)
it('moves and truncates folds that start in moved range', function() it('moves and truncates folds that start in moved range', function()
test_move_indent([[ test_move_indent(
[[
a a
a a
a a
@@ -220,34 +240,43 @@ a
a a
a a
a a
a]], '1,3m7') a]],
eq({0, 0, 0, 0, 0, 1, 2, 0, 0, 0}, get_folds()) '1,3m7'
)
eq({ 0, 0, 0, 0, 0, 1, 2, 0, 0, 0 }, get_folds())
end) end)
it('breaks a fold when moving text into it', function() it('breaks a fold when moving text into it', function()
test_move_indent([[ test_move_indent(
[[
a a
a a
a a
a a
a a
a a
a]], '$m4') a]],
eq({0, 1, 2, 2, 0, 0, 0}, get_folds()) '$m4'
)
eq({ 0, 1, 2, 2, 0, 0, 0 }, get_folds())
end) end)
it('adjusts correctly when moving a range backwards', function() it('adjusts correctly when moving a range backwards', function()
test_move_indent([[ test_move_indent(
[[
a a
a a
a a
a a
a]], '2,3m0') a]],
eq({1, 2, 0, 0, 0}, get_folds()) '2,3m0'
)
eq({ 1, 2, 0, 0, 0 }, get_folds())
end) end)
it('handles shifting all remaining folds', function() it('handles shifting all remaining folds', function()
test_move_indent([[ test_move_indent(
[[
a a
a a
a a
@@ -262,18 +291,23 @@ a]], '2,3m0')
a a
a a
a a
a]], '13m7') a]],
eq({1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0}, get_folds()) '13m7'
)
eq({ 1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0 }, get_folds())
end) end)
end) end)
it('updates correctly on :read', function() it('updates correctly on :read', function()
-- luacheck: ignore 621 -- luacheck: ignore 621
helpers.write_file(tempfname, [[ helpers.write_file(
tempfname,
[[
a a
a]]) a]]
)
insert([[ insert([[
a a
a a
@@ -295,13 +329,13 @@ a]], '13m7')
a a
a a
]]) ]])
for i = 1,2 do for i = 1, 2 do
eq(1, funcs.foldlevel(i)) eq(1, funcs.foldlevel(i))
end end
for i = 3,5 do for i = 3, 5 do
eq(0, funcs.foldlevel(i)) eq(0, funcs.foldlevel(i))
end end
for i = 6,8 do for i = 6, 8 do
eq(1, funcs.foldlevel(i)) eq(1, funcs.foldlevel(i))
end end
end) end)
@@ -356,7 +390,9 @@ a]], '13m7')
return 0 return 0
endfunction endfunction
]]) ]])
helpers.write_file(tempfname, [[ helpers.write_file(
tempfname,
[[
b b
b b
a a
@@ -364,7 +400,8 @@ a]], '13m7')
d d
a a
a a
c]]) c]]
)
insert([[ insert([[
a a
a a
@@ -388,7 +425,7 @@ a]], '13m7')
it('no folds remain if :delete makes buffer empty #19671', function() it('no folds remain if :delete makes buffer empty #19671', function()
command('setlocal foldmethod=manual') command('setlocal foldmethod=manual')
funcs.setline(1, {'foo', 'bar', 'baz'}) funcs.setline(1, { 'foo', 'bar', 'baz' })
command('2,3fold') command('2,3fold')
command('%delete') command('%delete')
eq(0, funcs.foldlevel(1)) eq(0, funcs.foldlevel(1))

View File

@@ -12,7 +12,7 @@ local curbufmeths = helpers.curbufmeths
describe('jumplist', function() describe('jumplist', function()
local fname1 = 'Xtest-functional-normal-jump' local fname1 = 'Xtest-functional-normal-jump'
local fname2 = fname1..'2' local fname2 = fname1 .. '2'
before_each(clear) before_each(clear)
after_each(function() after_each(function()
os.remove(fname1) os.remove(fname1)
@@ -27,7 +27,7 @@ describe('jumplist', function()
write_file(fname1, 'first file contents') write_file(fname1, 'first file contents')
write_file(fname2, 'second file contents') write_file(fname2, 'second file contents')
command('args '..fname1..' '..fname2) command('args ' .. fname1 .. ' ' .. fname2)
local buf1 = funcs.bufnr(fname1) local buf1 = funcs.bufnr(fname1)
local buf2 = funcs.bufnr(fname2) local buf2 = funcs.bufnr(fname2)
@@ -44,7 +44,7 @@ describe('jumplist', function()
feed('<C-O>') feed('<C-O>')
eq(buf1, funcs.bufnr('%')) eq(buf1, funcs.bufnr('%'))
command('drop '..fname2) command('drop ' .. fname2)
feed('<C-O>') feed('<C-O>')
eq(buf1, funcs.bufnr('%')) eq(buf1, funcs.bufnr('%'))
end) end)
@@ -56,11 +56,12 @@ describe('jumplist', function()
local screen = Screen.new(5, 25) local screen = Screen.new(5, 25)
screen:attach() screen:attach()
command('set number') command('set number')
command('edit '..fname1) command('edit ' .. fname1)
feed('35gg') feed('35gg')
command('edit '..fname2) command('edit ' .. fname2)
feed('<C-O>') feed('<C-O>')
screen:expect{grid=[[ screen:expect {
grid = [[
{1: 24 }foobar | {1: 24 }foobar |
{1: 25 }foobar | {1: 25 }foobar |
{1: 26 }foobar | {1: 26 }foobar |
@@ -86,9 +87,11 @@ describe('jumplist', function()
{1: 46 }foobar | {1: 46 }foobar |
{1: 47 }foobar | {1: 47 }foobar |
| |
]], attr_ids={ ]],
[1] = {foreground = Screen.colors.Brown}; attr_ids = {
}} [1] = { foreground = Screen.colors.Brown },
},
}
end) end)
end) end)
@@ -98,9 +101,8 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
feed(':clearjumps<cr>') feed(':clearjumps<cr>')
-- Add lines so that we have locations to jump to. -- Add lines so that we have locations to jump to.
for i = 1,101,1 for i = 1, 101, 1 do
do feed('iLine ' .. i .. '<cr><esc>')
feed('iLine ' .. i .. '<cr><esc>')
end end
-- Jump around to add some locations to the jump list. -- Jump around to add some locations to the jump list.
@@ -115,82 +117,90 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
end) end)
after_each(function() after_each(function()
feed('set jumpoptions=') feed('set jumpoptions=')
end) end)
it('discards the tail when navigating from the middle', function() it('discards the tail when navigating from the middle', function()
feed('<C-O>') feed('<C-O>')
feed('<C-O>') feed('<C-O>')
eq( '' eq(
.. ' jump line col file/text\n' ''
.. ' 4 102 0 \n' .. ' jump line col file/text\n'
.. ' 3 1 0 Line 1\n' .. ' 4 102 0 \n'
.. ' 2 10 0 Line 10\n' .. ' 3 1 0 Line 1\n'
.. ' 1 20 0 Line 20\n' .. ' 2 10 0 Line 10\n'
.. '> 0 30 0 Line 30\n' .. ' 1 20 0 Line 20\n'
.. ' 1 40 0 Line 40\n' .. '> 0 30 0 Line 30\n'
.. ' 2 50 0 Line 50', .. ' 1 40 0 Line 40\n'
exec_capture('jumps')) .. ' 2 50 0 Line 50',
exec_capture('jumps')
)
feed('90gg') feed('90gg')
eq( '' eq(
.. ' jump line col file/text\n' ''
.. ' 5 102 0 \n' .. ' jump line col file/text\n'
.. ' 4 1 0 Line 1\n' .. ' 5 102 0 \n'
.. ' 3 10 0 Line 10\n' .. ' 4 1 0 Line 1\n'
.. ' 2 20 0 Line 20\n' .. ' 3 10 0 Line 10\n'
.. ' 1 30 0 Line 30\n' .. ' 2 20 0 Line 20\n'
.. '>', .. ' 1 30 0 Line 30\n'
exec_capture('jumps')) .. '>',
exec_capture('jumps')
)
end) end)
it('does not add the same location twice adjacently', function() it('does not add the same location twice adjacently', function()
feed('60gg') feed('60gg')
feed('60gg') feed('60gg')
eq( '' eq(
.. ' jump line col file/text\n' ''
.. ' 7 102 0 \n' .. ' jump line col file/text\n'
.. ' 6 1 0 Line 1\n' .. ' 7 102 0 \n'
.. ' 5 10 0 Line 10\n' .. ' 6 1 0 Line 1\n'
.. ' 4 20 0 Line 20\n' .. ' 5 10 0 Line 10\n'
.. ' 3 30 0 Line 30\n' .. ' 4 20 0 Line 20\n'
.. ' 2 40 0 Line 40\n' .. ' 3 30 0 Line 30\n'
.. ' 1 50 0 Line 50\n' .. ' 2 40 0 Line 40\n'
.. '>', .. ' 1 50 0 Line 50\n'
exec_capture('jumps')) .. '>',
exec_capture('jumps')
)
end) end)
it('does add the same location twice nonadjacently', function() it('does add the same location twice nonadjacently', function()
feed('10gg') feed('10gg')
feed('20gg') feed('20gg')
eq( '' eq(
.. ' jump line col file/text\n' ''
.. ' 8 102 0 \n' .. ' jump line col file/text\n'
.. ' 7 1 0 Line 1\n' .. ' 8 102 0 \n'
.. ' 6 10 0 Line 10\n' .. ' 7 1 0 Line 1\n'
.. ' 5 20 0 Line 20\n' .. ' 6 10 0 Line 10\n'
.. ' 4 30 0 Line 30\n' .. ' 5 20 0 Line 20\n'
.. ' 3 40 0 Line 40\n' .. ' 4 30 0 Line 30\n'
.. ' 2 50 0 Line 50\n' .. ' 3 40 0 Line 40\n'
.. ' 1 10 0 Line 10\n' .. ' 2 50 0 Line 50\n'
.. '>', .. ' 1 10 0 Line 10\n'
exec_capture('jumps')) .. '>',
exec_capture('jumps')
)
end) end)
end) end)
describe("jumpoptions=view", function() describe('jumpoptions=view', function()
local file1 = 'Xtestfile-functional-editor-jumps' local file1 = 'Xtestfile-functional-editor-jumps'
local file2 = 'Xtestfile-functional-editor-jumps-2' local file2 = 'Xtestfile-functional-editor-jumps-2'
local function content() local function content()
local c = {} local c = {}
for i=1,30 do for i = 1, 30 do
c[i] = i .. " line" c[i] = i .. ' line'
end end
return table.concat(c, "\n") return table.concat(c, '\n')
end end
before_each(function() before_each(function()
clear() clear()
@@ -206,9 +216,9 @@ describe("jumpoptions=view", function()
it('restores the view', function() it('restores the view', function()
local screen = Screen.new(5, 8) local screen = Screen.new(5, 8)
screen:attach() screen:attach()
command("edit " .. file1) command('edit ' .. file1)
feed("12Gztj") feed('12Gztj')
feed("gg<C-o>") feed('gg<C-o>')
screen:expect([[ screen:expect([[
12 line | 12 line |
^13 line | ^13 line |
@@ -224,10 +234,10 @@ describe("jumpoptions=view", function()
it('restores the view across files', function() it('restores the view across files', function()
local screen = Screen.new(5, 5) local screen = Screen.new(5, 5)
screen:attach() screen:attach()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
feed("12Gzt") feed('12Gzt')
command("next") command('next')
feed("G") feed('G')
screen:expect([[ screen:expect([[
27 line | 27 line |
28 line | 28 line |
@@ -235,7 +245,7 @@ describe("jumpoptions=view", function()
^30 line | ^30 line |
| |
]]) ]])
feed("<C-o><C-o>") feed('<C-o><C-o>')
screen:expect([[ screen:expect([[
^12 line | ^12 line |
13 line | 13 line |
@@ -248,10 +258,10 @@ describe("jumpoptions=view", function()
it('restores the view across files with <C-^>', function() it('restores the view across files with <C-^>', function()
local screen = Screen.new(5, 5) local screen = Screen.new(5, 5)
screen:attach() screen:attach()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
feed("12Gzt") feed('12Gzt')
command("next") command('next')
feed("G") feed('G')
screen:expect([[ screen:expect([[
27 line | 27 line |
28 line | 28 line |
@@ -259,7 +269,7 @@ describe("jumpoptions=view", function()
^30 line | ^30 line |
| |
]]) ]])
feed("<C-^>") feed('<C-^>')
screen:expect([[ screen:expect([[
^12 line | ^12 line |
13 line | 13 line |
@@ -269,11 +279,11 @@ describe("jumpoptions=view", function()
]]) ]])
end) end)
it('falls back to standard behavior when view can\'t be recovered', function() it("falls back to standard behavior when view can't be recovered", function()
local screen = Screen.new(5, 8) local screen = Screen.new(5, 8)
screen:attach() screen:attach()
command("edit " .. file1) command('edit ' .. file1)
feed("7GzbG") feed('7GzbG')
curbufmeths.set_lines(0, 2, true, {}) curbufmeths.set_lines(0, 2, true, {})
-- Move to line 7, and set it as the last line visible on the view with zb, meaning to recover -- Move to line 7, and set it as the last line visible on the view with zb, meaning to recover
-- the view it needs to put the cursor 7 lines from the top line. Then go to the end of the -- the view it needs to put the cursor 7 lines from the top line. Then go to the end of the
@@ -281,7 +291,7 @@ describe("jumpoptions=view", function()
-- Therefore when trying to jump back to it it's not possible to set a 7 line offset from the -- Therefore when trying to jump back to it it's not possible to set a 7 line offset from the
-- mark position to the top line, since there's only 5 lines from the mark position to line 0. -- mark position to the top line, since there's only 5 lines from the mark position to line 0.
-- Therefore falls back to standard behavior which is centering the view/line. -- Therefore falls back to standard behavior which is centering the view/line.
feed("<C-o>") feed('<C-o>')
screen:expect([[ screen:expect([[
4 line | 4 line |
5 line | 5 line |

View File

@@ -9,11 +9,11 @@ describe('gu and gU', function()
it('works in any locale with default casemap', function() it('works in any locale with default casemap', function()
eq('internal,keepascii', eval('&casemap')) eq('internal,keepascii', eval('&casemap'))
insert("iI") insert('iI')
feed("VgU") feed('VgU')
expect("II") expect('II')
feed("Vgu") feed('Vgu')
expect("ii") expect('ii')
end) end)
describe('works in Turkish locale', function() describe('works in Turkish locale', function()
@@ -21,7 +21,7 @@ describe('gu and gU', function()
local err = exc_exec('lang ctype tr_TR.UTF-8') local err = exc_exec('lang ctype tr_TR.UTF-8')
if err ~= 0 then if err ~= 0 then
pending("Locale tr_TR.UTF-8 not supported", function() end) pending('Locale tr_TR.UTF-8 not supported', function() end)
return return
end end
@@ -32,29 +32,29 @@ describe('gu and gU', function()
it('with default casemap', function() it('with default casemap', function()
eq('internal,keepascii', eval('&casemap')) eq('internal,keepascii', eval('&casemap'))
-- expect ASCII behavior -- expect ASCII behavior
insert("iI") insert('iI')
feed("VgU") feed('VgU')
expect("II") expect('II')
feed("Vgu") feed('Vgu')
expect("ii") expect('ii')
end) end)
it('with casemap=""', function() it('with casemap=""', function()
command('set casemap=') command('set casemap=')
-- expect either Turkish locale behavior or ASCII behavior -- expect either Turkish locale behavior or ASCII behavior
local iupper = eval("toupper('i')") local iupper = eval("toupper('i')")
if iupper == "İ" then if iupper == 'İ' then
insert("iI") insert('iI')
feed("VgU") feed('VgU')
expect("İI") expect('İI')
feed("Vgu") feed('Vgu')
expect("iı") expect('iı')
elseif iupper == "I" then elseif iupper == 'I' then
insert("iI") insert('iI')
feed("VgU") feed('VgU')
expect("II") expect('II')
feed("Vgu") feed('Vgu')
expect("ii") expect('ii')
else else
error("expected toupper('i') to be either 'I' or 'İ'") error("expected toupper('i') to be either 'I' or 'İ'")
end end

View File

@@ -14,13 +14,13 @@ describe("'langmap'", function()
feed('gg0') feed('gg0')
end) end)
it("converts keys in normal mode", function() it('converts keys in normal mode', function()
feed('ix') feed('ix')
expect('iii ww') expect('iii ww')
feed('whello<esc>') feed('whello<esc>')
expect('iii helloww') expect('iii helloww')
end) end)
it("gives characters that are mapped by :nmap.", function() it('gives characters that are mapped by :nmap.', function()
command('map i 0x') command('map i 0x')
feed('w') feed('w')
expect('ii www') expect('ii www')
@@ -32,20 +32,18 @@ describe("'langmap'", function()
it("'langnoremap' is by default ON", function() it("'langnoremap' is by default ON", function()
eq(1, eval('&langnoremap')) eq(1, eval('&langnoremap'))
end) end)
it("Results of maps are not converted when 'langnoremap' ON.", it("Results of maps are not converted when 'langnoremap' ON.", function()
function()
command('nmap x i') command('nmap x i')
feed('xdl<esc>') feed('xdl<esc>')
expect('dliii www') expect('dliii www')
end) end)
it("applies when deciding whether to map recursively", function() it('applies when deciding whether to map recursively', function()
command('nmap l i') command('nmap l i')
command('nmap w j') command('nmap w j')
feed('ll') feed('ll')
expect('liii www') expect('liii www')
end) end)
it("does not stop applying 'langmap' on first character of a mapping", it("does not stop applying 'langmap' on first character of a mapping", function()
function()
command('1t1') command('1t1')
command('1t1') command('1t1')
command('goto 1') command('goto 1')
@@ -56,8 +54,7 @@ describe("'langmap'", function()
iii www iii www
ihelloii www]]) ihelloii www]])
end) end)
it("Results of maps are converted when 'langnoremap' OFF.", it("Results of maps are converted when 'langnoremap' OFF.", function()
function()
command('set nolangnoremap') command('set nolangnoremap')
command('nmap x i') command('nmap x i')
feed('xdl<esc>') feed('xdl<esc>')
@@ -65,8 +62,7 @@ describe("'langmap'", function()
end) end)
end) end)
-- e.g. CTRL-W_j , mj , 'j and "jp -- e.g. CTRL-W_j , mj , 'j and "jp
it('conversions are applied to keys in middle of command', it('conversions are applied to keys in middle of command', function()
function()
-- Works in middle of window command -- Works in middle of window command
feed('<C-w>s') feed('<C-w>s')
local origwin = curwin() local origwin = curwin()
@@ -74,12 +70,12 @@ describe("'langmap'", function()
neq(origwin, curwin()) neq(origwin, curwin())
-- Works when setting a mark -- Works when setting a mark
feed('yy3p3gg0mwgg0mi') feed('yy3p3gg0mwgg0mi')
eq({0, 3, 1, 0}, call('getpos', "'i")) eq({ 0, 3, 1, 0 }, call('getpos', "'i"))
eq({0, 1, 1, 0}, call('getpos', "'w")) eq({ 0, 1, 1, 0 }, call('getpos', "'w"))
feed('3dd') feed('3dd')
-- Works when moving to a mark -- Works when moving to a mark
feed("'i") feed("'i")
eq({0, 1, 1, 0}, call('getpos', '.')) eq({ 0, 1, 1, 0 }, call('getpos', '.'))
-- Works when selecting a register -- Works when selecting a register
feed('qillqqwhhq') feed('qillqqwhhq')
eq('hh', eval('@i')) eq('hh', eval('@i'))
@@ -193,8 +189,7 @@ describe("'langmap'", function()
eq(1, eval('gotten_one')) eq(1, eval('gotten_one'))
end) end)
end) end)
it('conversions are not applied during setreg()', it('conversions are not applied during setreg()', function()
function()
call('setreg', 'i', 'ww') call('setreg', 'i', 'ww')
eq('ww', eval('@i')) eq('ww', eval('@i'))
end) end)
@@ -214,12 +209,18 @@ describe("'langmap'", function()
end) end)
local function testrecording(command_string, expect_string, setup_function, expect_macro) local function testrecording(command_string, expect_string, setup_function, expect_macro)
if setup_function then setup_function() end if setup_function then
setup_function()
end
feed('qa' .. command_string .. 'q') feed('qa' .. command_string .. 'q')
expect(expect_string) expect(expect_string)
eq(expect_macro or helpers.funcs.nvim_replace_termcodes(command_string, true, true, true), eq(
eval('@a')) expect_macro or helpers.funcs.nvim_replace_termcodes(command_string, true, true, true),
if setup_function then setup_function() end eval('@a')
)
if setup_function then
setup_function()
end
-- n.b. may need nvim_replace_termcodes() here. -- n.b. may need nvim_replace_termcodes() here.
feed('@a') feed('@a')
expect(expect_string) expect(expect_string)
@@ -276,5 +277,4 @@ describe("'langmap'", function()
testrecording('<C-w>', 'whello', local_setup, eval([["\<*C-w>"]])) testrecording('<C-w>', 'whello', local_setup, eval([["\<*C-w>"]]))
testrecording('<C-i>', 'ihello', local_setup, eval([["\<*C-i>"]])) testrecording('<C-i>', 'ihello', local_setup, eval([["\<*C-i>"]]))
end) end)
end) end)

View File

@@ -11,10 +11,9 @@ local meths = helpers.meths
local insert = helpers.insert local insert = helpers.insert
local curbufmeths = helpers.curbufmeths local curbufmeths = helpers.curbufmeths
describe('macros', function() describe('macros', function()
before_each(function() before_each(function()
clear({args_rm = {'--cmd'}}) clear({ args_rm = { '--cmd' } })
end) end)
it('can be recorded and replayed', function() it('can be recorded and replayed', function()
feed('qiahello<esc>q') feed('qiahello<esc>q')
@@ -42,16 +41,16 @@ hello]]
feed [[gg]] feed [[gg]]
feed [[qqAFOO<esc>q]] feed [[qqAFOO<esc>q]]
eq({'helloFOO', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOO', 'hello', 'hello' }, curbufmeths.get_lines(0, -1, false))
feed[[Q]] feed [[Q]]
eq({'helloFOOFOO', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOOFOO', 'hello', 'hello' }, curbufmeths.get_lines(0, -1, false))
feed[[G3Q]] feed [[G3Q]]
eq({'helloFOOFOO', 'hello', 'helloFOOFOOFOO'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOOFOO', 'hello', 'helloFOOFOOFOO' }, curbufmeths.get_lines(0, -1, false))
feed[[ggV3jQ]] feed [[ggV3jQ]]
eq({'helloFOOFOOFOO', 'helloFOO', 'helloFOOFOOFOOFOO'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOOFOOFOO', 'helloFOO', 'helloFOOFOOFOOFOO' }, curbufmeths.get_lines(0, -1, false))
end) end)
it('can be replayed with @', function() it('can be replayed with @', function()
@@ -61,37 +60,36 @@ hello]]
feed [[gg]] feed [[gg]]
feed [[qqAFOO<esc>q]] feed [[qqAFOO<esc>q]]
eq({'helloFOO', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOO', 'hello', 'hello' }, curbufmeths.get_lines(0, -1, false))
feed[[Q]] feed [[Q]]
eq({'helloFOOFOO', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOOFOO', 'hello', 'hello' }, curbufmeths.get_lines(0, -1, false))
feed[[G3@@]] feed [[G3@@]]
eq({'helloFOOFOO', 'hello', 'helloFOOFOOFOO'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOOFOO', 'hello', 'helloFOOFOOFOO' }, curbufmeths.get_lines(0, -1, false))
feed[[ggV2j@@]] feed [[ggV2j@@]]
eq({'helloFOOFOOFOO', 'helloFOO', 'helloFOOFOOFOOFOO'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOOFOOFOO', 'helloFOO', 'helloFOOFOOFOOFOO' }, curbufmeths.get_lines(0, -1, false))
end) end)
it('can be replayed with @q and @w', function() it('can be replayed with @q and @w', function()
insert [[hello insert [[hello
hello hello
hello]] hello]]
feed [[gg]] feed [[gg]]
feed [[qqAFOO<esc>qu]] feed [[qqAFOO<esc>qu]]
eq({'hello', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false)) eq({ 'hello', 'hello', 'hello' }, curbufmeths.get_lines(0, -1, false))
feed [[qwA123<esc>qu]] feed [[qwA123<esc>qu]]
eq({'hello', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false)) eq({ 'hello', 'hello', 'hello' }, curbufmeths.get_lines(0, -1, false))
feed[[V3j@q]] feed [[V3j@q]]
eq({'helloFOO', 'helloFOO', 'helloFOO'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOO', 'helloFOO', 'helloFOO' }, curbufmeths.get_lines(0, -1, false))
feed [[gg]] feed [[gg]]
feed[[Vj@w]] feed [[Vj@w]]
eq({'helloFOO123', 'helloFOO123', 'helloFOO'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOO123', 'helloFOO123', 'helloFOO' }, curbufmeths.get_lines(0, -1, false))
end) end)
it('can be replayed with @q and @w visual-block', function() it('can be replayed with @q and @w visual-block', function()
@@ -101,17 +99,17 @@ hello]]
feed [[gg]] feed [[gg]]
feed [[qqAFOO<esc>qu]] feed [[qqAFOO<esc>qu]]
eq({'hello', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false)) eq({ 'hello', 'hello', 'hello' }, curbufmeths.get_lines(0, -1, false))
feed [[qwA123<esc>qu]] feed [[qwA123<esc>qu]]
eq({'hello', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false)) eq({ 'hello', 'hello', 'hello' }, curbufmeths.get_lines(0, -1, false))
feed[[<C-v>3j@q]] feed [[<C-v>3j@q]]
eq({'helloFOO', 'helloFOO', 'helloFOO'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOO', 'helloFOO', 'helloFOO' }, curbufmeths.get_lines(0, -1, false))
feed [[gg]] feed [[gg]]
feed[[<C-v>j@w]] feed [[<C-v>j@w]]
eq({'helloFOO123', 'helloFOO123', 'helloFOO'}, curbufmeths.get_lines(0, -1, false)) eq({ 'helloFOO123', 'helloFOO123', 'helloFOO' }, curbufmeths.get_lines(0, -1, false))
end) end)
end) end)
@@ -140,16 +138,16 @@ describe('immediately after a macro has finished executing,', function()
end) end)
it('if the macro does not end with a <Nop> mapping', function() it('if the macro does not end with a <Nop> mapping', function()
feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op
eq({mode = 'n', blocking = false}, meths.get_mode()) eq({ mode = 'n', blocking = false }, meths.get_mode())
expect('') expect('')
eq('', eval('@a')) eq('', eval('@a'))
end) end)
it('if the macro ends with a <Nop> mapping', function() it('if the macro ends with a <Nop> mapping', function()
command('nnoremap 0 <Nop>') command('nnoremap 0 <Nop>')
feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op
eq({mode = 'n', blocking = false}, meths.get_mode()) eq({ mode = 'n', blocking = false }, meths.get_mode())
expect('') expect('')
eq('', eval('@a')) eq('', eval('@a'))
end) end)

View File

@@ -9,7 +9,9 @@ local eq = helpers.eq
local feed = helpers.feed local feed = helpers.feed
local write_file = helpers.write_file local write_file = helpers.write_file
local pcall_err = helpers.pcall_err local pcall_err = helpers.pcall_err
local cursor = function() return helpers.meths.win_get_cursor(0) end local cursor = function()
return helpers.meths.win_get_cursor(0)
end
describe('named marks', function() describe('named marks', function()
local file1 = 'Xtestfile-functional-editor-marks' local file1 = 'Xtestfile-functional-editor-marks'
@@ -24,153 +26,153 @@ describe('named marks', function()
os.remove(file2) os.remove(file2)
end) end)
it("can be set", function() it('can be set', function()
command("edit " .. file1) command('edit ' .. file1)
command("mark a") command('mark a')
eq({1, 0}, curbufmeths.get_mark("a")) eq({ 1, 0 }, curbufmeths.get_mark('a'))
feed("jmb") feed('jmb')
eq({2, 0}, curbufmeths.get_mark("b")) eq({ 2, 0 }, curbufmeths.get_mark('b'))
feed("jmB") feed('jmB')
eq({3, 0}, curbufmeths.get_mark("B")) eq({ 3, 0 }, curbufmeths.get_mark('B'))
command("4kc") command('4kc')
eq({4, 0}, curbufmeths.get_mark("c")) eq({ 4, 0 }, curbufmeths.get_mark('c'))
end) end)
it("errors when set out of range with :mark", function() it('errors when set out of range with :mark', function()
command("edit " .. file1) command('edit ' .. file1)
local err = pcall_err(helpers.exec_capture, "1000mark x") local err = pcall_err(helpers.exec_capture, '1000mark x')
eq("nvim_exec2(): Vim(mark):E16: Invalid range: 1000mark x", err) eq('nvim_exec2(): Vim(mark):E16: Invalid range: 1000mark x', err)
end) end)
it("errors when set out of range with :k", function() it('errors when set out of range with :k', function()
command("edit " .. file1) command('edit ' .. file1)
local err = pcall_err(helpers.exec_capture, "1000kx") local err = pcall_err(helpers.exec_capture, '1000kx')
eq("nvim_exec2(): Vim(k):E16: Invalid range: 1000kx", err) eq('nvim_exec2(): Vim(k):E16: Invalid range: 1000kx', err)
end) end)
it("errors on unknown mark name with :mark", function() it('errors on unknown mark name with :mark', function()
command("edit " .. file1) command('edit ' .. file1)
local err = pcall_err(helpers.exec_capture, "mark #") local err = pcall_err(helpers.exec_capture, 'mark #')
eq("nvim_exec2(): Vim(mark):E191: Argument must be a letter or forward/backward quote", err) eq('nvim_exec2(): Vim(mark):E191: Argument must be a letter or forward/backward quote', err)
end) end)
it("errors on unknown mark name with '", function() it("errors on unknown mark name with '", function()
command("edit " .. file1) command('edit ' .. file1)
local err = pcall_err(helpers.exec_capture, "normal! '#") local err = pcall_err(helpers.exec_capture, "normal! '#")
eq("nvim_exec2(): Vim(normal):E78: Unknown mark", err) eq('nvim_exec2(): Vim(normal):E78: Unknown mark', err)
end) end)
it("errors on unknown mark name with `", function() it('errors on unknown mark name with `', function()
command("edit " .. file1) command('edit ' .. file1)
local err = pcall_err(helpers.exec_capture, "normal! `#") local err = pcall_err(helpers.exec_capture, 'normal! `#')
eq("nvim_exec2(): Vim(normal):E78: Unknown mark", err) eq('nvim_exec2(): Vim(normal):E78: Unknown mark', err)
end) end)
it("errors when moving to a mark that is not set with '", function() it("errors when moving to a mark that is not set with '", function()
command("edit " .. file1) command('edit ' .. file1)
local err = pcall_err(helpers.exec_capture, "normal! 'z") local err = pcall_err(helpers.exec_capture, "normal! 'z")
eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
err = pcall_err(helpers.exec_capture, "normal! '.") err = pcall_err(helpers.exec_capture, "normal! '.")
eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
end) end)
it("errors when moving to a mark that is not set with `", function() it('errors when moving to a mark that is not set with `', function()
command("edit " .. file1) command('edit ' .. file1)
local err = pcall_err(helpers.exec_capture, "normal! `z") local err = pcall_err(helpers.exec_capture, 'normal! `z')
eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
err = pcall_err(helpers.exec_capture, "normal! `>") err = pcall_err(helpers.exec_capture, 'normal! `>')
eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
end) end)
it("errors when moving to a global mark that is not set with '", function() it("errors when moving to a global mark that is not set with '", function()
command("edit " .. file1) command('edit ' .. file1)
local err = pcall_err(helpers.exec_capture, "normal! 'Z") local err = pcall_err(helpers.exec_capture, "normal! 'Z")
eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
end) end)
it("errors when moving to a global mark that is not set with `", function() it('errors when moving to a global mark that is not set with `', function()
command("edit " .. file1) command('edit ' .. file1)
local err = pcall_err(helpers.exec_capture, "normal! `Z") local err = pcall_err(helpers.exec_capture, 'normal! `Z')
eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
end) end)
it("can move to them using '", function() it("can move to them using '", function()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
feed("j") feed('j')
feed("ma") feed('ma')
feed("G'a") feed("G'a")
eq({2, 0}, cursor()) eq({ 2, 0 }, cursor())
feed("mA") feed('mA')
command("next") command('next')
feed("'A") feed("'A")
eq(1, meths.get_current_buf().id) eq(1, meths.get_current_buf().id)
eq({2, 0}, cursor()) eq({ 2, 0 }, cursor())
end) end)
it("can move to them using `", function() it('can move to them using `', function()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
feed("jll") feed('jll')
feed("ma") feed('ma')
feed("G`a") feed('G`a')
eq({2, 2}, cursor()) eq({ 2, 2 }, cursor())
feed("mA") feed('mA')
command("next") command('next')
feed("`A") feed('`A')
eq(1, meths.get_current_buf().id) eq(1, meths.get_current_buf().id)
eq({2, 2}, cursor()) eq({ 2, 2 }, cursor())
end) end)
it("can move to them using g'", function() it("can move to them using g'", function()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
feed("jll") feed('jll')
feed("ma") feed('ma')
feed("Gg'a") feed("Gg'a")
eq({2, 0}, cursor()) eq({ 2, 0 }, cursor())
feed("mA") feed('mA')
command("next") command('next')
feed("g'A") feed("g'A")
eq(1, meths.get_current_buf().id) eq(1, meths.get_current_buf().id)
eq({2, 0}, cursor()) eq({ 2, 0 }, cursor())
end) end)
it("can move to them using g`", function() it('can move to them using g`', function()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
feed("jll") feed('jll')
feed("ma") feed('ma')
feed("Gg`a") feed('Gg`a')
eq({2, 2}, cursor()) eq({ 2, 2 }, cursor())
feed("mA") feed('mA')
command("next") command('next')
feed("g`A") feed('g`A')
eq(1, meths.get_current_buf().id) eq(1, meths.get_current_buf().id)
eq({2, 2}, cursor()) eq({ 2, 2 }, cursor())
end) end)
it("can move to them using :'", function() it("can move to them using :'", function()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
feed("j") feed('j')
feed("ma") feed('ma')
feed("G") feed('G')
command("'a") command("'a")
eq({2, 0}, cursor()) eq({ 2, 0 }, cursor())
feed("mA") feed('mA')
command("next") command('next')
command("'A") command("'A")
eq(1, meths.get_current_buf().id) eq(1, meths.get_current_buf().id)
eq({2, 0}, cursor()) eq({ 2, 0 }, cursor())
end) end)
it("errors when it can't find the buffer", function() it("errors when it can't find the buffer", function()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
feed("mA") feed('mA')
command("next") command('next')
command("bw! " .. file1 ) command('bw! ' .. file1)
local err = pcall_err(helpers.exec_capture, "normal! 'A") local err = pcall_err(helpers.exec_capture, "normal! 'A")
eq("nvim_exec2(): Vim(normal):E92: Buffer 1 not found", err) eq('nvim_exec2(): Vim(normal):E92: Buffer 1 not found', err)
os.remove(file1) os.remove(file1)
end) end)
it("errors when using a mark in another buffer in command range", function() it('errors when using a mark in another buffer in command range', function()
feed('ifoo<Esc>mA') feed('ifoo<Esc>mA')
command('enew') command('enew')
feed('ibar<Esc>') feed('ibar<Esc>')
@@ -178,147 +180,147 @@ describe('named marks', function()
end) end)
it("leave a context mark when moving with '", function() it("leave a context mark when moving with '", function()
command("edit " .. file1) command('edit ' .. file1)
feed("llmamA") feed('llmamA')
feed("10j0") -- first col, last line feed('10j0') -- first col, last line
local pos = cursor() local pos = cursor()
feed("'a") feed("'a")
feed("<C-o>") feed('<C-o>')
eq(pos, cursor()) eq(pos, cursor())
feed("'A") feed("'A")
feed("<C-o>") feed('<C-o>')
eq(pos, cursor()) eq(pos, cursor())
end) end)
it("leave a context mark when moving with `", function() it('leave a context mark when moving with `', function()
command("edit " .. file1) command('edit ' .. file1)
feed("llmamA") feed('llmamA')
feed("10j0") -- first col, last line feed('10j0') -- first col, last line
local pos = cursor() local pos = cursor()
feed("`a") feed('`a')
feed("<C-o>") feed('<C-o>')
eq(pos, cursor()) eq(pos, cursor())
feed("`A") feed('`A')
feed("<C-o>") feed('<C-o>')
eq(pos, cursor()) eq(pos, cursor())
end) end)
it("leave a context mark when the mark changes buffer with g'", function() it("leave a context mark when the mark changes buffer with g'", function()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
local pos local pos
feed("GmA") feed('GmA')
command("next") command('next')
pos = cursor() pos = cursor()
command("clearjumps") command('clearjumps')
feed("g'A") -- since the mark is in another buffer, it leaves a context mark feed("g'A") -- since the mark is in another buffer, it leaves a context mark
feed("<C-o>") feed('<C-o>')
eq(pos, cursor()) eq(pos, cursor())
end) end)
it("leave a context mark when the mark changes buffer with g`", function() it('leave a context mark when the mark changes buffer with g`', function()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
local pos local pos
feed("GmA") feed('GmA')
command("next") command('next')
pos = cursor() pos = cursor()
command("clearjumps") command('clearjumps')
feed("g`A") -- since the mark is in another buffer, it leaves a context mark feed('g`A') -- since the mark is in another buffer, it leaves a context mark
feed("<C-o>") feed('<C-o>')
eq(pos, cursor()) eq(pos, cursor())
end) end)
it("do not leave a context mark when moving with g'", function() it("do not leave a context mark when moving with g'", function()
command("edit " .. file1) command('edit ' .. file1)
local pos local pos
feed("ma") feed('ma')
pos = cursor() -- Mark pos pos = cursor() -- Mark pos
feed("10j0") -- first col, last line feed('10j0') -- first col, last line
feed("g'a") feed("g'a")
feed("<C-o>") -- should do nothing feed('<C-o>') -- should do nothing
eq(pos, cursor()) eq(pos, cursor())
feed("mA") feed('mA')
pos = cursor() -- Mark pos pos = cursor() -- Mark pos
feed("10j0") -- first col, last line feed('10j0') -- first col, last line
feed("g'a") feed("g'a")
feed("<C-o>") -- should do nothing feed('<C-o>') -- should do nothing
eq(pos, cursor()) eq(pos, cursor())
end) end)
it("do not leave a context mark when moving with g`", function() it('do not leave a context mark when moving with g`', function()
command("edit " .. file1) command('edit ' .. file1)
local pos local pos
feed("ma") feed('ma')
pos = cursor() -- Mark pos pos = cursor() -- Mark pos
feed("10j0") -- first col, last line feed('10j0') -- first col, last line
feed("g`a") feed('g`a')
feed("<C-o>") -- should do nothing feed('<C-o>') -- should do nothing
eq(pos, cursor()) eq(pos, cursor())
feed("mA") feed('mA')
pos = cursor() -- Mark pos pos = cursor() -- Mark pos
feed("10j0") -- first col, last line feed('10j0') -- first col, last line
feed("g'a") feed("g'a")
feed("<C-o>") -- should do nothing feed('<C-o>') -- should do nothing
eq(pos, cursor()) eq(pos, cursor())
end) end)
it("open folds when moving to them", function() it('open folds when moving to them', function()
command("edit " .. file1) command('edit ' .. file1)
feed("jzfG") -- Fold from the second line to the end feed('jzfG') -- Fold from the second line to the end
command("3mark a") command('3mark a')
feed("G") -- On top of the fold feed('G') -- On top of the fold
assert(funcs.foldclosed('.') ~= -1) -- folded assert(funcs.foldclosed('.') ~= -1) -- folded
feed("'a") feed("'a")
eq(-1, funcs.foldclosed('.')) eq(-1, funcs.foldclosed('.'))
feed("zc") feed('zc')
assert(funcs.foldclosed('.') ~= -1) -- folded assert(funcs.foldclosed('.') ~= -1) -- folded
-- TODO: remove this workaround after fixing #15873 -- TODO: remove this workaround after fixing #15873
feed("k`a") feed('k`a')
eq(-1, funcs.foldclosed('.')) eq(-1, funcs.foldclosed('.'))
feed("zc") feed('zc')
assert(funcs.foldclosed('.') ~= -1) -- folded assert(funcs.foldclosed('.') ~= -1) -- folded
feed("kg'a") feed("kg'a")
eq(-1, funcs.foldclosed('.')) eq(-1, funcs.foldclosed('.'))
feed("zc") feed('zc')
assert(funcs.foldclosed('.') ~= -1) -- folded assert(funcs.foldclosed('.') ~= -1) -- folded
feed("kg`a") feed('kg`a')
eq(-1, funcs.foldclosed('.')) eq(-1, funcs.foldclosed('.'))
end) end)
it("do not open folds when moving to them doesn't move the cursor", function() it("do not open folds when moving to them doesn't move the cursor", function()
command("edit " .. file1) command('edit ' .. file1)
feed("jzfG") -- Fold from the second line to the end feed('jzfG') -- Fold from the second line to the end
assert(funcs.foldclosed('.') == 2) -- folded assert(funcs.foldclosed('.') == 2) -- folded
feed("ma") feed('ma')
feed("'a") feed("'a")
feed("`a") feed('`a')
feed("g'a") feed("g'a")
feed("g`a") feed('g`a')
-- should still be folded -- should still be folded
eq(2, funcs.foldclosed('.')) eq(2, funcs.foldclosed('.'))
end) end)
it("getting '{ '} '( ') does not move cursor", function() it("getting '{ '} '( ') does not move cursor", function()
meths.buf_set_lines(0, 0, 0, true, {'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee'}) meths.buf_set_lines(0, 0, 0, true, { 'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee' })
meths.win_set_cursor(0, {2, 0}) meths.win_set_cursor(0, { 2, 0 })
funcs.getpos("'{") funcs.getpos("'{")
eq({2, 0}, meths.win_get_cursor(0)) eq({ 2, 0 }, meths.win_get_cursor(0))
funcs.getpos("'}") funcs.getpos("'}")
eq({2, 0}, meths.win_get_cursor(0)) eq({ 2, 0 }, meths.win_get_cursor(0))
funcs.getpos("'(") funcs.getpos("'(")
eq({2, 0}, meths.win_get_cursor(0)) eq({ 2, 0 }, meths.win_get_cursor(0))
funcs.getpos("')") funcs.getpos("')")
eq({2, 0}, meths.win_get_cursor(0)) eq({ 2, 0 }, meths.win_get_cursor(0))
end) end)
it('in command range does not move cursor #19248', function() it('in command range does not move cursor #19248', function()
meths.create_user_command('Test', ':', {range = true}) meths.create_user_command('Test', ':', { range = true })
meths.buf_set_lines(0, 0, 0, true, {'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee'}) meths.buf_set_lines(0, 0, 0, true, { 'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee' })
meths.win_set_cursor(0, {2, 0}) meths.win_set_cursor(0, { 2, 0 })
command([['{,'}Test]]) command([['{,'}Test]])
eq({2, 0}, meths.win_get_cursor(0)) eq({ 2, 0 }, meths.win_get_cursor(0))
end) end)
end) end)
@@ -327,16 +329,16 @@ describe('named marks view', function()
local file2 = 'Xtestfile-functional-editor-marks-2' local file2 = 'Xtestfile-functional-editor-marks-2'
local function content() local function content()
local c = {} local c = {}
for i=1,30 do for i = 1, 30 do
c[i] = i .. " line" c[i] = i .. ' line'
end end
return table.concat(c, "\n") return table.concat(c, '\n')
end end
before_each(function() before_each(function()
clear() clear()
write_file(file1, content(), false, false) write_file(file1, content(), false, false)
write_file(file2, content(), false, false) write_file(file2, content(), false, false)
command("set jumpoptions+=view") command('set jumpoptions+=view')
end) end)
after_each(function() after_each(function()
os.remove(file1) os.remove(file1)
@@ -344,12 +346,12 @@ describe('named marks view', function()
end) end)
it('is restored in normal mode but not op-pending mode', function() it('is restored in normal mode but not op-pending mode', function()
local screen = Screen.new(5, 8) local screen = Screen.new(5, 8)
screen:attach() screen:attach()
command("edit " .. file1) command('edit ' .. file1)
feed("<C-e>jWma") feed('<C-e>jWma')
feed("G'a") feed("G'a")
local expected = [[ local expected = [[
2 line | 2 line |
^3 line | ^3 line |
4 line | 4 line |
@@ -359,9 +361,9 @@ describe('named marks view', function()
8 line | 8 line |
| |
]] ]]
screen:expect({grid=expected}) screen:expect({ grid = expected })
feed("G`a") feed('G`a')
screen:expect([[ screen:expect([[
2 line | 2 line |
3 ^line | 3 ^line |
4 line | 4 line |
@@ -371,9 +373,9 @@ describe('named marks view', function()
8 line | 8 line |
| |
]]) ]])
-- not in op-pending mode #20886 -- not in op-pending mode #20886
feed("ggj=`a") feed('ggj=`a')
screen:expect([[ screen:expect([[
1 line | 1 line |
^2 line | ^2 line |
3 line | 3 line |
@@ -388,8 +390,8 @@ describe('named marks view', function()
it('is restored across files', function() it('is restored across files', function()
local screen = Screen.new(5, 5) local screen = Screen.new(5, 5)
screen:attach() screen:attach()
command("args " .. file1 .. " " .. file2) command('args ' .. file1 .. ' ' .. file2)
feed("<C-e>mA") feed('<C-e>mA')
local mark_view = [[ local mark_view = [[
^2 line | ^2 line |
3 line | 3 line |
@@ -398,7 +400,7 @@ describe('named marks view', function()
| |
]] ]]
screen:expect(mark_view) screen:expect(mark_view)
command("next") command('next')
screen:expect([[ screen:expect([[
^1 line | ^1 line |
2 line | 2 line |
@@ -410,14 +412,14 @@ describe('named marks view', function()
screen:expect(mark_view) screen:expect(mark_view)
end) end)
it('fallback to standard behavior when view can\'t be recovered', function() it("fallback to standard behavior when view can't be recovered", function()
local screen = Screen.new(10, 10) local screen = Screen.new(10, 10)
screen:attach() screen:attach()
command("edit " .. file1) command('edit ' .. file1)
feed("7GzbmaG") -- Seven lines from the top feed('7GzbmaG') -- Seven lines from the top
command("new") -- Screen size for window is now half the height can't be restored command('new') -- Screen size for window is now half the height can't be restored
feed("<C-w>p'a") feed("<C-w>p'a")
screen:expect([[ screen:expect([[
| |
~ |*3 ~ |*3
[No Name] | [No Name] |

View File

@@ -66,11 +66,11 @@ describe('meta-keys #8226 #13042', function()
command('inoremap <A-j> alt-j') command('inoremap <A-j> alt-j')
feed('i<M-l> xxx <A-j><M-h>a<A-h>') feed('i<M-l> xxx <A-j><M-h>a<A-h>')
expect('meta-l xxx alt-j') expect('meta-l xxx alt-j')
eq({ 0, 1, 14, 0, }, funcs.getpos('.')) eq({ 0, 1, 14, 0 }, funcs.getpos('.'))
-- Unmapped ALT-chord behaves as ESC+c. -- Unmapped ALT-chord behaves as ESC+c.
command('iunmap <M-l>') command('iunmap <M-l>')
feed('0i<M-l>') feed('0i<M-l>')
eq({ 0, 1, 2, 0, }, funcs.getpos('.')) eq({ 0, 1, 2, 0 }, funcs.getpos('.'))
-- Unmapped ALT-chord has same `undo` characteristics as ESC+<key> -- Unmapped ALT-chord has same `undo` characteristics as ESC+<key>
command('0,$d') command('0,$d')
feed('ahello<M-.>') feed('ahello<M-.>')
@@ -101,7 +101,7 @@ describe('meta-keys #8226 #13042', function()
eq(meta_l_seq .. 'yyy' .. meta_l_seq .. 'alt-j', exec_lua([[return _G.input_data]])) eq(meta_l_seq .. 'yyy' .. meta_l_seq .. 'alt-j', exec_lua([[return _G.input_data]]))
eq('t', eval('mode(1)')) eq('t', eval('mode(1)'))
feed('<Esc>j') feed('<Esc>j')
eq({ 0, 2, 1, 0, }, funcs.getpos('.')) eq({ 0, 2, 1, 0 }, funcs.getpos('.'))
eq('nt', eval('mode(1)')) eq('nt', eval('mode(1)'))
end) end)

View File

@@ -48,25 +48,29 @@ describe('cmdline', function()
it('redraws statusline when toggling overstrike', function() it('redraws statusline when toggling overstrike', function()
local screen = Screen.new(60, 4) local screen = Screen.new(60, 4)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
[1] = {reverse = true, bold = true}, -- StatusLine [1] = { reverse = true, bold = true }, -- StatusLine
}) })
screen:attach() screen:attach()
command('set laststatus=2 statusline=%!mode(1)') command('set laststatus=2 statusline=%!mode(1)')
feed(':') feed(':')
screen:expect{grid=[[ screen:expect {
grid = [[
| |
{0:~ }| {0:~ }|
{1:c }| {1:c }|
:^ | :^ |
]]} ]],
}
feed('<Insert>') feed('<Insert>')
screen:expect{grid=[[ screen:expect {
grid = [[
| |
{0:~ }| {0:~ }|
{1:cr }| {1:cr }|
:^ | :^ |
]]} ]],
}
end) end)
describe('history', function() describe('history', function()

View File

@@ -53,13 +53,13 @@ describe('insert-mode', function()
it('double quote is removed after hit-enter prompt #22609', function() it('double quote is removed after hit-enter prompt #22609', function()
local screen = Screen.new(60, 6) local screen = Screen.new(60, 6)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
[1] = {foreground = Screen.colors.Blue}, -- SpecialKey [1] = { foreground = Screen.colors.Blue }, -- SpecialKey
[2] = {foreground = Screen.colors.SlateBlue}, [2] = { foreground = Screen.colors.SlateBlue },
[3] = {bold = true}, -- ModeMsg [3] = { bold = true }, -- ModeMsg
[4] = {reverse = true, bold = true}, -- MsgSeparator [4] = { reverse = true, bold = true }, -- MsgSeparator
[5] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg [5] = { background = Screen.colors.Red, foreground = Screen.colors.White }, -- ErrorMsg
[6] = {foreground = Screen.colors.SeaGreen, bold = true}, -- MoreMsg [6] = { foreground = Screen.colors.SeaGreen, bold = true }, -- MoreMsg
}) })
screen:attach() screen:attach()
feed('i<C-R>') feed('i<C-R>')
@@ -187,10 +187,10 @@ describe('insert-mode', function()
it('multi-char mapping updates screen properly #25626', function() it('multi-char mapping updates screen properly #25626', function()
local screen = Screen.new(60, 6) local screen = Screen.new(60, 6)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}; -- NonText [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
[1] = {bold = true, reverse = true}; -- StatusLine [1] = { bold = true, reverse = true }, -- StatusLine
[2] = {reverse = true}; -- StatusLineNC [2] = { reverse = true }, -- StatusLineNC
[3] = {bold = true}; -- ModeMsg [3] = { bold = true }, -- ModeMsg
}) })
screen:attach() screen:attach()
command('vnew') command('vnew')
@@ -199,22 +199,26 @@ describe('insert-mode', function()
command('set timeoutlen=10000') command('set timeoutlen=10000')
command('inoremap jk <Esc>') command('inoremap jk <Esc>')
feed('i<CR>βββ<Left><Left>j') feed('i<CR>βββ<Left><Left>j')
screen:expect{grid=[[ screen:expect {
grid = [[
foo │ | foo │ |
foo │β^jβ | foo │β^jβ |
foo │{0:~ }| foo │{0:~ }|
{0:~ }│{0:~ }| {0:~ }│{0:~ }|
{2:[No Name] [+] }{1:[No Name] [+] }| {2:[No Name] [+] }{1:[No Name] [+] }|
{3:-- INSERT --} | {3:-- INSERT --} |
]]} ]],
}
feed('k') feed('k')
screen:expect{grid=[[ screen:expect {
grid = [[
foo │ | foo │ |
foo │^βββ | foo │^βββ |
foo │{0:~ }| foo │{0:~ }|
{0:~ }│{0:~ }| {0:~ }│{0:~ }|
{2:[No Name] [+] }{1:[No Name] [+] }| {2:[No Name] [+] }{1:[No Name] [+] }|
| |
]]} ]],
}
end) end)
end) end)

View File

@@ -35,12 +35,12 @@ describe('put command', function()
before_each(reset) before_each(reset)
local function visual_marks_zero() local function visual_marks_zero()
for _,v in pairs(funcs.getpos("'<")) do for _, v in pairs(funcs.getpos("'<")) do
if v ~= 0 then if v ~= 0 then
return false return false
end end
end end
for _,v in pairs(funcs.getpos("'>")) do for _, v in pairs(funcs.getpos("'>")) do
if v ~= 0 then if v ~= 0 then
return false return false
end end
@@ -51,10 +51,12 @@ describe('put command', function()
-- {{{ Where test definitions are run -- {{{ Where test definitions are run
local function run_test_variations(test_variations, extra_setup) local function run_test_variations(test_variations, extra_setup)
reset() reset()
if extra_setup then extra_setup() end if extra_setup then
extra_setup()
end
local init_contents = curbuf_contents() local init_contents = curbuf_contents()
local init_cursorpos = funcs.getcurpos() local init_cursorpos = funcs.getcurpos()
local assert_no_change = function (exception_table, after_undo) local assert_no_change = function(exception_table, after_undo)
expect(init_contents) expect(init_contents)
-- When putting the ". register forwards, undo doesn't move -- When putting the ". register forwards, undo doesn't move
-- the cursor back to where it was before. -- the cursor back to where it was before.
@@ -69,7 +71,9 @@ describe('put command', function()
for _, test in pairs(test_variations) do for _, test in pairs(test_variations) do
it(test.description, function() it(test.description, function()
if extra_setup then extra_setup() end if extra_setup then
extra_setup()
end
local orig_dotstr = funcs.getreg('.') local orig_dotstr = funcs.getreg('.')
helpers.ok(visual_marks_zero()) helpers.ok(visual_marks_zero())
-- Make sure every test starts from the same conditions -- Make sure every test starts from the same conditions
@@ -115,8 +119,13 @@ describe('put command', function()
end -- run_test_variations() end -- run_test_variations()
-- }}} -- }}}
local function create_test_defs(test_defs, command_base, command_creator, -- {{{ local function create_test_defs(
expect_base, expect_creator) test_defs,
command_base,
command_creator, -- {{{
expect_base,
expect_creator
)
local rettab = {} local rettab = {}
local exceptions local exceptions
for _, v in pairs(test_defs) do for _, v in pairs(test_defs) do
@@ -125,8 +134,7 @@ describe('put command', function()
else else
exceptions = {} exceptions = {}
end end
table.insert(rettab, table.insert(rettab, {
{
test_action = command_creator(command_base, v[1]), test_action = command_creator(command_base, v[1]),
test_assertions = expect_creator(expect_base, v[2]), test_assertions = expect_creator(expect_base, v[2]),
description = v[3], description = v[3],
@@ -146,7 +154,7 @@ describe('put command', function()
for linenum, line in pairs(funcs.split(expect_string, '\n', 1)) do for linenum, line in pairs(funcs.split(expect_string, '\n', 1)) do
local column = line:find('x') local column = line:find('x')
if column then if column then
return {linenum, column}, expect_string:gsub('x', '') return { linenum, column }, expect_string:gsub('x', '')
end end
end end
end -- find_cursor_position() }}} end -- find_cursor_position() }}}
@@ -186,7 +194,7 @@ describe('put command', function()
-- '.' command. -- '.' command.
if not (exception_table.redo_position and after_redo) then if not (exception_table.redo_position and after_redo) then
local actual_position = funcs.getcurpos() local actual_position = funcs.getcurpos()
eq(cursor_position, {actual_position[2], actual_position[5]}) eq(cursor_position, { actual_position[2], actual_position[5] })
end end
end end
end -- expect_creator() }}} end -- expect_creator() }}}
@@ -195,13 +203,13 @@ describe('put command', function()
local function copy_def(def) local function copy_def(def)
local rettab = { '', {}, '', nil } local rettab = { '', {}, '', nil }
rettab[1] = def[1] rettab[1] = def[1]
for k,v in pairs(def[2]) do for k, v in pairs(def[2]) do
rettab[2][k] = v rettab[2][k] = v
end end
rettab[3] = def[3] rettab[3] = def[3]
if def[4] then if def[4] then
rettab[4] = {} rettab[4] = {}
for k,v in pairs(def[4]) do for k, v in pairs(def[4]) do
rettab[4][k] = v rettab[4][k] = v
end end
end end
@@ -211,52 +219,52 @@ describe('put command', function()
local normal_command_defs = { local normal_command_defs = {
{ {
'p', 'p',
{cursor_after = false, put_backwards = false, dot_register = false}, { cursor_after = false, put_backwards = false, dot_register = false },
'pastes after cursor with p', 'pastes after cursor with p',
}, },
{ {
'gp', 'gp',
{cursor_after = true, put_backwards = false, dot_register = false}, { cursor_after = true, put_backwards = false, dot_register = false },
'leaves cursor after text with gp', 'leaves cursor after text with gp',
}, },
{ {
'".p', '".p',
{cursor_after = false, put_backwards = false, dot_register = true}, { cursor_after = false, put_backwards = false, dot_register = true },
'works with the ". register', 'works with the ". register',
}, },
{ {
'".gp', '".gp',
{cursor_after = true, put_backwards = false, dot_register = true}, { cursor_after = true, put_backwards = false, dot_register = true },
'gp works with the ". register', 'gp works with the ". register',
{redo_position = true}, { redo_position = true },
}, },
{ {
'P', 'P',
{cursor_after = false, put_backwards = true, dot_register = false}, { cursor_after = false, put_backwards = true, dot_register = false },
'pastes before cursor with P', 'pastes before cursor with P',
}, },
{ {
'gP', 'gP',
{cursor_after = true, put_backwards = true, dot_register = false}, { cursor_after = true, put_backwards = true, dot_register = false },
'gP pastes before cursor and leaves cursor after text', 'gP pastes before cursor and leaves cursor after text',
}, },
{ {
'".P', '".P',
{cursor_after = false, put_backwards = true, dot_register = true}, { cursor_after = false, put_backwards = true, dot_register = true },
'P works with ". register', 'P works with ". register',
}, },
{ {
'".gP', '".gP',
{cursor_after = true, put_backwards = true, dot_register = true}, { cursor_after = true, put_backwards = true, dot_register = true },
'gP works with ". register', 'gP works with ". register',
{redo_position = true}, { redo_position = true },
}, },
} }
-- Add a definition applying a count for each definition above. -- Add a definition applying a count for each definition above.
-- Could do this for each transformation (p -> P, p -> gp etc), but I think -- Could do this for each transformation (p -> P, p -> gp etc), but I think
-- it's neater this way (balance between being explicit and too verbose). -- it's neater this way (balance between being explicit and too verbose).
for i = 1,#normal_command_defs do for i = 1, #normal_command_defs do
local cur = normal_command_defs[i] local cur = normal_command_defs[i]
-- Make modified copy of current definition that includes a count. -- Make modified copy of current definition that includes a count.
@@ -279,35 +287,36 @@ describe('put command', function()
local ex_command_defs = { local ex_command_defs = {
{ {
'put', 'put',
{put_backwards = false, dot_register = false}, { put_backwards = false, dot_register = false },
'pastes linewise forwards with :put', 'pastes linewise forwards with :put',
}, },
{ {
'put!', 'put!',
{put_backwards = true, dot_register = false}, { put_backwards = true, dot_register = false },
'pastes linewise backwards with :put!', 'pastes linewise backwards with :put!',
}, },
{ {
'put .', 'put .',
{put_backwards = false, dot_register = true}, { put_backwards = false, dot_register = true },
'pastes linewise with the dot register', 'pastes linewise with the dot register',
}, },
{ {
'put! .', 'put! .',
{put_backwards = true, dot_register = true}, { put_backwards = true, dot_register = true },
'pastes linewise backwards with the dot register', 'pastes linewise backwards with the dot register',
}, },
} }
local function non_dotdefs(def_table) local function non_dotdefs(def_table)
return filter(function(d) return not d[2].dot_register end, def_table) return filter(function(d)
return not d[2].dot_register
end, def_table)
end end
-- }}} -- }}}
-- Conversion functions {{{ -- Conversion functions {{{
local function convert_charwise(expect_base, conversion_table, local function convert_charwise(expect_base, conversion_table, virtualedit_end, visual_put)
virtualedit_end, visual_put)
expect_base = dedent(expect_base) expect_base = dedent(expect_base)
-- There is no difference between 'P' and 'p' when VIsual_active -- There is no difference between 'P' and 'p' when VIsual_active
if not visual_put then if not visual_put then
@@ -324,7 +333,7 @@ describe('put command', function()
end end
if conversion_table.count > 1 then if conversion_table.count > 1 then
local rep_string = 'test_string"' local rep_string = 'test_string"'
local extra_puts = rep_string:rep(conversion_table.count - 1) local extra_puts = rep_string:rep(conversion_table.count - 1)
expect_base = expect_base:gsub('test_stringx"', extra_puts .. 'test_stringx"') expect_base = expect_base:gsub('test_stringx"', extra_puts .. 'test_stringx"')
end end
if conversion_table.cursor_after then if conversion_table.cursor_after then
@@ -395,7 +404,7 @@ describe('put command', function()
indent = '' indent = ''
end end
local rep_string = indent .. p_str .. '\n' local rep_string = indent .. p_str .. '\n'
local extra_puts = rep_string:rep(conversion_table.count - 1) local extra_puts = rep_string:rep(conversion_table.count - 1)
local orig_string, new_string local orig_string, new_string
if conversion_table.cursor_after then if conversion_table.cursor_after then
orig_string = indent .. p_str .. '\nx' orig_string = indent .. p_str .. '\nx'
@@ -420,8 +429,13 @@ describe('put command', function()
return orig_line:sub(1, prev_end - 1) .. 'x' .. orig_line:sub(prev_end) return orig_line:sub(1, prev_end - 1) .. 'x' .. orig_line:sub(prev_end)
end end
local function convert_blockwise(expect_base, conversion_table, visual, local function convert_blockwise(
use_b, trailing_whitespace) expect_base,
conversion_table,
visual,
use_b,
trailing_whitespace
)
expect_base = dedent(expect_base) expect_base = dedent(expect_base)
local p_str = 'test_string"' local p_str = 'test_string"'
if use_b then if use_b then
@@ -452,11 +466,9 @@ describe('put command', function()
if conversion_table.count and conversion_table.count > 1 then if conversion_table.count and conversion_table.count > 1 then
local p_pattern = p_str:gsub('%.', '%%.') local p_pattern = p_str:gsub('%.', '%%.')
expect_base = expect_base:gsub(p_pattern, expect_base = expect_base:gsub(p_pattern, p_str:rep(conversion_table.count))
p_str:rep(conversion_table.count)) expect_base =
expect_base = expect_base:gsub('test_stringx([b".])', expect_base:gsub('test_stringx([b".])', p_str:rep(conversion_table.count - 1) .. '%0')
p_str:rep(conversion_table.count - 1)
.. '%0')
end end
if conversion_table.cursor_after then if conversion_table.cursor_after then
@@ -496,8 +508,13 @@ describe('put command', function()
-- }}} -- }}}
-- Convenience functions {{{ -- Convenience functions {{{
local function run_normal_mode_tests(test_string, base_map, extra_setup, local function run_normal_mode_tests(
virtualedit_end, selection_string) test_string,
base_map,
extra_setup,
virtualedit_end,
selection_string
)
local function convert_closure(e, c) local function convert_closure(e, c)
return convert_charwise(e, c, virtualedit_end, selection_string) return convert_charwise(e, c, virtualedit_end, selection_string)
end end
@@ -532,8 +549,12 @@ describe('put command', function()
local function run_linewise_tests(expect_base, base_command, extra_setup) local function run_linewise_tests(expect_base, base_command, extra_setup)
local linewise_test_defs = create_test_defs( local linewise_test_defs = create_test_defs(
ex_command_defs, base_command, ex_command_defs,
create_put_action, expect_base, convert_linewiseer) base_command,
create_put_action,
expect_base,
convert_linewiseer
)
run_test_variations(linewise_test_defs, extra_setup) run_test_variations(linewise_test_defs, extra_setup)
end -- run_linewise_tests() end -- run_linewise_tests()
-- }}} -- }}}
@@ -545,7 +566,8 @@ describe('put command', function()
Line of words 2]] Line of words 2]]
run_normal_mode_tests(expect_string, 'p') run_normal_mode_tests(expect_string, 'p')
run_linewise_tests([[ run_linewise_tests(
[[
Line of words 1 Line of words 1
xtest_string" xtest_string"
Line of words 2]], Line of words 2]],
@@ -585,11 +607,12 @@ describe('put command', function()
run_test_variations( run_test_variations(
create_test_defs( create_test_defs(
linewise_put_defs, linewise_put_defs,
'put a', create_put_action, 'put a',
base_expect_string, convert_linewiseer create_put_action,
base_expect_string,
convert_linewiseer
) )
) )
end) end)
describe('blockwise register', function() describe('blockwise register', function()
@@ -600,18 +623,13 @@ describe('put command', function()
test_stringb]] test_stringb]]
local function expect_block_creator(expect_base, conversion_table) local function expect_block_creator(expect_base, conversion_table)
return expect_creator(function(e,c) return convert_blockwise(e,c,nil,true) end, return expect_creator(function(e, c)
expect_base, conversion_table) return convert_blockwise(e, c, nil, true)
end, expect_base, conversion_table)
end end
run_test_variations( run_test_variations(
create_test_defs( create_test_defs(blockwise_put_defs, '"bp', create_p_action, test_base, expect_block_creator)
blockwise_put_defs,
'"bp',
create_p_action,
test_base,
expect_block_creator
)
) )
end) end)
@@ -632,17 +650,17 @@ describe('put command', function()
describe('linewise paste with autoindent', function() describe('linewise paste with autoindent', function()
-- luacheck: ignore -- luacheck: ignore
run_linewise_tests([[ run_linewise_tests(
[[
Line of words 1 Line of words 1
Line of words 2 Line of words 2
xtest_string"]], xtest_string"]],
'put' 'put',
,
function() function()
funcs.setline('$', ' Line of words 2') funcs.setline('$', ' Line of words 2')
-- Set curswant to '8' to be at the end of the tab character -- Set curswant to '8' to be at the end of the tab character
-- This is where the cursor is put back after the 'u' command. -- This is where the cursor is put back after the 'u' command.
funcs.setpos('.', {0, 2, 1, 0, 8}) funcs.setpos('.', { 0, 2, 1, 0, 8 })
command('set autoindent') command('set autoindent')
end end
) )
@@ -655,7 +673,7 @@ describe('put command', function()
run_normal_mode_tests(test_string, 'p', function() run_normal_mode_tests(test_string, 'p', function()
funcs.setline('$', ' Line of words 2') funcs.setline('$', ' Line of words 2')
command('setlocal virtualedit=all') command('setlocal virtualedit=all')
funcs.setpos('.', {0, 2, 1, 2, 3}) funcs.setpos('.', { 0, 2, 1, 2, 3 })
end) end)
end) end)
@@ -667,7 +685,7 @@ describe('put command', function()
run_normal_mode_tests(test_string, 'p', function() run_normal_mode_tests(test_string, 'p', function()
funcs.setline('$', ' Line of words 2') funcs.setline('$', ' Line of words 2')
command('setlocal virtualedit=all') command('setlocal virtualedit=all')
funcs.setpos('.', {0, 1, 16, 1, 17}) funcs.setpos('.', { 0, 1, 16, 1, 17 })
end, true) end, true)
end) end)
@@ -679,12 +697,10 @@ describe('put command', function()
run_normal_mode_tests(test_string, 'v2ep', nil, nil, 'Line of') run_normal_mode_tests(test_string, 'v2ep', nil, nil, 'Line of')
end) end)
describe('over trailing newline', function() describe('over trailing newline', function()
local test_string = 'Line of test_stringx"Line of words 2' local test_string = 'Line of test_stringx"Line of words 2'
run_normal_mode_tests(test_string, 'v$p', function() run_normal_mode_tests(test_string, 'v$p', function()
funcs.setpos('.', {0, 1, 9, 0, 9}) funcs.setpos('.', { 0, 1, 9, 0, 9 })
end, end, nil, 'words 1\n')
nil,
'words 1\n')
end) end)
describe('linewise mode', function() describe('linewise mode', function()
local test_string = [[ local test_string = [[
@@ -693,8 +709,7 @@ describe('put command', function()
local function expect_vis_linewise(expect_base, conversion_table) local function expect_vis_linewise(expect_base, conversion_table)
return expect_creator(function(e, c) return expect_creator(function(e, c)
return convert_linewise(e, c, nil, nil) return convert_linewise(e, c, nil, nil)
end, end, expect_base, conversion_table)
expect_base, conversion_table)
end end
run_test_variations( run_test_variations(
create_test_defs( create_test_defs(
@@ -704,15 +719,16 @@ describe('put command', function()
test_string, test_string,
expect_vis_linewise expect_vis_linewise
), ),
function() funcs.setpos('.', {0, 1, 1, 0, 1}) end function()
funcs.setpos('.', { 0, 1, 1, 0, 1 })
end
) )
describe('with whitespace at bol', function() describe('with whitespace at bol', function()
local function expect_vis_lineindented(expect_base, conversion_table) local function expect_vis_lineindented(expect_base, conversion_table)
local test_expect = expect_creator(function(e, c) local test_expect = expect_creator(function(e, c)
return convert_linewise(e, c, nil, nil, ' ') return convert_linewise(e, c, nil, nil, ' ')
end, end, expect_base, conversion_table)
expect_base, conversion_table)
return function(exception_table, after_redo) return function(exception_table, after_redo)
test_expect(exception_table, after_redo) test_expect(exception_table, after_redo)
if not conversion_table.put_backwards then if not conversion_table.put_backwards then
@@ -737,7 +753,6 @@ describe('put command', function()
end end
) )
end) end)
end) end)
describe('blockwise visual mode', function() describe('blockwise visual mode', function()
@@ -747,10 +762,10 @@ describe('put command', function()
local function expect_block_creator(expect_base, conversion_table) local function expect_block_creator(expect_base, conversion_table)
local test_expect = expect_creator(function(e, c) local test_expect = expect_creator(function(e, c)
return convert_blockwise(e, c, true) return convert_blockwise(e, c, true)
end, expect_base, conversion_table) end, expect_base, conversion_table)
return function(e,c) return function(e, c)
test_expect(e,c) test_expect(e, c)
if not conversion_table.put_backwards then if not conversion_table.put_backwards then
eq('Lin\nLin', funcs.getreg('"')) eq('Lin\nLin', funcs.getreg('"'))
end end
@@ -758,28 +773,26 @@ describe('put command', function()
end end
local select_down_test_defs = create_test_defs( local select_down_test_defs = create_test_defs(
normal_command_defs, normal_command_defs,
'<C-v>jllp', '<C-v>jllp',
create_p_action, create_p_action,
test_base, test_base,
expect_block_creator expect_block_creator
) )
run_test_variations(select_down_test_defs) run_test_variations(select_down_test_defs)
-- Undo and redo of a visual block put leave the cursor in the top -- Undo and redo of a visual block put leave the cursor in the top
-- left of the visual block area no matter where the cursor was -- left of the visual block area no matter where the cursor was
-- when it started. -- when it started.
local undo_redo_no = map(function(table) local undo_redo_no = map(function(table)
local rettab = copy_def(table) local rettab = copy_def(table)
if not rettab[4] then if not rettab[4] then
rettab[4] = {} rettab[4] = {}
end end
rettab[4].undo_position = true rettab[4].undo_position = true
rettab[4].redo_position = true rettab[4].redo_position = true
return rettab return rettab
end, end, normal_command_defs)
normal_command_defs)
-- Selection direction doesn't matter -- Selection direction doesn't matter
run_test_variations( run_test_variations(
@@ -790,7 +803,9 @@ describe('put command', function()
test_base, test_base,
expect_block_creator expect_block_creator
), ),
function() funcs.setpos('.', {0, 2, 1, 0, 1}) end function()
funcs.setpos('.', { 0, 2, 1, 0, 1 })
end
) )
describe('blockwise cursor after undo', function() describe('blockwise cursor after undo', function()
@@ -800,62 +815,45 @@ describe('put command', function()
-- the same pattern as everything else. -- the same pattern as everything else.
-- Here we fix this by directly checking the undo/redo position -- Here we fix this by directly checking the undo/redo position
-- in the test_assertions of our test definitions. -- in the test_assertions of our test definitions.
local function assertion_creator(_,_) local function assertion_creator(_, _)
return function(_,_) return function(_, _)
feed('u') feed('u')
-- Have to use feed('u') here to set curswant, because -- Have to use feed('u') here to set curswant, because
-- ex_undo() doesn't do that. -- ex_undo() doesn't do that.
eq({0, 1, 1, 0, 1}, funcs.getcurpos()) eq({ 0, 1, 1, 0, 1 }, funcs.getcurpos())
feed('<C-r>') feed('<C-r>')
eq({0, 1, 1, 0, 1}, funcs.getcurpos()) eq({ 0, 1, 1, 0, 1 }, funcs.getcurpos())
end end
end end
run_test_variations( run_test_variations(
create_test_defs( create_test_defs(undo_redo_no, '<C-v>kllp', create_p_action, test_base, assertion_creator),
undo_redo_no, function()
'<C-v>kllp', funcs.setpos('.', { 0, 2, 1, 0, 1 })
create_p_action, end
test_base,
assertion_creator
),
function() funcs.setpos('.', {0, 2, 1, 0, 1}) end
) )
end) end)
end) end)
describe("with 'virtualedit'", function() describe("with 'virtualedit'", function()
describe('splitting a tab character', function() describe('splitting a tab character', function()
local base_expect_string = [[ local base_expect_string = [[
Line of words 1 Line of words 1
test_stringx" Line of words 2]] test_stringx" Line of words 2]]
run_normal_mode_tests( run_normal_mode_tests(base_expect_string, 'vp', function()
base_expect_string, funcs.setline('$', ' Line of words 2')
'vp', command('setlocal virtualedit=all')
function() funcs.setpos('.', { 0, 2, 1, 2, 3 })
funcs.setline('$', ' Line of words 2') end, nil, ' ')
command('setlocal virtualedit=all')
funcs.setpos('.', {0, 2, 1, 2, 3})
end,
nil,
' '
)
end) end)
describe('after end of line', function() describe('after end of line', function()
local base_expect_string = [[ local base_expect_string = [[
Line of words 1 test_stringx" Line of words 1 test_stringx"
Line of words 2]] Line of words 2]]
run_normal_mode_tests( run_normal_mode_tests(base_expect_string, 'vp', function()
base_expect_string, command('setlocal virtualedit=all')
'vp', funcs.setpos('.', { 0, 1, 16, 2, 18 })
function() end, true, ' ')
command('setlocal virtualedit=all')
funcs.setpos('.', {0, 1, 16, 2, 18})
end,
true,
' '
)
end) end)
end) end)
end) end)
@@ -873,9 +871,12 @@ describe('put command', function()
Line of words 1 Line of words 1
Line of words 2]]) Line of words 2]])
feed('u1go<C-v>j".p') feed('u1go<C-v>j".p')
eq([[ eq(
[[
ine of words 1 ine of words 1
ine of words 2]], curbuf_contents()) ine of words 2]],
curbuf_contents()
)
end) end)
local screen local screen
@@ -891,33 +892,42 @@ describe('put command', function()
end end
helpers.ok(not screen.bell and not screen.visualbell) helpers.ok(not screen.bell and not screen.visualbell)
actions() actions()
screen:expect{condition=function() screen:expect {
if should_ring then condition = function()
if not screen.bell and not screen.visualbell then if should_ring then
error('Bell was not rung after action') if not screen.bell and not screen.visualbell then
error('Bell was not rung after action')
end
else
if screen.bell or screen.visualbell then
error('Bell was rung after action')
end
end end
else end,
if screen.bell or screen.visualbell then unchanged = not should_ring,
error('Bell was rung after action') }
end
end
end, unchanged=(not should_ring)}
screen.bell = false screen.bell = false
screen.visualbell = false screen.visualbell = false
end end
it('should not ring the bell with gp at end of line', function() it('should not ring the bell with gp at end of line', function()
bell_test(function() feed('$".gp') end) bell_test(function()
feed('$".gp')
end)
-- Even if the last character is a multibyte character. -- Even if the last character is a multibyte character.
reset() reset()
funcs.setline(1, 'helloม') funcs.setline(1, 'helloม')
bell_test(function() feed('$".gp') end) bell_test(function()
feed('$".gp')
end)
end) end)
it('should not ring the bell with gp and end of file', function() it('should not ring the bell with gp and end of file', function()
funcs.setpos('.', {0, 2, 1, 0}) funcs.setpos('.', { 0, 2, 1, 0 })
bell_test(function() feed('$vl".gp') end) bell_test(function()
feed('$vl".gp')
end)
end) end)
it('should ring the bell when deleting if not appropriate', function() it('should ring the bell when deleting if not appropriate', function()
@@ -926,7 +936,9 @@ describe('put command', function()
expect([[ expect([[
ine of words 1 ine of words 1
Line of words 2]]) Line of words 2]])
bell_test(function() feed('".P') end, true) bell_test(function()
feed('".P')
end, true)
end) end)
it('should restore cursor position after undo of ".p', function() it('should restore cursor position after undo of ".p', function()
@@ -946,4 +958,3 @@ describe('put command', function()
end) end)
end) end)
end) end)

View File

@@ -8,10 +8,7 @@ describe('search (/)', function()
before_each(clear) before_each(clear)
it('fails with huge column (%c) value #9930', function() it('fails with huge column (%c) value #9930', function()
eq([[Vim:E951: \% value too large]], eq([[Vim:E951: \% value too large]], pcall_err(command, '/\\v%18446744071562067968c'))
pcall_err(command, "/\\v%18446744071562067968c")) eq([[Vim:E951: \% value too large]], pcall_err(command, '/\\v%2147483648c'))
eq([[Vim:E951: \% value too large]],
pcall_err(command, "/\\v%2147483648c"))
end) end)
end) end)

View File

@@ -58,7 +58,9 @@ describe('tabpage', function()
end) end)
it('no segfault with strange WinClosed autocommand #20290', function() it('no segfault with strange WinClosed autocommand #20290', function()
pcall(exec, [[ pcall(
exec,
[[
set nohidden set nohidden
edit Xa edit Xa
split Xb split Xb
@@ -66,45 +68,46 @@ describe('tabpage', function()
new new
autocmd WinClosed * tabprev | bwipe! autocmd WinClosed * tabprev | bwipe!
close close
]]) ]]
)
assert_alive() assert_alive()
end) end)
it('nvim_win_close and nvim_win_hide update tabline #20285', function() it('nvim_win_close and nvim_win_hide update tabline #20285', function()
eq(1, #meths.list_tabpages()) eq(1, #meths.list_tabpages())
eq({1, 1}, funcs.win_screenpos(0)) eq({ 1, 1 }, funcs.win_screenpos(0))
local win1 = curwin().id local win1 = curwin().id
command('tabnew') command('tabnew')
eq(2, #meths.list_tabpages()) eq(2, #meths.list_tabpages())
eq({2, 1}, funcs.win_screenpos(0)) eq({ 2, 1 }, funcs.win_screenpos(0))
local win2 = curwin().id local win2 = curwin().id
meths.win_close(win1, true) meths.win_close(win1, true)
eq(win2, curwin().id) eq(win2, curwin().id)
eq(1, #meths.list_tabpages()) eq(1, #meths.list_tabpages())
eq({1, 1}, funcs.win_screenpos(0)) eq({ 1, 1 }, funcs.win_screenpos(0))
command('tabnew') command('tabnew')
eq(2, #meths.list_tabpages()) eq(2, #meths.list_tabpages())
eq({2, 1}, funcs.win_screenpos(0)) eq({ 2, 1 }, funcs.win_screenpos(0))
local win3 = curwin().id local win3 = curwin().id
meths.win_hide(win2) meths.win_hide(win2)
eq(win3, curwin().id) eq(win3, curwin().id)
eq(1, #meths.list_tabpages()) eq(1, #meths.list_tabpages())
eq({1, 1}, funcs.win_screenpos(0)) eq({ 1, 1 }, funcs.win_screenpos(0))
end) end)
it('switching tabpage after setting laststatus=3 #19591', function() it('switching tabpage after setting laststatus=3 #19591', function()
local screen = Screen.new(40, 8) local screen = Screen.new(40, 8)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}, [0] = { bold = true, foreground = Screen.colors.Blue },
[1] = {bold = true, reverse = true}, -- StatusLine [1] = { bold = true, reverse = true }, -- StatusLine
[2] = {reverse = true}, -- TabLineFill [2] = { reverse = true }, -- TabLineFill
[3] = {bold = true}, -- TabLineSel [3] = { bold = true }, -- TabLineSel
[4] = {background = Screen.colors.LightGrey, underline = true}, -- TabLine [4] = { background = Screen.colors.LightGrey, underline = true }, -- TabLine
[5] = {bold = true, foreground = Screen.colors.Magenta}, [5] = { bold = true, foreground = Screen.colors.Magenta },
}) })
screen:attach() screen:attach()
@@ -130,7 +133,7 @@ describe('tabpage', function()
]]) ]])
end) end)
it(":tabmove handles modifiers and addr", function() it(':tabmove handles modifiers and addr', function()
command('tabnew | tabnew | tabnew') command('tabnew | tabnew | tabnew')
eq(4, funcs.nvim_tabpage_get_number(0)) eq(4, funcs.nvim_tabpage_get_number(0))
command(' silent :keepalt :: ::: silent! - tabmove') command(' silent :keepalt :: ::: silent! - tabmove')

View File

@@ -21,15 +21,23 @@ describe('u CTRL-R g- g+', function()
before_each(clear) before_each(clear)
local function create_history(num_steps) local function create_history(num_steps)
if num_steps == 0 then return end if num_steps == 0 then
return
end
insert('1') insert('1')
if num_steps == 1 then return end if num_steps == 1 then
return
end
feed('o2<esc>') feed('o2<esc>')
feed('o3<esc>') feed('o3<esc>')
feed('u') feed('u')
if num_steps == 2 then return end if num_steps == 2 then
return
end
feed('o4<esc>') feed('o4<esc>')
if num_steps == 3 then return end if num_steps == 3 then
return
end
feed('u') feed('u')
end end
@@ -57,13 +65,23 @@ describe('u CTRL-R g- g+', function()
undo_and_redo(2, 'g-', 'g+', '1') undo_and_redo(2, 'g-', 'g+', '1')
end) end)
it('undoes properly around a branch point', function() it('undoes properly around a branch point', function()
undo_and_redo(3, 'u', '<C-r>', [[ undo_and_redo(
3,
'u',
'<C-r>',
[[
1 1
2]]) 2]]
undo_and_redo(3, 'g-', 'g+', [[ )
undo_and_redo(
3,
'g-',
'g+',
[[
1 1
2 2
3]]) 3]]
)
end) end)
it('can find the previous sequence after undoing to a branch', function() it('can find the previous sequence after undoing to a branch', function()
undo_and_redo(4, 'u', '<C-r>', '1') undo_and_redo(4, 'u', '<C-r>', '1')

View File

@@ -29,8 +29,7 @@ local cmdtest = function(cmd, prep, ret1)
-- Used to crash because this invokes history processing which uses -- Used to crash because this invokes history processing which uses
-- hist_char2type which after fdb68e35e4c729c7ed097d8ade1da29e5b3f4b31 -- hist_char2type which after fdb68e35e4c729c7ed097d8ade1da29e5b3f4b31
-- crashed. -- crashed.
it(cmd .. 's' .. prep .. ' the current line by default when feeding', it(cmd .. 's' .. prep .. ' the current line by default when feeding', function()
function()
feed(':' .. cmd .. '\nabc\ndef\n.\n') feed(':' .. cmd .. '\nabc\ndef\n.\n')
eq(ret1, buffer_contents()) eq(ret1, buffer_contents())
end) end)
@@ -63,8 +62,8 @@ describe('the first line is redrawn correctly after inserting text in an empty b
clear() clear()
screen = Screen.new(20, 8) screen = Screen.new(20, 8)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue}, [1] = { bold = true, foreground = Screen.colors.Blue },
[2] = {bold = true, reverse = true}, [2] = { bold = true, reverse = true },
}) })
screen:attach() screen:attach()
end) end)

View File

@@ -1,30 +1,30 @@
local helpers = require("test.functional.helpers")(after_each) local helpers = require('test.functional.helpers')(after_each)
local eq, command, funcs = helpers.eq, helpers.command, helpers.funcs local eq, command, funcs = helpers.eq, helpers.command, helpers.funcs
local ok = helpers.ok local ok = helpers.ok
local clear = helpers.clear local clear = helpers.clear
describe(":argument", function() describe(':argument', function()
before_each(function() before_each(function()
clear() clear()
end) end)
it("does not restart :terminal buffer", function() it('does not restart :terminal buffer', function()
command("terminal") command('terminal')
helpers.feed([[<C-\><C-N>]]) helpers.feed([[<C-\><C-N>]])
command("argadd") command('argadd')
helpers.feed([[<C-\><C-N>]]) helpers.feed([[<C-\><C-N>]])
local bufname_before = funcs.bufname("%") local bufname_before = funcs.bufname('%')
local bufnr_before = funcs.bufnr("%") local bufnr_before = funcs.bufnr('%')
helpers.ok(nil ~= string.find(bufname_before, "^term://")) -- sanity helpers.ok(nil ~= string.find(bufname_before, '^term://')) -- sanity
command("argument 1") command('argument 1')
helpers.feed([[<C-\><C-N>]]) helpers.feed([[<C-\><C-N>]])
local bufname_after = funcs.bufname("%") local bufname_after = funcs.bufname('%')
local bufnr_after = funcs.bufnr("%") local bufnr_after = funcs.bufnr('%')
eq("["..bufname_before.."]", helpers.eval('trim(execute("args"))')) eq('[' .. bufname_before .. ']', helpers.eval('trim(execute("args"))'))
ok(funcs.line('$') > 1) ok(funcs.line('$') > 1)
eq(bufname_before, bufname_after) eq(bufname_before, bufname_after)
eq(bufnr_before, bufnr_after) eq(bufnr_before, bufnr_after)
end) end)
end) end)

View File

@@ -21,18 +21,30 @@ local directories = {
} }
-- Shorthand writing to get the current working directory -- Shorthand writing to get the current working directory
local cwd = function(...) return call('getcwd', ...) end -- effective working dir local cwd = function(...)
local wcwd = function() return cwd(0) end -- window dir return call('getcwd', ...)
local tcwd = function() return cwd(-1, 0) end -- tab dir end -- effective working dir
local wcwd = function()
return cwd(0)
end -- window dir
local tcwd = function()
return cwd(-1, 0)
end -- tab dir
-- Same, except these tell us if there is a working directory at all -- Same, except these tell us if there is a working directory at all
local lwd = function(...) return call('haslocaldir', ...) end -- effective working dir local lwd = function(...)
local wlwd = function() return lwd(0) end -- window dir return call('haslocaldir', ...)
local tlwd = function() return lwd(-1, 0) end -- tab dir end -- effective working dir
local wlwd = function()
return lwd(0)
end -- window dir
local tlwd = function()
return lwd(-1, 0)
end -- tab dir
--local glwd = function() return eval('haslocaldir(-1, -1)') end -- global dir --local glwd = function() return eval('haslocaldir(-1, -1)') end -- global dir
-- Test both the `cd` and `chdir` variants -- Test both the `cd` and `chdir` variants
for _, cmd in ipairs {'cd', 'chdir'} do for _, cmd in ipairs { 'cd', 'chdir' } do
describe(':' .. cmd, function() describe(':' .. cmd, function()
before_each(function() before_each(function()
clear() clear()
@@ -168,23 +180,23 @@ for _, cmd in ipairs {'cd', 'chdir'} do
-- Create a new tab first and verify that is has the same working dir -- Create a new tab first and verify that is has the same working dir
command('tabnew') command('tabnew')
eq(globalDir, cwd()) eq(globalDir, cwd())
eq(globalDir, tcwd()) -- has no tab-local directory eq(globalDir, tcwd()) -- has no tab-local directory
eq(0, tlwd()) eq(0, tlwd())
eq(globalDir, wcwd()) -- has no window-local directory eq(globalDir, wcwd()) -- has no window-local directory
eq(0, wlwd()) eq(0, wlwd())
-- Change tab-local working directory and verify it is different -- Change tab-local working directory and verify it is different
command('silent t' .. cmd .. ' ' .. directories.tab) command('silent t' .. cmd .. ' ' .. directories.tab)
eq(globalDir .. pathsep .. directories.tab, cwd()) eq(globalDir .. pathsep .. directories.tab, cwd())
eq(cwd(), tcwd()) -- working directory matches tab directory eq(cwd(), tcwd()) -- working directory matches tab directory
eq(1, tlwd()) eq(1, tlwd())
eq(cwd(), wcwd()) -- still no window-directory eq(cwd(), wcwd()) -- still no window-directory
eq(0, wlwd()) eq(0, wlwd())
-- Create a new window in this tab to test `:lcd` -- Create a new window in this tab to test `:lcd`
command('new') command('new')
eq(1, tlwd()) -- Still tab-local working directory eq(1, tlwd()) -- Still tab-local working directory
eq(0, wlwd()) -- Still no window-local working directory eq(0, wlwd()) -- Still no window-local working directory
eq(globalDir .. pathsep .. directories.tab, cwd()) eq(globalDir .. pathsep .. directories.tab, cwd())
command('silent l' .. cmd .. ' ../' .. directories.window) command('silent l' .. cmd .. ' ../' .. directories.window)
eq(globalDir .. pathsep .. directories.window, cwd()) eq(globalDir .. pathsep .. directories.window, cwd())
@@ -193,13 +205,13 @@ for _, cmd in ipairs {'cd', 'chdir'} do
-- Verify the first window still has the tab local directory -- Verify the first window still has the tab local directory
command('wincmd w') command('wincmd w')
eq(globalDir .. pathsep .. directories.tab, cwd()) eq(globalDir .. pathsep .. directories.tab, cwd())
eq(globalDir .. pathsep .. directories.tab, tcwd()) eq(globalDir .. pathsep .. directories.tab, tcwd())
eq(0, wlwd()) -- No window-local directory eq(0, wlwd()) -- No window-local directory
-- Change back to initial tab and verify working directory has stayed -- Change back to initial tab and verify working directory has stayed
command('tabnext') command('tabnext')
eq(globalDir, cwd() ) eq(globalDir, cwd())
eq(0, tlwd()) eq(0, tlwd())
eq(0, wlwd()) eq(0, wlwd())
@@ -207,31 +219,31 @@ for _, cmd in ipairs {'cd', 'chdir'} do
command('silent ' .. cmd .. ' ' .. directories.global) command('silent ' .. cmd .. ' ' .. directories.global)
eq(globalDir .. pathsep .. directories.global, cwd()) eq(globalDir .. pathsep .. directories.global, cwd())
command('tabnext') command('tabnext')
eq(globalDir .. pathsep .. directories.tab, cwd()) eq(globalDir .. pathsep .. directories.tab, cwd())
eq(globalDir .. pathsep .. directories.tab, tcwd()) eq(globalDir .. pathsep .. directories.tab, tcwd())
eq(0, wlwd()) -- Still no window-local directory in this window eq(0, wlwd()) -- Still no window-local directory in this window
-- Unless the global change happened in a tab with local directory -- Unless the global change happened in a tab with local directory
command('silent ' .. cmd .. ' ..') command('silent ' .. cmd .. ' ..')
eq(globalDir, cwd() ) eq(globalDir, cwd())
eq(0 , tlwd()) eq(0, tlwd())
eq(0 , wlwd()) eq(0, wlwd())
-- Which also affects the first tab -- Which also affects the first tab
command('tabnext') command('tabnext')
eq(globalDir, cwd()) eq(globalDir, cwd())
-- But not in a window with its own local directory -- But not in a window with its own local directory
command('tabnext | wincmd w') command('tabnext | wincmd w')
eq(globalDir .. pathsep .. directories.window, cwd() ) eq(globalDir .. pathsep .. directories.window, cwd())
eq(0 , tlwd()) eq(0, tlwd())
eq(globalDir .. pathsep .. directories.window, wcwd()) eq(globalDir .. pathsep .. directories.window, wcwd())
end) end)
end) end)
end end
-- Test legal parameters for 'getcwd' and 'haslocaldir' -- Test legal parameters for 'getcwd' and 'haslocaldir'
for _, cmd in ipairs {'getcwd', 'haslocaldir'} do for _, cmd in ipairs { 'getcwd', 'haslocaldir' } do
describe(cmd..'()', function() describe(cmd .. '()', function()
before_each(function() before_each(function()
clear() clear()
end) end)
@@ -271,7 +283,7 @@ for _, cmd in ipairs {'getcwd', 'haslocaldir'} do
end) end)
end end
describe("getcwd()", function () describe('getcwd()', function()
before_each(function() before_each(function()
clear() clear()
mkdir(directories.global) mkdir(directories.global)
@@ -281,11 +293,11 @@ describe("getcwd()", function ()
helpers.rmdir(directories.global) helpers.rmdir(directories.global)
end) end)
it("returns empty string if working directory does not exist", function() it('returns empty string if working directory does not exist', function()
skip(is_os('win')) skip(is_os('win'))
command("cd "..directories.global) command('cd ' .. directories.global)
command("call delete('../"..directories.global.."', 'd')") command("call delete('../" .. directories.global .. "', 'd')")
eq("", helpers.eval("getcwd()")) eq('', helpers.eval('getcwd()'))
end) end)
it("works with 'autochdir' after local directory was set (#9892)", function() it("works with 'autochdir' after local directory was set (#9892)", function()

View File

@@ -16,24 +16,24 @@ describe('mappings with <Cmd>', function()
local tmpfile = 'X_ex_cmds_cmd_map' local tmpfile = 'X_ex_cmds_cmd_map'
local function cmdmap(lhs, rhs) local function cmdmap(lhs, rhs)
command('noremap '..lhs..' <Cmd>'..rhs..'<cr>') command('noremap ' .. lhs .. ' <Cmd>' .. rhs .. '<cr>')
command('noremap! '..lhs..' <Cmd>'..rhs..'<cr>') command('noremap! ' .. lhs .. ' <Cmd>' .. rhs .. '<cr>')
end end
before_each(function() before_each(function()
clear() clear()
screen = Screen.new(65, 8) screen = Screen.new(65, 8)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1}, [1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
[3] = {bold = true, foreground = Screen.colors.SeaGreen4}, [3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
[4] = {bold = true}, [4] = { bold = true },
[5] = {background = Screen.colors.LightGrey}, [5] = { background = Screen.colors.LightGrey },
[6] = {foreground = Screen.colors.Blue1}, [6] = { foreground = Screen.colors.Blue1 },
[7] = {bold = true, reverse = true}, [7] = { bold = true, reverse = true },
[8] = {background = Screen.colors.WebGray}, [8] = { background = Screen.colors.WebGray },
[9] = {background = Screen.colors.LightMagenta}, [9] = { background = Screen.colors.LightMagenta },
[10] = {foreground = Screen.colors.Red}, [10] = { foreground = Screen.colors.Red },
}) })
screen:attach() screen:attach()
@@ -57,7 +57,7 @@ describe('mappings with <Cmd>', function()
feed('gg') feed('gg')
cmdmap('<F8>', 'startinsert') cmdmap('<F8>', 'startinsert')
cmdmap('<F9>', 'stopinsert') cmdmap('<F9>', 'stopinsert')
command("abbr foo <Cmd>let g:y = 17<cr>bar") command('abbr foo <Cmd>let g:y = 17<cr>bar')
end) end)
after_each(function() after_each(function()
@@ -121,7 +121,7 @@ describe('mappings with <Cmd>', function()
feed('<F3>') feed('<F3>')
eq('foo…bar', eval('g:str')) eq('foo…bar', eval('g:str'))
local str = eval([["foo\<D-…>bar"]]) local str = eval([["foo\<D-…>bar"]])
command([[noremap <F3> <Cmd>let g:str = ']]..str..[['<CR>]]) command([[noremap <F3> <Cmd>let g:str = ']] .. str .. [['<CR>]])
feed('<F3>') feed('<F3>')
eq(str, eval('g:str')) eq(str, eval('g:str'))
command([[noremap <F3> <Cmd>let g:str = 'foo<D-…>bar'<CR>]]) command([[noremap <F3> <Cmd>let g:str = 'foo<D-…>bar'<CR>]])
@@ -160,7 +160,7 @@ describe('mappings with <Cmd>', function()
eq('n', eval('mode(1)')) eq('n', eval('mode(1)'))
-- operator-pending mode -- operator-pending mode
feed("d<F3>") feed('d<F3>')
eq('no', eval('m')) eq('no', eval('m'))
-- did leave operator-pending mode -- did leave operator-pending mode
eq('n', eval('mode(1)')) eq('n', eval('mode(1)'))
@@ -171,21 +171,21 @@ describe('mappings with <Cmd>', function()
eq('i', eval('mode(1)')) eq('i', eval('mode(1)'))
-- replace mode -- replace mode
feed("<Ins><F3>") feed('<Ins><F3>')
eq('R', eval('m')) eq('R', eval('m'))
eq('R', eval('mode(1)')) eq('R', eval('mode(1)'))
feed('<esc>') feed('<esc>')
eq('n', eval('mode(1)')) eq('n', eval('mode(1)'))
-- virtual replace mode -- virtual replace mode
feed("gR<F3>") feed('gR<F3>')
eq('Rv', eval('m')) eq('Rv', eval('m'))
eq('Rv', eval('mode(1)')) eq('Rv', eval('mode(1)'))
feed('<esc>') feed('<esc>')
eq('n', eval('mode(1)')) eq('n', eval('mode(1)'))
-- langmap works, but is not distinguished in mode(1) -- langmap works, but is not distinguished in mode(1)
feed(":set iminsert=1<cr>i<F3>") feed(':set iminsert=1<cr>i<F3>')
eq('i', eval('m')) eq('i', eval('m'))
eq('i', eval('mode(1)')) eq('i', eval('mode(1)'))
feed('<esc>') feed('<esc>')
@@ -212,15 +212,15 @@ describe('mappings with <Cmd>', function()
-- check v:count and v:register works -- check v:count and v:register works
feed('<F2>') feed('<F2>')
eq({'n', 0, '"'}, eval('s')) eq({ 'n', 0, '"' }, eval('s'))
feed('7<F2>') feed('7<F2>')
eq({'n', 7, '"'}, eval('s')) eq({ 'n', 7, '"' }, eval('s'))
feed('"e<F2>') feed('"e<F2>')
eq({'n', 0, 'e'}, eval('s')) eq({ 'n', 0, 'e' }, eval('s'))
feed('5"k<F2>') feed('5"k<F2>')
eq({'n', 5, 'k'}, eval('s')) eq({ 'n', 5, 'k' }, eval('s'))
feed('"+2<F2>') feed('"+2<F2>')
eq({'n', 2, '+'}, eval('s')) eq({ 'n', 2, '+' }, eval('s'))
-- text object enters visual mode -- text object enters visual mode
feed('<F7>') feed('<F7>')
@@ -249,7 +249,7 @@ describe('mappings with <Cmd>', function()
{4:-- INSERT --} | {4:-- INSERT --} |
]]) ]])
-- feedkeys were not executed immediately -- feedkeys were not executed immediately
eq({'n', 'of test text'}, eval('[m,a]')) eq({ 'n', 'of test text' }, eval('[m,a]'))
eq('i', eval('mode(1)')) eq('i', eval('mode(1)'))
feed('<esc>') feed('<esc>')
@@ -261,7 +261,7 @@ describe('mappings with <Cmd>', function()
| |
]]) ]])
-- feedkeys(..., 'x') was executed immediately, but insert mode gets aborted -- feedkeys(..., 'x') was executed immediately, but insert mode gets aborted
eq({'n', 'of alphabetatest text'}, eval('[m,b]')) eq({ 'n', 'of alphabetatest text' }, eval('[m,b]'))
eq('n', eval('mode(1)')) eq('n', eval('mode(1)'))
end) end)
@@ -270,9 +270,11 @@ describe('mappings with <Cmd>', function()
command('noremap ,f <Cmd>nosuchcommand<cr>') command('noremap ,f <Cmd>nosuchcommand<cr>')
command('noremap ,e <Cmd>throw "very error"\\| call append(1, "yy")<cr>') command('noremap ,e <Cmd>throw "very error"\\| call append(1, "yy")<cr>')
command('noremap ,m <Cmd>echoerr "The message."\\| call append(1, "zz")<cr>') command('noremap ,m <Cmd>echoerr "The message."\\| call append(1, "zz")<cr>')
command('noremap ,w <Cmd>for i in range(5)\\|if i==1\\|echoerr "Err"\\|endif\\|call append(1, i)\\|endfor<cr>') command(
'noremap ,w <Cmd>for i in range(5)\\|if i==1\\|echoerr "Err"\\|endif\\|call append(1, i)\\|endfor<cr>'
)
feed(":normal ,x<cr>") feed(':normal ,x<cr>')
screen:expect([[ screen:expect([[
^some short lines | ^some short lines |
aa | aa |
@@ -282,9 +284,9 @@ describe('mappings with <Cmd>', function()
:normal ,x | :normal ,x |
]]) ]])
eq('Vim:E492: Not an editor command: nosuchcommand', exc_exec("normal ,f")) eq('Vim:E492: Not an editor command: nosuchcommand', exc_exec('normal ,f'))
eq('very error', exc_exec("normal ,e")) eq('very error', exc_exec('normal ,e'))
eq('Vim(echoerr):The message.', exc_exec("normal ,m")) eq('Vim(echoerr):The message.', exc_exec('normal ,m'))
feed('w') feed('w')
screen:expect([[ screen:expect([[
some ^short lines | some ^short lines |
@@ -296,7 +298,7 @@ describe('mappings with <Cmd>', function()
]]) ]])
command(':%d') command(':%d')
eq('Vim(echoerr):Err', exc_exec("normal ,w")) eq('Vim(echoerr):Err', exc_exec('normal ,w'))
screen:expect([[ screen:expect([[
^ | ^ |
0 | 0 |
@@ -332,7 +334,7 @@ describe('mappings with <Cmd>', function()
-- can invoke operator, ending visual mode -- can invoke operator, ending visual mode
feed('<F5>') feed('<F5>')
eq('n', funcs.mode(1)) eq('n', funcs.mode(1))
eq({'some short l'}, funcs.getreg('a',1,1)) eq({ 'some short l' }, funcs.getreg('a', 1, 1))
-- error doesn't interrupt visual mode -- error doesn't interrupt visual mode
feed('ggvw<F6>') feed('ggvw<F6>')
@@ -393,12 +395,12 @@ describe('mappings with <Cmd>', function()
-- visual mapping in select mode restart select mode after operator -- visual mapping in select mode restart select mode after operator
feed('<F5>') feed('<F5>')
eq('s', funcs.mode(1)) eq('s', funcs.mode(1))
eq({'some short l'}, funcs.getreg('a',1,1)) eq({ 'some short l' }, funcs.getreg('a', 1, 1))
-- select mode mapping works, and does not restart select mode -- select mode mapping works, and does not restart select mode
feed('<F2>') feed('<F2>')
eq('n', funcs.mode(1)) eq('n', funcs.mode(1))
eq({'some short l'}, funcs.getreg('b',1,1)) eq({ 'some short l' }, funcs.getreg('b', 1, 1))
-- error doesn't interrupt temporary visual mode -- error doesn't interrupt temporary visual mode
feed('<esc>ggvw<c-g><F6>') feed('<esc>ggvw<c-g><F6>')
@@ -468,17 +470,16 @@ describe('mappings with <Cmd>', function()
eq('i', eval('mode(1)')) eq('i', eval('mode(1)'))
end) end)
it('works in operator-pending mode', function() it('works in operator-pending mode', function()
feed('d<F4>') feed('d<F4>')
expect([[ expect([[
lines lines
of test text]]) of test text]])
eq({'some short '}, funcs.getreg('"',1,1)) eq({ 'some short ' }, funcs.getreg('"', 1, 1))
feed('.') feed('.')
expect([[ expect([[
test text]]) test text]])
eq({'lines', 'of '}, funcs.getreg('"',1,1)) eq({ 'lines', 'of ' }, funcs.getreg('"', 1, 1))
feed('uu') feed('uu')
expect([[ expect([[
some short lines some short lines
@@ -504,7 +505,7 @@ describe('mappings with <Cmd>', function()
feed('"bd<F7>') feed('"bd<F7>')
expect([[ expect([[
soest text]]) soest text]])
eq(funcs.getreg('b',1,1), {'me short lines', 'of t'}) eq(funcs.getreg('b', 1, 1), { 'me short lines', 'of t' })
-- startinsert aborts operator -- startinsert aborts operator
feed('d<F8>') feed('d<F8>')
@@ -514,7 +515,6 @@ describe('mappings with <Cmd>', function()
end) end)
it('works in insert mode', function() it('works in insert mode', function()
-- works the same as <c-o>w<c-o>w -- works the same as <c-o>w<c-o>w
feed('iindeed <F4>little ') feed('iindeed <F4>little ')
screen:expect([[ screen:expect([[
@@ -535,7 +535,6 @@ describe('mappings with <Cmd>', function()
{3:Press ENTER or type command to continue}^ | {3:Press ENTER or type command to continue}^ |
]]) ]])
feed('<cr>') feed('<cr>')
eq('E605: Exception not caught: very error', eval('v:errmsg')) eq('E605: Exception not caught: very error', eval('v:errmsg'))
-- still in insert -- still in insert
@@ -562,7 +561,7 @@ describe('mappings with <Cmd>', function()
of stuff test text]]) of stuff test text]])
feed('<F5>') feed('<F5>')
eq(funcs.getreg('a',1,1), {'deed some short little lines', 'of stuff t'}) eq(funcs.getreg('a', 1, 1), { 'deed some short little lines', 'of stuff t' })
-- still in insert -- still in insert
screen:expect([[ screen:expect([[
@@ -704,7 +703,6 @@ describe('mappings with <Cmd>', function()
]]) ]])
eq('i', eval('mode(1)')) eq('i', eval('mode(1)'))
eq(9, eval('g:y')) eq(9, eval('g:y'))
end) end)
it("doesn't crash when invoking cmdline mode recursively #8859", function() it("doesn't crash when invoking cmdline mode recursively #8859", function()
@@ -726,18 +724,20 @@ describe('mappings with <Cmd>', function()
]]) ]])
end) end)
it("works with <SID> mappings", function() it('works with <SID> mappings', function()
command('new!') command('new!')
write_file(tmpfile, [[ write_file(
tmpfile,
[[
map <f2> <Cmd>call <SID>do_it()<Cr> map <f2> <Cmd>call <SID>do_it()<Cr>
function! s:do_it() function! s:do_it()
let g:x = 10 let g:x = 10
endfunction endfunction
]]) ]]
command('source '..tmpfile) )
command('source ' .. tmpfile)
feed('<f2>') feed('<f2>')
eq('', eval('v:errmsg')) eq('', eval('v:errmsg'))
eq(10, eval('g:x')) eq(10, eval('g:x'))
end) end)
end) end)

View File

@@ -9,10 +9,10 @@ describe(':debug', function()
clear() clear()
screen = Screen.new(30, 14) screen = Screen.new(30, 14)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1}, [1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = {bold = true, reverse = true}, [2] = { bold = true, reverse = true },
[3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
[4] = {bold = true, foreground = Screen.colors.SeaGreen4}, [4] = { bold = true, foreground = Screen.colors.SeaGreen4 },
}) })
screen:attach() screen:attach()
end) end)

View File

@@ -8,7 +8,6 @@ local exec_lua = helpers.exec_lua
local command = helpers.command local command = helpers.command
local eval = helpers.eval local eval = helpers.eval
describe('Vimscript dictionary notifications', function() describe('Vimscript dictionary notifications', function()
local channel local channel
@@ -29,9 +28,9 @@ describe('Vimscript dictionary notifications', function()
key = 'watched' key = 'watched'
end end
if opval == '' then if opval == '' then
command(('unlet %s[\'%s\']'):format(dict_expr, key)) command(("unlet %s['%s']"):format(dict_expr, key))
else else
command(('let %s[\'%s\'] %s'):format(dict_expr, key, opval)) command(("let %s['%s'] %s"):format(dict_expr, key, opval))
end end
end end
@@ -40,9 +39,9 @@ describe('Vimscript dictionary notifications', function()
key = 'watched' key = 'watched'
end end
if opval == '' then if opval == '' then
exec_lua(('vim.api.nvim_del_var(\'%s\')'):format(key)) exec_lua(("vim.api.nvim_del_var('%s')"):format(key))
else else
exec_lua(('vim.api.nvim_set_var(\'%s\', %s)'):format(key, opval)) exec_lua(("vim.api.nvim_set_var('%s', %s)"):format(key, opval))
end end
end end
@@ -61,14 +60,14 @@ describe('Vimscript dictionary notifications', function()
-- helper to verify that no notifications are sent after certain change -- helper to verify that no notifications are sent after certain change
-- to a dict -- to a dict
nvim('command', "call rpcnotify(g:channel, 'echo')") nvim('command', "call rpcnotify(g:channel, 'echo')")
eq({'notification', 'echo', {}}, next_msg()) eq({ 'notification', 'echo', {} }, next_msg())
end end
local function verify_value(vals, key) local function verify_value(vals, key)
if not key then if not key then
key = 'watched' key = 'watched'
end end
eq({'notification', 'values', {key, vals}}, next_msg()) eq({ 'notification', 'values', { key, vals } }, next_msg())
end end
describe(dict_expr .. ' watcher', function() describe(dict_expr .. ' watcher', function()
@@ -81,20 +80,20 @@ describe('Vimscript dictionary notifications', function()
before_each(function() before_each(function()
source([[ source([[
function! g:Changed(dict, key, value) function! g:Changed(dict, key, value)
if a:dict isnot ]]..dict_expr..[[ | if a:dict isnot ]] .. dict_expr .. [[ |
throw 'invalid dict' throw 'invalid dict'
endif endif
call rpcnotify(g:channel, 'values', a:key, a:value) call rpcnotify(g:channel, 'values', a:key, a:value)
endfunction endfunction
call dictwatcheradd(]]..dict_expr..[[, "watched", "g:Changed") call dictwatcheradd(]] .. dict_expr .. [[, "watched", "g:Changed")
call dictwatcheradd(]]..dict_expr..[[, "watched2", "g:Changed") call dictwatcheradd(]] .. dict_expr .. [[, "watched2", "g:Changed")
]]) ]])
end) end)
after_each(function() after_each(function()
source([[ source([[
call dictwatcherdel(]]..dict_expr..[[, "watched", "g:Changed") call dictwatcherdel(]] .. dict_expr .. [[, "watched", "g:Changed")
call dictwatcherdel(]]..dict_expr..[[, "watched2", "g:Changed") call dictwatcherdel(]] .. dict_expr .. [[, "watched2", "g:Changed")
]]) ]])
update('= "test"') update('= "test"')
update('= "test2"', 'watched2') update('= "test2"', 'watched2')
@@ -134,99 +133,99 @@ describe('Vimscript dictionary notifications', function()
it('is triggered by remove()', function() it('is triggered by remove()', function()
update('= "test"') update('= "test"')
verify_value({new = 'test'}) verify_value({ new = 'test' })
nvim('command', 'call remove('..dict_expr..', "watched")') nvim('command', 'call remove(' .. dict_expr .. ', "watched")')
verify_value({old = 'test'}) verify_value({ old = 'test' })
end) end)
if is_g then if is_g then
it('is triggered by remove() when updated with nvim_*_var', function() it('is triggered by remove() when updated with nvim_*_var', function()
update_with_api('"test"') update_with_api('"test"')
verify_value({new = 'test'}) verify_value({ new = 'test' })
nvim('command', 'call remove('..dict_expr..', "watched")') nvim('command', 'call remove(' .. dict_expr .. ', "watched")')
verify_value({old = 'test'}) verify_value({ old = 'test' })
end) end)
it('is triggered by remove() when updated with vim.g', function() it('is triggered by remove() when updated with vim.g', function()
update_with_vim_g('= "test"') update_with_vim_g('= "test"')
verify_value({new = 'test'}) verify_value({ new = 'test' })
nvim('command', 'call remove('..dict_expr..', "watched")') nvim('command', 'call remove(' .. dict_expr .. ', "watched")')
verify_value({old = 'test'}) verify_value({ old = 'test' })
end) end)
end end
it('is triggered by extend()', function() it('is triggered by extend()', function()
update('= "xtend"') update('= "xtend"')
verify_value({new = 'xtend'}) verify_value({ new = 'xtend' })
nvim('command', [[ nvim('command', [[
call extend(]]..dict_expr..[[, {'watched': 'xtend2', 'watched2': 5, 'watched3': 'a'}) call extend(]] .. dict_expr .. [[, {'watched': 'xtend2', 'watched2': 5, 'watched3': 'a'})
]]) ]])
verify_value({old = 'xtend', new = 'xtend2'}) verify_value({ old = 'xtend', new = 'xtend2' })
verify_value({new = 5}, 'watched2') verify_value({ new = 5 }, 'watched2')
update('') update('')
verify_value({old = 'xtend2'}) verify_value({ old = 'xtend2' })
update('', 'watched2') update('', 'watched2')
verify_value({old = 5}, 'watched2') verify_value({ old = 5 }, 'watched2')
update('', 'watched3') update('', 'watched3')
verify_echo() verify_echo()
end) end)
it('is triggered with key patterns', function() it('is triggered with key patterns', function()
source([[ source([[
call dictwatcheradd(]]..dict_expr..[[, "wat*", "g:Changed") call dictwatcheradd(]] .. dict_expr .. [[, "wat*", "g:Changed")
]]) ]])
update('= 1') update('= 1')
verify_value({new = 1}) verify_value({ new = 1 })
verify_value({new = 1}) verify_value({ new = 1 })
update('= 3', 'watched2') update('= 3', 'watched2')
verify_value({new = 3}, 'watched2') verify_value({ new = 3 }, 'watched2')
verify_value({new = 3}, 'watched2') verify_value({ new = 3 }, 'watched2')
verify_echo() verify_echo()
source([[ source([[
call dictwatcherdel(]]..dict_expr..[[, "wat*", "g:Changed") call dictwatcherdel(]] .. dict_expr .. [[, "wat*", "g:Changed")
]]) ]])
-- watch every key pattern -- watch every key pattern
source([[ source([[
call dictwatcheradd(]]..dict_expr..[[, "*", "g:Changed") call dictwatcheradd(]] .. dict_expr .. [[, "*", "g:Changed")
]]) ]])
update('= 3', 'another_key') update('= 3', 'another_key')
update('= 4', 'another_key') update('= 4', 'another_key')
update('', 'another_key') update('', 'another_key')
update('= 2') update('= 2')
verify_value({new = 3}, 'another_key') verify_value({ new = 3 }, 'another_key')
verify_value({old = 3, new = 4}, 'another_key') verify_value({ old = 3, new = 4 }, 'another_key')
verify_value({old = 4}, 'another_key') verify_value({ old = 4 }, 'another_key')
verify_value({old = 1, new = 2}) verify_value({ old = 1, new = 2 })
verify_value({old = 1, new = 2}) verify_value({ old = 1, new = 2 })
verify_echo() verify_echo()
source([[ source([[
call dictwatcherdel(]]..dict_expr..[[, "*", "g:Changed") call dictwatcherdel(]] .. dict_expr .. [[, "*", "g:Changed")
]]) ]])
end) end)
it('is triggered for empty keys', function() it('is triggered for empty keys', function()
command([[ command([[
call dictwatcheradd(]]..dict_expr..[[, "", "g:Changed") call dictwatcheradd(]] .. dict_expr .. [[, "", "g:Changed")
]]) ]])
update('= 1', '') update('= 1', '')
verify_value({new = 1}, '') verify_value({ new = 1 }, '')
update('= 2', '') update('= 2', '')
verify_value({old = 1, new = 2}, '') verify_value({ old = 1, new = 2 }, '')
command([[ command([[
call dictwatcherdel(]]..dict_expr..[[, "", "g:Changed") call dictwatcherdel(]] .. dict_expr .. [[, "", "g:Changed")
]]) ]])
end) end)
it('is triggered for empty keys when using catch-all *', function() it('is triggered for empty keys when using catch-all *', function()
command([[ command([[
call dictwatcheradd(]]..dict_expr..[[, "*", "g:Changed") call dictwatcheradd(]] .. dict_expr .. [[, "*", "g:Changed")
]]) ]])
update('= 1', '') update('= 1', '')
verify_value({new = 1}, '') verify_value({ new = 1 }, '')
update('= 2', '') update('= 2', '')
verify_value({old = 1, new = 2}, '') verify_value({ old = 1, new = 2 }, '')
command([[ command([[
call dictwatcherdel(]]..dict_expr..[[, "*", "g:Changed") call dictwatcherdel(]] .. dict_expr .. [[, "*", "g:Changed")
]]) ]])
end) end)
@@ -244,31 +243,31 @@ describe('Vimscript dictionary notifications', function()
end end
test_updates({ test_updates({
{'= 3', {new = 3}}, { '= 3', { new = 3 } },
{'= 6', {old = 3, new = 6}}, { '= 6', { old = 3, new = 6 } },
{'+= 3', {old = 6, new = 9}}, { '+= 3', { old = 6, new = 9 } },
{'', {old = 9}} { '', { old = 9 } },
}) })
test_updates({ test_updates({
{'= "str"', {new = 'str'}}, { '= "str"', { new = 'str' } },
{'= "str2"', {old = 'str', new = 'str2'}}, { '= "str2"', { old = 'str', new = 'str2' } },
{'.= "2str"', {old = 'str2', new = 'str22str'}}, { '.= "2str"', { old = 'str2', new = 'str22str' } },
{'', {old = 'str22str'}} { '', { old = 'str22str' } },
}) })
test_updates({ test_updates({
{'= [1, 2]', {new = {1, 2}}}, { '= [1, 2]', { new = { 1, 2 } } },
{'= [1, 2, 3]', {old = {1, 2}, new = {1, 2, 3}}}, { '= [1, 2, 3]', { old = { 1, 2 }, new = { 1, 2, 3 } } },
-- the += will update the list in place, so old and new are the same -- the += will update the list in place, so old and new are the same
{'+= [4, 5]', {old = {1, 2, 3, 4, 5}, new = {1, 2, 3, 4, 5}}}, { '+= [4, 5]', { old = { 1, 2, 3, 4, 5 }, new = { 1, 2, 3, 4, 5 } } },
{'', {old = {1, 2, 3, 4 ,5}}} { '', { old = { 1, 2, 3, 4, 5 } } },
}) })
test_updates({ test_updates({
{'= {"k": "v"}', {new = {k = 'v'}}}, { '= {"k": "v"}', { new = { k = 'v' } } },
{'= {"k1": 2}', {old = {k = 'v'}, new = {k1 = 2}}}, { '= {"k1": 2}', { old = { k = 'v' }, new = { k1 = 2 } } },
{'', {old = {k1 = 2}}}, { '', { old = { k1 = 2 } } },
}) })
end) end)
end end
@@ -295,17 +294,17 @@ describe('Vimscript dictionary notifications', function()
it('invokes all callbacks when the key is changed', function() it('invokes all callbacks when the key is changed', function()
nvim('command', 'let g:key = "value"') nvim('command', 'let g:key = "value"')
eq({'notification', '1', {'key', {new = 'value'}}}, next_msg()) eq({ 'notification', '1', { 'key', { new = 'value' } } }, next_msg())
eq({'notification', '2', {'key', {new = 'value'}}}, next_msg()) eq({ 'notification', '2', { 'key', { new = 'value' } } }, next_msg())
end) end)
it('only removes watchers that fully match dict, key and callback', function() it('only removes watchers that fully match dict, key and callback', function()
nvim('command', 'let g:key = "value"') nvim('command', 'let g:key = "value"')
eq({'notification', '1', {'key', {new = 'value'}}}, next_msg()) eq({ 'notification', '1', { 'key', { new = 'value' } } }, next_msg())
eq({'notification', '2', {'key', {new = 'value'}}}, next_msg()) eq({ 'notification', '2', { 'key', { new = 'value' } } }, next_msg())
nvim('command', 'call dictwatcherdel(g:, "key", "g:Watcher1")') nvim('command', 'call dictwatcherdel(g:, "key", "g:Watcher1")')
nvim('command', 'let g:key = "v2"') nvim('command', 'let g:key = "v2"')
eq({'notification', '2', {'key', {old = 'value', new = 'v2'}}}, next_msg()) eq({ 'notification', '2', { 'key', { old = 'value', new = 'v2' } } }, next_msg())
end) end)
end) end)
@@ -315,8 +314,10 @@ describe('Vimscript dictionary notifications', function()
call rpcnotify(g:channel, '1', a:key, a:value) call rpcnotify(g:channel, '1', a:key, a:value)
endfunction endfunction
]]) ]])
eq('Vim(call):E46: Cannot change read-only variable "dictwatcheradd() argument"', eq(
exc_exec('call dictwatcheradd(v:_null_dict, "x", "g:Watcher1")')) 'Vim(call):E46: Cannot change read-only variable "dictwatcheradd() argument"',
exc_exec('call dictwatcheradd(v:_null_dict, "x", "g:Watcher1")')
)
end) end)
describe('errors', function() describe('errors', function()
@@ -333,13 +334,17 @@ describe('Vimscript dictionary notifications', function()
-- WARNING: This suite depends on the above tests -- WARNING: This suite depends on the above tests
it('fails to remove if no watcher with matching callback is found', function() it('fails to remove if no watcher with matching callback is found', function()
eq("Vim(call):Couldn't find a watcher matching key and callback", eq(
exc_exec('call dictwatcherdel(g:, "key", "g:Watcher1")')) "Vim(call):Couldn't find a watcher matching key and callback",
exc_exec('call dictwatcherdel(g:, "key", "g:Watcher1")')
)
end) end)
it('fails to remove if no watcher with matching key is found', function() it('fails to remove if no watcher with matching key is found', function()
eq("Vim(call):Couldn't find a watcher matching key and callback", eq(
exc_exec('call dictwatcherdel(g:, "invalid_key", "g:Watcher2")')) "Vim(call):Couldn't find a watcher matching key and callback",
exc_exec('call dictwatcherdel(g:, "invalid_key", "g:Watcher2")')
)
end) end)
it("does not fail to add/remove if the callback doesn't exist", function() it("does not fail to add/remove if the callback doesn't exist", function()
@@ -348,8 +353,10 @@ describe('Vimscript dictionary notifications', function()
end) end)
it('fails to remove watcher from v:_null_dict', function() it('fails to remove watcher from v:_null_dict', function()
eq("Vim(call):Couldn't find a watcher matching key and callback", eq(
exc_exec('call dictwatcherdel(v:_null_dict, "x", "g:Watcher2")')) "Vim(call):Couldn't find a watcher matching key and callback",
exc_exec('call dictwatcherdel(v:_null_dict, "x", "g:Watcher2")')
)
end) end)
--[[ --[[
@@ -373,7 +380,7 @@ describe('Vimscript dictionary notifications', function()
]]) ]])
command('call g:ReplaceWatcher2()') command('call g:ReplaceWatcher2()')
command('let g:key = "value"') command('let g:key = "value"')
eq({'notification', '2b', {'key', {old = 'v2', new = 'value'}}}, next_msg()) eq({ 'notification', '2b', { 'key', { old = 'v2', new = 'value' } } }, next_msg())
end) end)
it('does not crash when freeing a watched dictionary', function() it('does not crash when freeing a watched dictionary', function()
@@ -400,7 +407,7 @@ describe('Vimscript dictionary notifications', function()
call dictwatcheradd(d, 'foo', {dict, key, value -> rpcnotify(g:channel, '2', key, value)}) call dictwatcheradd(d, 'foo', {dict, key, value -> rpcnotify(g:channel, '2', key, value)})
let d.foo = 'bar' let d.foo = 'bar'
]]) ]])
eq({'notification', '2', {'foo', {old = 'baz', new = 'bar'}}}, next_msg()) eq({ 'notification', '2', { 'foo', { old = 'baz', new = 'bar' } } }, next_msg())
end) end)
end) end)
@@ -412,12 +419,11 @@ describe('Vimscript dictionary notifications', function()
call dictwatcheradd(b:, 'changedtick', 'OnTickChanged') call dictwatcheradd(b:, 'changedtick', 'OnTickChanged')
]]) ]])
insert('t'); insert('t')
eq({'notification', 'SendChangeTick', {'changedtick', {old = 2, new = 3}}}, eq({ 'notification', 'SendChangeTick', { 'changedtick', { old = 2, new = 3 } } }, next_msg())
next_msg())
command([[call dictwatcherdel(b:, 'changedtick', 'OnTickChanged')]]) command([[call dictwatcherdel(b:, 'changedtick', 'OnTickChanged')]])
insert('t'); insert('t')
assert_alive() assert_alive()
end) end)
@@ -479,7 +485,7 @@ describe('Vimscript dictionary notifications', function()
let g:d.foo = 23 let g:d.foo = 23
]]) ]])
eq(23, eval('g:d.foo')) eq(23, eval('g:d.foo'))
eq({"W1"}, eval('g:calls')) eq({ 'W1' }, eval('g:calls'))
end) end)
it('calls watcher deleted in callback', function() it('calls watcher deleted in callback', function()
@@ -507,7 +513,6 @@ describe('Vimscript dictionary notifications', function()
let g:d.foo = 123 let g:d.foo = 123
]]) ]])
eq(123, eval('g:d.foo')) eq(123, eval('g:d.foo'))
eq({"W1", "W2", "W2", "W1"}, eval('g:calls')) eq({ 'W1', 'W2', 'W2', 'W1' }, eval('g:calls'))
end) end)
end) end)

View File

@@ -10,13 +10,13 @@ describe(':digraphs', function()
clear() clear()
screen = Screen.new(65, 8) screen = Screen.new(65, 8)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1}, [1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
[3] = {bold = true, foreground = Screen.colors.SeaGreen4}, [3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
[4] = {bold = true}, [4] = { bold = true },
[5] = {background = Screen.colors.LightGrey}, [5] = { background = Screen.colors.LightGrey },
[6] = {foreground = Screen.colors.Blue1}, [6] = { foreground = Screen.colors.Blue1 },
[7] = {bold = true, reverse = true}, [7] = { bold = true, reverse = true },
}) })
screen:attach() screen:attach()
end) end)

View File

@@ -3,7 +3,7 @@ local command = helpers.command
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local clear, feed, feed_command = helpers.clear, helpers.feed, helpers.feed_command local clear, feed, feed_command = helpers.clear, helpers.feed, helpers.feed_command
describe(":drop", function() describe(':drop', function()
local screen local screen
before_each(function() before_each(function()
@@ -11,16 +11,16 @@ describe(":drop", function()
screen = Screen.new(35, 10) screen = Screen.new(35, 10)
screen:attach() screen:attach()
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[0] = {bold=true, foreground=Screen.colors.Blue}, [0] = { bold = true, foreground = Screen.colors.Blue },
[1] = {bold = true, reverse = true}, [1] = { bold = true, reverse = true },
[2] = {reverse = true}, [2] = { reverse = true },
[3] = {bold = true}, [3] = { bold = true },
}) })
command("set laststatus=2 shortmess-=F") command('set laststatus=2 shortmess-=F')
end) end)
it("works like :e when called with only one window open", function() it('works like :e when called with only one window open', function()
feed_command("drop tmp1.vim") feed_command('drop tmp1.vim')
screen:expect([[ screen:expect([[
^ | ^ |
{0:~ }|*7 {0:~ }|*7
@@ -29,11 +29,11 @@ describe(":drop", function()
]]) ]])
end) end)
it("switches to an open window showing the buffer", function() it('switches to an open window showing the buffer', function()
feed_command("edit tmp1") feed_command('edit tmp1')
feed_command("vsplit") feed_command('vsplit')
feed_command("edit tmp2") feed_command('edit tmp2')
feed_command("drop tmp1") feed_command('drop tmp1')
screen:expect([[ screen:expect([[
│^ | │^ |
{0:~ }│{0:~ }|*7 {0:~ }│{0:~ }|*7
@@ -43,12 +43,12 @@ describe(":drop", function()
end) end)
it("splits off a new window when a buffer can't be abandoned", function() it("splits off a new window when a buffer can't be abandoned", function()
command("set nohidden") command('set nohidden')
feed_command("edit tmp1") feed_command('edit tmp1')
feed_command("vsplit") feed_command('vsplit')
feed_command("edit tmp2") feed_command('edit tmp2')
feed("iABC<esc>") feed('iABC<esc>')
feed_command("drop tmp3") feed_command('drop tmp3')
screen:expect([[ screen:expect([[
^ │ | ^ │ |
{0:~ }│{0:~ }|*3 {0:~ }│{0:~ }|*3
@@ -59,5 +59,4 @@ describe(":drop", function()
"tmp3" [New] | "tmp3" [New] |
]]) ]])
end) end)
end) end)

View File

@@ -14,15 +14,15 @@ local exec_capture = helpers.exec_capture
local matches = helpers.matches local matches = helpers.matches
describe(':echo :echon :echomsg :echoerr', function() describe(':echo :echon :echomsg :echoerr', function()
local fn_tbl = {'String', 'StringN', 'StringMsg', 'StringErr'} local fn_tbl = { 'String', 'StringN', 'StringMsg', 'StringErr' }
local function assert_same_echo_dump(expected, input, use_eval) local function assert_same_echo_dump(expected, input, use_eval)
for _,v in pairs(fn_tbl) do for _, v in pairs(fn_tbl) do
eq(expected, use_eval and eval(v..'('..input..')') or funcs[v](input)) eq(expected, use_eval and eval(v .. '(' .. input .. ')') or funcs[v](input))
end end
end end
local function assert_matches_echo_dump(expected, input, use_eval) local function assert_matches_echo_dump(expected, input, use_eval)
for _,v in pairs(fn_tbl) do for _, v in pairs(fn_tbl) do
matches(expected, use_eval and eval(v..'('..input..')') or funcs[v](input)) matches(expected, use_eval and eval(v .. '(' .. input .. ')') or funcs[v](input))
end end
end end
@@ -85,14 +85,12 @@ describe(':echo :echon :echomsg :echoerr', function()
eq('v:null', funcs.StringErr(NIL)) eq('v:null', funcs.StringErr(NIL))
end) end)
it('dumps values with at most six digits after the decimal point', it('dumps values with at most six digits after the decimal point', function()
function()
assert_same_echo_dump('1.234568e-20', 1.23456789123456789123456789e-020) assert_same_echo_dump('1.234568e-20', 1.23456789123456789123456789e-020)
assert_same_echo_dump('1.234568', 1.23456789123456789123456789) assert_same_echo_dump('1.234568', 1.23456789123456789123456789)
end) end)
it('dumps values with at most seven digits before the decimal point', it('dumps values with at most seven digits before the decimal point', function()
function()
assert_same_echo_dump('1234567.891235', 1234567.89123456789123456789) assert_same_echo_dump('1234567.891235', 1234567.89123456789123456789)
assert_same_echo_dump('1.234568e7', 12345678.9123456789123456789) assert_same_echo_dump('1.234568e7', 12345678.9123456789123456789)
end) end)
@@ -115,8 +113,8 @@ describe(':echo :echon :echomsg :echoerr', function()
end) end)
it('dumps large values', function() it('dumps large values', function()
assert_same_echo_dump('2147483647', 2^31-1) assert_same_echo_dump('2147483647', 2 ^ 31 - 1)
assert_same_echo_dump('-2147483648', -2^31) assert_same_echo_dump('-2147483648', -2 ^ 31)
end) end)
end) end)
@@ -198,75 +196,95 @@ describe(':echo :echon :echomsg :echoerr', function()
let TestDictRef = function('TestDict', d) let TestDictRef = function('TestDict', d)
let d.tdr = TestDictRef let d.tdr = TestDictRef
]]) ]])
eq(dedent([[ eq(
dedent([[
function('TestDict', {'tdr': function('TestDict', {...@1})})]]), function('TestDict', {'tdr': function('TestDict', {...@1})})]]),
exec_capture('echo String(d.tdr)')) exec_capture('echo String(d.tdr)')
)
end) end)
it('dumps automatically created partials', function() it('dumps automatically created partials', function()
assert_same_echo_dump( assert_same_echo_dump(
"function('<SNR>1_Test2', {'f': function('<SNR>1_Test2')})", "function('<SNR>1_Test2', {'f': function('<SNR>1_Test2')})",
'{"f": Test2_f}.f', '{"f": Test2_f}.f',
true) true
)
assert_same_echo_dump( assert_same_echo_dump(
"function('<SNR>1_Test2', [1], {'f': function('<SNR>1_Test2', [1])})", "function('<SNR>1_Test2', [1], {'f': function('<SNR>1_Test2', [1])})",
'{"f": function(Test2_f, [1])}.f', '{"f": function(Test2_f, [1])}.f',
true) true
)
end) end)
it('dumps manually created partials', function() it('dumps manually created partials', function()
assert_same_echo_dump("function('Test3', [1, 2], {})", assert_same_echo_dump("function('Test3', [1, 2], {})", "function('Test3', [1, 2], {})", true)
"function('Test3', [1, 2], {})", true) assert_same_echo_dump("function('Test3', [1, 2])", "function('Test3', [1, 2])", true)
assert_same_echo_dump("function('Test3', [1, 2])", assert_same_echo_dump("function('Test3', {})", "function('Test3', {})", true)
"function('Test3', [1, 2])", true)
assert_same_echo_dump("function('Test3', {})",
"function('Test3', {})", true)
end) end)
it('does not crash or halt when dumping partials with reference cycles in self', it('does not crash or halt when dumping partials with reference cycles in self', function()
function() meths.set_var('d', { v = true })
meths.set_var('d', {v=true}) eq(
eq(dedent([[ dedent(
{'p': function('<SNR>1_Test2', {...@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]]), [[
exec_capture('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))')) {'p': function('<SNR>1_Test2', {...@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]]
),
exec_capture('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))')
)
end) end)
it('does not show errors when dumping partials referencing the same dictionary', it('does not show errors when dumping partials referencing the same dictionary', function()
function()
command('let d = {}') command('let d = {}')
-- Regression for “eval/typval_encode: Dump empty dictionary before -- Regression for “eval/typval_encode: Dump empty dictionary before
-- checking for refcycle”, results in error. -- checking for refcycle”, results in error.
eq('[function(\'tr\', {}), function(\'tr\', {})]', eval('String([function("tr", d), function("tr", d)])')) eq(
"[function('tr', {}), function('tr', {})]",
eval('String([function("tr", d), function("tr", d)])')
)
-- Regression for “eval: Work with reference cycles in partials (self) -- Regression for “eval: Work with reference cycles in partials (self)
-- properly”, results in crash. -- properly”, results in crash.
eval('extend(d, {"a": 1})') eval('extend(d, {"a": 1})')
eq('[function(\'tr\', {\'a\': 1}), function(\'tr\', {\'a\': 1})]', eval('String([function("tr", d), function("tr", d)])')) eq(
"[function('tr', {'a': 1}), function('tr', {'a': 1})]",
eval('String([function("tr", d), function("tr", d)])')
)
end) end)
it('does not crash or halt when dumping partials with reference cycles in arguments', it('does not crash or halt when dumping partials with reference cycles in arguments', function()
function()
meths.set_var('l', {}) meths.set_var('l', {})
eval('add(l, l)') eval('add(l, l)')
-- Regression: the below line used to crash (add returns original list and -- Regression: the below line used to crash (add returns original list and
-- there was error in dumping partials). Tested explicitly in -- there was error in dumping partials). Tested explicitly in
-- test/unit/api/private_helpers_spec.lua. -- test/unit/api/private_helpers_spec.lua.
eval('add(l, function("Test1", l))') eval('add(l, function("Test1", l))')
eq(dedent([=[ eq(
function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])]=]), dedent(
exec_capture('echo String(function("Test1", l))')) [=[
function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])]=]
),
exec_capture('echo String(function("Test1", l))')
)
end) end)
it('does not crash or halt when dumping partials with reference cycles in self and arguments', it(
function() 'does not crash or halt when dumping partials with reference cycles in self and arguments',
meths.set_var('d', {v=true}) function()
meths.set_var('l', {}) meths.set_var('d', { v = true })
eval('add(l, l)') meths.set_var('l', {})
eval('add(l, function("Test1", l))') eval('add(l, l)')
eval('add(l, function("Test1", d))') eval('add(l, function("Test1", l))')
eq(dedent([=[ eval('add(l, function("Test1", d))')
{'p': function('<SNR>1_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]=]), eq(
exec_capture('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))')) dedent(
end) [=[
{'p': function('<SNR>1_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]=]
),
exec_capture(
'echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'
)
)
end
)
end) end)
describe('used to represent lists', function() describe('used to represent lists', function()
@@ -275,15 +293,15 @@ describe(':echo :echon :echomsg :echoerr', function()
end) end)
it('dumps non-empty list', function() it('dumps non-empty list', function()
assert_same_echo_dump('[1, 2]', {1,2}) assert_same_echo_dump('[1, 2]', { 1, 2 })
end) end)
it('dumps nested lists', function() it('dumps nested lists', function()
assert_same_echo_dump('[[[[[]]]]]', {{{{{}}}}}) assert_same_echo_dump('[[[[[]]]]]', { { { { {} } } } })
end) end)
it('dumps nested non-empty lists', function() it('dumps nested non-empty lists', function()
assert_same_echo_dump('[1, [[3, [[5], 4]], 2]]', {1, {{3, {{5}, 4}}, 2}}) assert_same_echo_dump('[1, [[3, [[5], 4]], 2]]', { 1, { { 3, { { 5 }, 4 } }, 2 } })
end) end)
it('does not error when dumping recursive lists', function() it('does not error when dumping recursive lists', function()
@@ -308,27 +326,25 @@ describe(':echo :echon :echomsg :echoerr', function()
it('dumps list with two same empty dictionaries, also in partials', function() it('dumps list with two same empty dictionaries, also in partials', function()
command('let d = {}') command('let d = {}')
assert_same_echo_dump('[{}, {}]', '[d, d]', true) assert_same_echo_dump('[{}, {}]', '[d, d]', true)
eq('[function(\'tr\', {}), {}]', eval('String([function("tr", d), d])')) eq("[function('tr', {}), {}]", eval('String([function("tr", d), d])'))
eq('[{}, function(\'tr\', {})]', eval('String([d, function("tr", d)])')) eq("[{}, function('tr', {})]", eval('String([d, function("tr", d)])'))
end) end)
it('dumps non-empty dictionary', function() it('dumps non-empty dictionary', function()
assert_same_echo_dump("{'t''est': 1}", {["t'est"]=1}) assert_same_echo_dump("{'t''est': 1}", { ["t'est"] = 1 })
end) end)
it('does not error when dumping recursive dictionaries', function() it('does not error when dumping recursive dictionaries', function()
meths.set_var('d', {d=1}) meths.set_var('d', { d = 1 })
eval('extend(d, {"d": d})') eval('extend(d, {"d": d})')
eq(0, exc_exec('echo String(d)')) eq(0, exc_exec('echo String(d)'))
end) end)
it('dumps recursive dictionaries without the error', function() it('dumps recursive dictionaries without the error', function()
meths.set_var('d', {d=1}) meths.set_var('d', { d = 1 })
eval('extend(d, {"d": d})') eval('extend(d, {"d": d})')
eq('{\'d\': {...@0}}', eq("{'d': {...@0}}", exec_capture('echo String(d)'))
exec_capture('echo String(d)')) eq("{'out': {'d': {...@1}}}", exec_capture('echo String({"out": d})'))
eq('{\'out\': {\'d\': {...@1}}}',
exec_capture('echo String({"out": d})'))
end) end)
end) end)

View File

@@ -1,27 +1,27 @@
local helpers = require("test.functional.helpers")(after_each) local helpers = require('test.functional.helpers')(after_each)
local eq, command, funcs = helpers.eq, helpers.command, helpers.funcs local eq, command, funcs = helpers.eq, helpers.command, helpers.funcs
local ok = helpers.ok local ok = helpers.ok
local clear = helpers.clear local clear = helpers.clear
local feed = helpers.feed local feed = helpers.feed
describe(":edit", function() describe(':edit', function()
before_each(function() before_each(function()
clear() clear()
end) end)
it("without arguments does not restart :terminal buffer", function() it('without arguments does not restart :terminal buffer', function()
command("terminal") command('terminal')
feed([[<C-\><C-N>]]) feed([[<C-\><C-N>]])
local bufname_before = funcs.bufname("%") local bufname_before = funcs.bufname('%')
local bufnr_before = funcs.bufnr("%") local bufnr_before = funcs.bufnr('%')
helpers.ok(nil ~= string.find(bufname_before, "^term://")) -- sanity helpers.ok(nil ~= string.find(bufname_before, '^term://')) -- sanity
command("edit") command('edit')
local bufname_after = funcs.bufname("%") local bufname_after = funcs.bufname('%')
local bufnr_after = funcs.bufnr("%") local bufnr_after = funcs.bufnr('%')
ok(funcs.line('$') > 1) ok(funcs.line('$') > 1)
eq(bufname_before, bufname_after) eq(bufname_before, bufname_after)
eq(bufnr_before, bufnr_after) eq(bufnr_before, bufnr_after)
end) end)
end) end)

View File

@@ -3,7 +3,6 @@ local clear, feed_command, feed = helpers.clear, helpers.feed_command, helpers.f
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
describe('&encoding', function() describe('&encoding', function()
before_each(function() before_each(function()
clear() clear()
-- sanity check: tests should run with encoding=utf-8 -- sanity check: tests should run with encoding=utf-8
@@ -32,9 +31,9 @@ describe('&encoding', function()
it('can be set to utf-8 without error', function() it('can be set to utf-8 without error', function()
feed_command('set encoding=utf-8') feed_command('set encoding=utf-8')
eq("", eval('v:errmsg')) eq('', eval('v:errmsg'))
clear('--cmd', 'set enc=utf-8') clear('--cmd', 'set enc=utf-8')
eq("", eval('v:errmsg')) eq('', eval('v:errmsg'))
end) end)
end) end)

View File

@@ -1,4 +1,4 @@
local helpers = require("test.functional.helpers")(after_each) local helpers = require('test.functional.helpers')(after_each)
local command = helpers.command local command = helpers.command
local eq = helpers.eq local eq = helpers.eq
local clear = helpers.clear local clear = helpers.clear
@@ -20,15 +20,25 @@ describe('Ex cmds', function()
command(':later 9999999999999999999999999999999999999999') command(':later 9999999999999999999999999999999999999999')
command(':echo expand("#<9999999999999999999999999999999999999999")') command(':echo expand("#<9999999999999999999999999999999999999999")')
command(':lockvar 9999999999999999999999999999999999999999') command(':lockvar 9999999999999999999999999999999999999999')
command(':winsize 9999999999999999999999999999999999999999 9999999999999999999999999999999999999999') command(
check_excmd_err(':tabnext 9999999999999999999999999999999999999999', ':winsize 9999999999999999999999999999999999999999 9999999999999999999999999999999999999999'
'Vim(tabnext):E475: Invalid argument: 9999999999999999999999999999999999999999') )
check_excmd_err(':N 9999999999999999999999999999999999999999', check_excmd_err(
'Vim(Next):E939: Positive count required') ':tabnext 9999999999999999999999999999999999999999',
check_excmd_err(':bdelete 9999999999999999999999999999999999999999', 'Vim(tabnext):E475: Invalid argument: 9999999999999999999999999999999999999999'
'Vim(bdelete):E939: Positive count required') )
eq('Vim(menu):E329: No menu "9999999999999999999999999999999999999999"', check_excmd_err(
pcall_err(command, ':menu 9999999999999999999999999999999999999999')) ':N 9999999999999999999999999999999999999999',
'Vim(Next):E939: Positive count required'
)
check_excmd_err(
':bdelete 9999999999999999999999999999999999999999',
'Vim(bdelete):E939: Positive count required'
)
eq(
'Vim(menu):E329: No menu "9999999999999999999999999999999999999999"',
pcall_err(command, ':menu 9999999999999999999999999999999999999999')
)
assert_alive() assert_alive()
end) end)

View File

@@ -8,7 +8,7 @@ local rmdir = helpers.rmdir
local mkdir = helpers.mkdir local mkdir = helpers.mkdir
describe(':file', function() describe(':file', function()
local swapdir = luv.cwd()..'/Xtest-file_spec' local swapdir = luv.cwd() .. '/Xtest-file_spec'
before_each(function() before_each(function()
clear() clear()
rmdir(swapdir) rmdir(swapdir)
@@ -19,18 +19,17 @@ describe(':file', function()
rmdir(swapdir) rmdir(swapdir)
end) end)
it("rename does not lose swapfile #6487", function() it('rename does not lose swapfile #6487', function()
local testfile = 'test-file_spec' local testfile = 'test-file_spec'
local testfile_renamed = testfile..'-renamed' local testfile_renamed = testfile .. '-renamed'
-- Note: `set swapfile` *must* go after `set directory`: otherwise it may -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
-- attempt to create a swapfile in different directory. -- attempt to create a swapfile in different directory.
command('set directory^='..swapdir..'//') command('set directory^=' .. swapdir .. '//')
command('set swapfile fileformat=unix undolevels=-1') command('set swapfile fileformat=unix undolevels=-1')
command('edit! '..testfile) command('edit! ' .. testfile)
-- Before #6487 this gave "E301: Oops, lost the swap file !!!" on Windows. -- Before #6487 this gave "E301: Oops, lost the swap file !!!" on Windows.
command('file '..testfile_renamed) command('file ' .. testfile_renamed)
eq(testfile_renamed..'.swp', eq(testfile_renamed .. '.swp', string.match(funcs.execute('swapname'), '[^%%]+$'))
string.match(funcs.execute('swapname'), '[^%%]+$'))
end) end)
end) end)

View File

@@ -15,7 +15,7 @@ describe(':grep', function()
-- Change to test directory so that the test does not run too long. -- Change to test directory so that the test does not run too long.
feed_command('cd test') feed_command('cd test')
feed_command('grep a **/*') feed_command('grep a **/*')
feed('<cr>') -- Press ENTER feed('<cr>') -- Press ENTER
ok(eval('len(getqflist())') > 9000) -- IT'S OVER 9000!!1 ok(eval('len(getqflist())') > 9000) -- IT'S OVER 9000!!1
end) end)
end) end)

View File

@@ -1,5 +1,5 @@
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local helpers = require("test.functional.helpers")(after_each) local helpers = require('test.functional.helpers')(after_each)
local eq, command = helpers.eq, helpers.command local eq, command = helpers.eq, helpers.command
local clear = helpers.clear local clear = helpers.clear
local eval, exc_exec = helpers.eval, helpers.exc_exec local eval, exc_exec = helpers.eval, helpers.exc_exec
@@ -17,15 +17,18 @@ describe(':highlight', function()
end) end)
it('invalid color name', function() it('invalid color name', function()
eq('Vim(highlight):E421: Color name or number not recognized: ctermfg=#181818', eq(
exc_exec("highlight normal ctermfg=#181818")) 'Vim(highlight):E421: Color name or number not recognized: ctermfg=#181818',
eq('Vim(highlight):E421: Color name or number not recognized: ctermbg=#181818', exc_exec('highlight normal ctermfg=#181818')
exc_exec("highlight normal ctermbg=#181818")) )
eq(
'Vim(highlight):E421: Color name or number not recognized: ctermbg=#181818',
exc_exec('highlight normal ctermbg=#181818')
)
end) end)
it('invalid group name', function() it('invalid group name', function()
eq('Vim(highlight):E411: Highlight group not found: foo', eq('Vim(highlight):E411: Highlight group not found: foo', exc_exec('highlight foo'))
exc_exec("highlight foo"))
end) end)
it('"Normal" foreground with red', function() it('"Normal" foreground with red', function()

View File

@@ -44,6 +44,4 @@ describe(':ls', function()
eq('\n 3 %aF ', string.match(ls_output, '^\n *3 ... ')) eq('\n 3 %aF ', string.match(ls_output, '^\n *3 ... '))
end) end)
end) end)
end) end)

View File

@@ -8,27 +8,30 @@ local testprg = helpers.testprg
describe(':make', function() describe(':make', function()
clear() clear()
before_each(function () before_each(function()
clear() clear()
end) end)
describe('with powershell', function() describe('with powershell', function()
if not has_powershell() then if not has_powershell() then
pending("not tested; powershell was not found", function() end) pending('not tested; powershell was not found', function() end)
return return
end end
before_each(function () before_each(function()
helpers.set_shell_powershell() helpers.set_shell_powershell()
end) end)
it('captures stderr & non zero exit code #14349', function () it('captures stderr & non zero exit code #14349', function()
nvim('set_option_value', 'makeprg', testprg('shell-test')..' foo', {}) nvim('set_option_value', 'makeprg', testprg('shell-test') .. ' foo', {})
local out = eval('execute("make")') local out = eval('execute("make")')
-- Error message is captured in the file and printed in the footer -- Error message is captured in the file and printed in the footer
matches('[\r\n]+.*[\r\n]+Unknown first argument%: foo[\r\n]+%(1 of 1%)%: Unknown first argument%: foo', out) matches(
'[\r\n]+.*[\r\n]+Unknown first argument%: foo[\r\n]+%(1 of 1%)%: Unknown first argument%: foo',
out
)
end) end)
it('captures stderr & zero exit code #14349', function () it('captures stderr & zero exit code #14349', function()
nvim('set_option_value', 'makeprg', testprg('shell-test'), {}) nvim('set_option_value', 'makeprg', testprg('shell-test'), {})
local out = eval('execute("make")') local out = eval('execute("make")')
-- Ensure there are no "shell returned X" messages between -- Ensure there are no "shell returned X" messages between
@@ -36,7 +39,5 @@ describe(':make', function()
matches('LastExitCode%s+ready [$]%s+[(]', out) matches('LastExitCode%s+ready [$]%s+[(]', out)
matches('\n.*%: ready [$]', out) matches('\n.*%: ready [$]', out)
end) end)
end) end)
end) end)

View File

@@ -1,4 +1,4 @@
local helpers = require("test.functional.helpers")(after_each) local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local eq = helpers.eq local eq = helpers.eq
@@ -33,23 +33,27 @@ describe(':*map', function()
it('shows <Nop> as mapping rhs', function() it('shows <Nop> as mapping rhs', function()
command('nmap asdf <Nop>') command('nmap asdf <Nop>')
eq([[ eq(
[[
n asdf <Nop>]], n asdf <Nop>]],
exec_capture('nmap asdf')) exec_capture('nmap asdf')
)
end) end)
it('mappings with description can be filtered', function() it('mappings with description can be filtered', function()
meths.set_keymap('n', 'asdf1', 'qwert', {desc='do the one thing'}) meths.set_keymap('n', 'asdf1', 'qwert', { desc = 'do the one thing' })
meths.set_keymap('n', 'asdf2', 'qwert', {desc='doesnot really do anything'}) meths.set_keymap('n', 'asdf2', 'qwert', { desc = 'doesnot really do anything' })
meths.set_keymap('n', 'asdf3', 'qwert', {desc='do the other thing'}) meths.set_keymap('n', 'asdf3', 'qwert', { desc = 'do the other thing' })
eq([[ eq(
[[
n asdf3 qwert n asdf3 qwert
do the other thing do the other thing
n asdf1 qwert n asdf1 qwert
do the one thing]], do the one thing]],
exec_capture('filter the nmap')) exec_capture('filter the nmap')
)
end) end)
it('<Plug> mappings ignore nore', function() it('<Plug> mappings ignore nore', function()
@@ -75,7 +79,7 @@ n asdf1 qwert
nmap increase_x_remap x<Plug>(Increase_x)x nmap increase_x_remap x<Plug>(Increase_x)x
nnoremap increase_x_noremap x<Plug>(Increase_x)x nnoremap increase_x_noremap x<Plug>(Increase_x)x
]] ]]
insert("Some text") insert('Some text')
eq('Some text', eval("getline('.')")) eq('Some text', eval("getline('.')"))
feed('increase_x_remap') feed('increase_x_remap')

View File

@@ -4,9 +4,7 @@ local expect, feed = helpers.expect, helpers.feed
local eq, eval = helpers.eq, helpers.eval local eq, eval = helpers.eq, helpers.eval
local funcs = helpers.funcs local funcs = helpers.funcs
describe(':emenu', function() describe(':emenu', function()
before_each(function() before_each(function()
clear() clear()
command('nnoremenu Test.Test inormal<ESC>') command('nnoremenu Test.Test inormal<ESC>')
@@ -41,26 +39,25 @@ describe(':emenu', function()
end) end)
it('executes correct bindings in command mode', function() it('executes correct bindings in command mode', function()
feed('ithis is a sentence<esc>^yiwo<esc>') feed('ithis is a sentence<esc>^yiwo<esc>')
-- Invoke "Edit.Paste" in normal-mode. -- Invoke "Edit.Paste" in normal-mode.
nvim('command', 'emenu Edit.Paste') nvim('command', 'emenu Edit.Paste')
-- Invoke "Edit.Paste" and "Test.Test" in command-mode. -- Invoke "Edit.Paste" and "Test.Test" in command-mode.
feed(':') feed(':')
nvim('command', 'emenu Edit.Paste') nvim('command', 'emenu Edit.Paste')
nvim('command', 'emenu Test.Test') nvim('command', 'emenu Test.Test')
expect([[ expect([[
this is a sentence this is a sentence
this]]) this]])
-- Assert that Edit.Paste pasted @" into the commandline. -- Assert that Edit.Paste pasted @" into the commandline.
eq('thiscmdmode', eval('getcmdline()')) eq('thiscmdmode', eval('getcmdline()'))
end) end)
end) end)
describe('menu_get', function() describe('menu_get', function()
before_each(function() before_each(function()
clear() clear()
command([=[ command([=[
@@ -83,12 +80,12 @@ describe('menu_get', function()
end) end)
it("path='', modes='a'", function() it("path='', modes='a'", function()
local m = funcs.menu_get("","a"); local m = funcs.menu_get('', 'a')
-- HINT: To print the expected table and regenerate the tests: -- HINT: To print the expected table and regenerate the tests:
-- print(require('vim.inspect')(m)) -- print(require('vim.inspect')(m))
local expected = { local expected = {
{ {
shortcut = "T", shortcut = 'T',
hidden = 0, hidden = 0,
submenus = { submenus = {
{ {
@@ -97,45 +94,45 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "insert", rhs = 'insert',
silent = 0 silent = 0,
}, },
s = { s = {
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "x", rhs = 'x',
silent = 0 silent = 0,
}, },
n = { n = {
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "inormal<Esc>", rhs = 'inormal<Esc>',
silent = 0 silent = 0,
}, },
v = { v = {
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "x", rhs = 'x',
silent = 0 silent = 0,
}, },
c = { c = {
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "cmdmode", rhs = 'cmdmode',
silent = 0 silent = 0,
} },
}, },
priority = 500, priority = 500,
name = "Test", name = 'Test',
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
name = "Nested", name = 'Nested',
submenus = { submenus = {
{ {
mappings = { mappings = {
@@ -143,34 +140,34 @@ describe('menu_get', function()
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "level1", rhs = 'level1',
silent = 0 silent = 0,
}, },
v = { v = {
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "level1", rhs = 'level1',
silent = 0 silent = 0,
}, },
s = { s = {
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "level1", rhs = 'level1',
silent = 0 silent = 0,
}, },
n = { n = {
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "level1", rhs = 'level1',
silent = 0 silent = 0,
} },
}, },
priority = 500, priority = 500,
name = "test", name = 'test',
hidden = 0 hidden = 0,
}, },
{ {
mappings = { mappings = {
@@ -178,67 +175,67 @@ describe('menu_get', function()
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "level2", rhs = 'level2',
silent = 0 silent = 0,
}, },
v = { v = {
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "level2", rhs = 'level2',
silent = 0 silent = 0,
}, },
s = { s = {
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "level2", rhs = 'level2',
silent = 0 silent = 0,
}, },
n = { n = {
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "level2", rhs = 'level2',
silent = 0 silent = 0,
} },
}, },
priority = 500, priority = 500,
name = "Nested2", name = 'Nested2',
hidden = 0 hidden = 0,
} },
}, },
hidden = 0 hidden = 0,
} },
}, },
priority = 500, priority = 500,
name = "Test" name = 'Test',
}, },
{ {
priority = 500, priority = 500,
name = "Export", name = 'Export',
submenus = { submenus = {
{ {
tooltip = "This is the tooltip", tooltip = 'This is the tooltip',
hidden = 0, hidden = 0,
name = "Script", name = 'Script',
priority = 500, priority = 500,
mappings = { mappings = {
n = { n = {
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "p", rhs = 'p',
silent = 0 silent = 0,
} },
} },
} },
}, },
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
name = "Edit", name = 'Edit',
submenus = { submenus = {
{ {
mappings = { mappings = {
@@ -246,27 +243,27 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "<C-R>\"", rhs = '<C-R>"',
silent = 0 silent = 0,
}, },
n = { n = {
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "p", rhs = 'p',
silent = 0 silent = 0,
} },
}, },
priority = 500, priority = 500,
name = "Paste", name = 'Paste',
hidden = 0 hidden = 0,
} },
}, },
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
name = "]Export", name = ']Export',
submenus = { submenus = {
{ {
mappings = { mappings = {
@@ -274,72 +271,76 @@ describe('menu_get', function()
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "thisoneshouldbehidden", rhs = 'thisoneshouldbehidden',
silent = 0 silent = 0,
}, },
v = { v = {
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "thisoneshouldbehidden", rhs = 'thisoneshouldbehidden',
silent = 0 silent = 0,
}, },
s = { s = {
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "thisoneshouldbehidden", rhs = 'thisoneshouldbehidden',
silent = 0 silent = 0,
}, },
n = { n = {
sid = 0, sid = 0,
noremap = 0, noremap = 0,
enabled = 1, enabled = 1,
rhs = "thisoneshouldbehidden", rhs = 'thisoneshouldbehidden',
silent = 0 silent = 0,
} },
}, },
priority = 500, priority = 500,
name = "hidden", name = 'hidden',
hidden = 0 hidden = 0,
} },
}, },
hidden = 1 hidden = 1,
} },
} }
eq(expected, m) eq(expected, m)
end) end)
it('matching path, all modes', function() it('matching path, all modes', function()
local m = funcs.menu_get("Export", "a") local m = funcs.menu_get('Export', 'a')
local expected = { { local expected = {
hidden = 0, {
name = "Export",
priority = 500,
submenus = { {
tooltip = "This is the tooltip",
hidden = 0, hidden = 0,
name = "Script", name = 'Export',
priority = 500, priority = 500,
mappings = { submenus = {
n = { {
sid = 1, tooltip = 'This is the tooltip',
noremap = 1, hidden = 0,
enabled = 1, name = 'Script',
rhs = "p", priority = 500,
silent = 0 mappings = {
} n = {
} sid = 1,
} } noremap = 1,
} } enabled = 1,
rhs = 'p',
silent = 0,
},
},
},
},
},
}
eq(expected, m) eq(expected, m)
end) end)
it('no path, matching modes', function() it('no path, matching modes', function()
local m = funcs.menu_get("","i") local m = funcs.menu_get('', 'i')
local expected = { local expected = {
{ {
shortcut = "T", shortcut = 'T',
hidden = 0, hidden = 0,
submenus = { submenus = {
{ {
@@ -348,27 +349,27 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "insert", rhs = 'insert',
silent = 0 silent = 0,
} },
}, },
priority = 500, priority = 500,
name = "Test", name = 'Test',
hidden = 0 hidden = 0,
}, },
}, },
priority = 500, priority = 500,
name = "Test" name = 'Test',
} },
} }
eq(expected, m) eq(expected, m)
end) end)
it('matching path and modes', function() it('matching path and modes', function()
local m = funcs.menu_get("Test","i") local m = funcs.menu_get('Test', 'i')
local expected = { local expected = {
{ {
shortcut = "T", shortcut = 'T',
submenus = { submenus = {
{ {
mappings = { mappings = {
@@ -376,26 +377,25 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "insert", rhs = 'insert',
silent = 0 silent = 0,
}, },
}, },
priority = 500, priority = 500,
name = "Test", name = 'Test',
hidden = 0 hidden = 0,
}, },
}, },
priority = 500, priority = 500,
name = "Test", name = 'Test',
hidden = 0 hidden = 0,
} },
} }
eq(expected, m) eq(expected, m)
end) end)
end) end)
describe('menu_get', function() describe('menu_get', function()
before_each(function() before_each(function()
clear() clear()
command('aunmenu *') command('aunmenu *')
@@ -412,10 +412,10 @@ describe('menu_get', function()
command('nnoremenu &Test.Test8 <NoP>') command('nnoremenu &Test.Test8 <NoP>')
command('nnoremenu &Test.Test9 ""') command('nnoremenu &Test.Test9 ""')
local m = funcs.menu_get(""); local m = funcs.menu_get('')
local expected = { local expected = {
{ {
shortcut = "T", shortcut = 'T',
hidden = 0, hidden = 0,
submenus = { submenus = {
{ {
@@ -425,12 +425,12 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "inormal<Esc>", rhs = 'inormal<Esc>',
silent = 0 silent = 0,
} },
}, },
name = "Test", name = 'Test',
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
@@ -439,12 +439,12 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "<Tab><Esc>", rhs = '<Tab><Esc>',
silent = 0 silent = 0,
} },
}, },
name = "Test2", name = 'Test2',
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
@@ -453,19 +453,19 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "yA<C-R>0<Tab>xyz<Esc>", rhs = 'yA<C-R>0<Tab>xyz<Esc>',
silent = 0 silent = 0,
}, },
v = { v = {
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "yA<C-R>0<Tab>xyz<Esc>", rhs = 'yA<C-R>0<Tab>xyz<Esc>',
silent = 0 silent = 0,
} },
}, },
name = "Test3", name = 'Test3',
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
@@ -474,12 +474,12 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "<C-R>*", rhs = '<C-R>*',
silent = 0 silent = 0,
} },
}, },
name = "Test4", name = 'Test4',
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
@@ -488,12 +488,12 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "<C-R>+", rhs = '<C-R>+',
silent = 0 silent = 0,
} },
}, },
name = "Test5", name = 'Test5',
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
@@ -502,12 +502,12 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "", rhs = '',
silent = 0 silent = 0,
} },
}, },
name = "Test6", name = 'Test6',
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
@@ -516,12 +516,12 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "", rhs = '',
silent = 0 silent = 0,
} },
}, },
name = "Test7", name = 'Test7',
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
@@ -530,12 +530,12 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "", rhs = '',
silent = 0 silent = 0,
} },
}, },
name = "Test8", name = 'Test8',
hidden = 0 hidden = 0,
}, },
{ {
priority = 500, priority = 500,
@@ -544,17 +544,17 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "\"\"", rhs = '""',
silent = 0 silent = 0,
} },
}, },
name = "Test9", name = 'Test9',
hidden = 0 hidden = 0,
} },
}, },
priority = 500, priority = 500,
name = "Test" name = 'Test',
} },
} }
eq(m, expected) eq(m, expected)
@@ -565,12 +565,12 @@ describe('menu_get', function()
command('nnoremenu &Test\\ 1.Test\\ 2 Wargl') command('nnoremenu &Test\\ 1.Test\\ 2 Wargl')
command('nnoremenu &Test4.Test<Tab>3 i space<Esc>') command('nnoremenu &Test4.Test<Tab>3 i space<Esc>')
local m = funcs.menu_get(""); local m = funcs.menu_get('')
local expected = { local expected = {
{ {
shortcut = "T", shortcut = 'T',
hidden = 0, hidden = 0,
actext = "Y", actext = 'Y',
submenus = { submenus = {
{ {
mappings = { mappings = {
@@ -578,21 +578,21 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "inormal<Alt-j>", rhs = 'inormal<Alt-j>',
silent = 0 silent = 0,
} },
}, },
hidden = 0, hidden = 0,
actext = "X x", actext = 'X x',
priority = 500, priority = 500,
name = "Test" name = 'Test',
} },
}, },
priority = 500, priority = 500,
name = "Test" name = 'Test',
}, },
{ {
shortcut = "T", shortcut = 'T',
hidden = 0, hidden = 0,
submenus = { submenus = {
{ {
@@ -602,19 +602,19 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "Wargl", rhs = 'Wargl',
silent = 0 silent = 0,
} },
}, },
name = "Test 2", name = 'Test 2',
hidden = 0 hidden = 0,
} },
}, },
priority = 500, priority = 500,
name = "Test 1" name = 'Test 1',
}, },
{ {
shortcut = "T", shortcut = 'T',
hidden = 0, hidden = 0,
submenus = { submenus = {
{ {
@@ -623,19 +623,19 @@ describe('menu_get', function()
sid = 1, sid = 1,
noremap = 1, noremap = 1,
enabled = 1, enabled = 1,
rhs = "i space<Esc>", rhs = 'i space<Esc>',
silent = 0 silent = 0,
} },
}, },
hidden = 0, hidden = 0,
actext = "3", actext = '3',
priority = 500, priority = 500,
name = "Test" name = 'Test',
} },
}, },
priority = 500, priority = 500,
name = "Test4" name = 'Test4',
} },
} }
eq(m, expected) eq(m, expected)

View File

@@ -18,7 +18,9 @@ local mkdir = helpers.mkdir
local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec' local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec'
if helpers.skip(helpers.is_os('win')) then return end if helpers.skip(helpers.is_os('win')) then
return
end
describe(':mksession', function() describe(':mksession', function()
local session_file = file_prefix .. '.vim' local session_file = file_prefix .. '.vim'

View File

@@ -29,8 +29,7 @@ describe(':mkview', function()
it('viewoption curdir restores local current directory', function() it('viewoption curdir restores local current directory', function()
local cwd_dir = funcs.getcwd() local cwd_dir = funcs.getcwd()
local set_view_dir_command = 'set viewdir=' .. cwd_dir .. local set_view_dir_command = 'set viewdir=' .. cwd_dir .. get_pathsep() .. view_dir
get_pathsep() .. view_dir
-- By default the local current directory should save -- By default the local current directory should save
command(set_view_dir_command) command(set_view_dir_command)
@@ -63,5 +62,4 @@ describe(':mkview', function()
-- The view's local directory should have been saved -- The view's local directory should have been saved
eq(cwd_dir .. get_pathsep() .. local_dir, funcs.getcwd()) eq(cwd_dir .. get_pathsep() .. local_dir, funcs.getcwd())
end) end)
end) end)

View File

@@ -12,9 +12,15 @@ local eval = helpers.eval
local shada_file = 'Xtest.shada' local shada_file = 'Xtest.shada'
local function _clear() local function _clear()
clear{args={'-i', shada_file, -- Need shada for these tests. clear {
'--cmd', 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}, args = {
args_rm={'-i', '--cmd'}} '-i',
shada_file, -- Need shada for these tests.
'--cmd',
'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler',
},
args_rm = { '-i', '--cmd' },
}
end end
describe(':oldfiles', function() describe(':oldfiles', function()
@@ -40,8 +46,8 @@ describe(':oldfiles', function()
feed_command('oldfiles') feed_command('oldfiles')
screen:expect([[ screen:expect([[
| |
1: ]].. add_padding(oldfiles[1]) ..[[ | 1: ]] .. add_padding(oldfiles[1]) .. [[ |
2: ]].. add_padding(oldfiles[2]) ..[[ | 2: ]] .. add_padding(oldfiles[2]) .. [[ |
| |
Press ENTER or type command to continue^ | Press ENTER or type command to continue^ |
]]) ]])
@@ -59,7 +65,7 @@ describe(':oldfiles', function()
feed_command('rshada!') feed_command('rshada!')
local function get_oldfiles(cmd) local function get_oldfiles(cmd)
local t = eval([[split(execute(']]..cmd..[['), "\n")]]) local t = eval([[split(execute(']] .. cmd .. [['), "\n")]])
for i, _ in ipairs(t) do for i, _ in ipairs(t) do
t[i] = t[i]:gsub('^%d+:%s+', '') t[i] = t[i]:gsub('^%d+:%s+', '')
end end
@@ -68,16 +74,16 @@ describe(':oldfiles', function()
end end
local oldfiles = get_oldfiles('oldfiles') local oldfiles = get_oldfiles('oldfiles')
eq({another, file1, file2}, oldfiles) eq({ another, file1, file2 }, oldfiles)
oldfiles = get_oldfiles('filter file_ oldfiles') oldfiles = get_oldfiles('filter file_ oldfiles')
eq({file1, file2}, oldfiles) eq({ file1, file2 }, oldfiles)
oldfiles = get_oldfiles('filter /another/ oldfiles') oldfiles = get_oldfiles('filter /another/ oldfiles')
eq({another}, oldfiles) eq({ another }, oldfiles)
oldfiles = get_oldfiles('filter! file_ oldfiles') oldfiles = get_oldfiles('filter! file_ oldfiles')
eq({another}, oldfiles) eq({ another }, oldfiles)
end) end)
end) end)

View File

@@ -1,6 +1,5 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local clear, eq, command, funcs = local clear, eq, command, funcs = helpers.clear, helpers.eq, helpers.command, helpers.funcs
helpers.clear, helpers.eq, helpers.command, helpers.funcs
describe(':z^', function() describe(':z^', function()
before_each(clear) before_each(clear)

View File

@@ -1,13 +1,13 @@
require('os') require('os')
local luv = require('luv') local luv = require('luv')
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local eval = helpers.eval local eval = helpers.eval
local command = helpers.command local command = helpers.command
local eq, neq = helpers.eq, helpers.neq local eq, neq = helpers.eq, helpers.neq
local tempfile = helpers.tmpname() local tempfile = helpers.tmpname()
local source = helpers.source local source = helpers.source
local matches = helpers.matches local matches = helpers.matches
local read_file = helpers.read_file local read_file = helpers.read_file
-- tmpname() also creates the file on POSIX systems. Remove it again. -- tmpname() also creates the file on POSIX systems. Remove it again.

View File

@@ -15,20 +15,24 @@ local file_base = 'Xtest-functional-ex_cmds-quickfix_commands'
before_each(clear) before_each(clear)
for _, c in ipairs({'l', 'c'}) do for _, c in ipairs({ 'l', 'c' }) do
local file = ('%s.%s'):format(file_base, c) local file = ('%s.%s'):format(file_base, c)
local filecmd = c .. 'file' local filecmd = c .. 'file'
local getfcmd = c .. 'getfile' local getfcmd = c .. 'getfile'
local addfcmd = c .. 'addfile' local addfcmd = c .. 'addfile'
local getlist = (c == 'c') and funcs.getqflist or ( local getlist = (c == 'c') and funcs.getqflist or function()
function() return funcs.getloclist(0) end) return funcs.getloclist(0)
end
describe((':%s*file commands'):format(c), function() describe((':%s*file commands'):format(c), function()
before_each(function() before_each(function()
write_file(file, ([[ write_file(
file,
([[
%s-1.res:700:10:Line 700 %s-1.res:700:10:Line 700
%s-2.res:800:15:Line 800 %s-2.res:800:15:Line 800
]]):format(file, file)) ]]):format(file, file)
)
end) end)
after_each(function() after_each(function()
os.remove(file) os.remove(file)
@@ -39,10 +43,34 @@ for _, c in ipairs({'l', 'c'}) do
-- Second line of each entry (i.e. `nr=-1, …`) was obtained from actual -- Second line of each entry (i.e. `nr=-1, …`) was obtained from actual
-- results. First line (i.e. `{lnum=…`) was obtained from legacy test. -- results. First line (i.e. `{lnum=…`) was obtained from legacy test.
local list = { local list = {
{lnum=700, end_lnum=0, col=10, end_col=0, text='Line 700', module='', {
nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''}, lnum = 700,
{lnum=800, end_lnum=0, col=15, end_col=0, text='Line 800', module='', end_lnum = 0,
nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''}, col = 10,
end_col = 0,
text = 'Line 700',
module = '',
nr = -1,
bufnr = 2,
valid = 1,
pattern = '',
vcol = 0,
['type'] = '',
},
{
lnum = 800,
end_lnum = 0,
col = 15,
end_col = 0,
text = 'Line 800',
module = '',
nr = -1,
bufnr = 3,
valid = 1,
pattern = '',
vcol = 0,
['type'] = '',
},
} }
eq(list, getlist()) eq(list, getlist())
eq(('%s-1.res'):format(file), funcs.bufname(list[1].bufnr)) eq(('%s-1.res'):format(file), funcs.bufname(list[1].bufnr))
@@ -51,33 +79,74 @@ for _, c in ipairs({'l', 'c'}) do
-- Run cfile/lfile from a modified buffer -- Run cfile/lfile from a modified buffer
command('set nohidden') command('set nohidden')
command('enew!') command('enew!')
curbufmeths.set_lines(1, 1, true, {'Quickfix'}) curbufmeths.set_lines(1, 1, true, { 'Quickfix' })
eq(('Vim(%s):E37: No write since last change (add ! to override)'):format( eq(
filecmd), ('Vim(%s):E37: No write since last change (add ! to override)'):format(filecmd),
exc_exec(('%s %s'):format(filecmd, file))) exc_exec(('%s %s'):format(filecmd, file))
)
write_file(file, ([[ write_file(
file,
([[
%s-3.res:900:30:Line 900 %s-3.res:900:30:Line 900
]]):format(file)) ]]):format(file)
)
command(('%s %s'):format(addfcmd, file)) command(('%s %s'):format(addfcmd, file))
list[#list + 1] = { list[#list + 1] = {
lnum=900, end_lnum=0, col=30, end_col=0, text='Line 900', module='', lnum = 900,
nr=-1, bufnr=5, valid=1, pattern='', vcol=0, ['type']='', end_lnum = 0,
col = 30,
end_col = 0,
text = 'Line 900',
module = '',
nr = -1,
bufnr = 5,
valid = 1,
pattern = '',
vcol = 0,
['type'] = '',
} }
eq(list, getlist()) eq(list, getlist())
eq(('%s-3.res'):format(file), funcs.bufname(list[3].bufnr)) eq(('%s-3.res'):format(file), funcs.bufname(list[3].bufnr))
write_file(file, ([[ write_file(
file,
([[
%s-1.res:222:77:Line 222 %s-1.res:222:77:Line 222
%s-2.res:333:88:Line 333 %s-2.res:333:88:Line 333
]]):format(file, file)) ]]):format(file, file)
)
command('enew!') command('enew!')
command(('%s %s'):format(getfcmd, file)) command(('%s %s'):format(getfcmd, file))
list = { list = {
{lnum=222, end_lnum=0, col=77, end_col=0, text='Line 222', module='', {
nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''}, lnum = 222,
{lnum=333, end_lnum=0, col=88, end_col=0, text='Line 333', module='', end_lnum = 0,
nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''}, col = 77,
end_col = 0,
text = 'Line 222',
module = '',
nr = -1,
bufnr = 2,
valid = 1,
pattern = '',
vcol = 0,
['type'] = '',
},
{
lnum = 333,
end_lnum = 0,
col = 88,
end_col = 0,
text = 'Line 333',
module = '',
nr = -1,
bufnr = 3,
valid = 1,
pattern = '',
vcol = 0,
['type'] = '',
},
} }
eq(list, getlist()) eq(list, getlist())
eq(('%s-1.res'):format(file), funcs.bufname(list[1].bufnr)) eq(('%s-1.res'):format(file), funcs.bufname(list[1].bufnr))
@@ -109,7 +178,7 @@ describe('quickfix', function()
call append(0, ['New line 1', 'New line 2', 'New line 3']) call append(0, ['New line 1', 'New line 2', 'New line 3'])
silent ll silent ll
]]) ]])
eq({0, 6, 1, 0, 1}, funcs.getcurpos()) eq({ 0, 6, 1, 0, 1 }, funcs.getcurpos())
end) end)
it('BufAdd does not cause E16 when reusing quickfix buffer #18135', function() it('BufAdd does not cause E16 when reusing quickfix buffer #18135', function()
@@ -127,11 +196,14 @@ describe('quickfix', function()
end) end)
it(':vimgrep can specify Unicode pattern without delimiters', function() it(':vimgrep can specify Unicode pattern without delimiters', function()
eq('Vim(vimgrep):E480: No match: →', exc_exec('vimgrep → test/functional/fixtures/tty-test.c')) eq(
'Vim(vimgrep):E480: No match: →',
exc_exec('vimgrep → test/functional/fixtures/tty-test.c')
)
local screen = Screen.new(40, 6) local screen = Screen.new(40, 6)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
[1] = {reverse = true}, -- IncSearch [1] = { reverse = true }, -- IncSearch
}) })
screen:attach() screen:attach()
feed('i→<Esc>:vimgrep →') feed('i→<Esc>:vimgrep →')

View File

@@ -11,4 +11,3 @@ describe(':qa', function()
-- errors -- errors
end) end)
end) end)

View File

@@ -17,7 +17,7 @@ before_each(clear)
local function source(code) local function source(code)
write_file(tmpfile, code) write_file(tmpfile, code)
command('source '..tmpfile) command('source ' .. tmpfile)
end end
describe('script_get-based command', function() describe('script_get-based command', function()
@@ -30,29 +30,48 @@ describe('script_get-based command', function()
local function test_garbage_exec(cmd, check_neq) local function test_garbage_exec(cmd, check_neq)
describe(cmd, function() describe(cmd, function()
it('works correctly when skipping oneline variant', function() it('works correctly when skipping oneline variant', function()
eq(true, pcall(source, (dedent([[ eq(
true,
pcall(
source,
(dedent([[
if 0 if 0
%s %s %s %s
endif endif
]])):format(cmd, garbage))) ]])):format(cmd, garbage)
)
)
eq('', exec_capture('messages')) eq('', exec_capture('messages'))
if check_neq then if check_neq then
neq(0, exc_exec(dedent([[ neq(
0,
exc_exec(dedent([[
%s %s %s %s
]])):format(cmd, garbage)) ]])):format(cmd, garbage)
)
end end
end) end)
it('works correctly when skipping HEREdoc variant', function() it('works correctly when skipping HEREdoc variant', function()
eq(true, pcall(source, (dedent([[ eq(
true,
pcall(
source,
(dedent([[
if 0 if 0
%s << EOF %s << EOF
%s %s
EOF EOF
endif endif
]])):format(cmd, garbage))) ]])):format(cmd, garbage)
)
)
eq('', exec_capture('messages')) eq('', exec_capture('messages'))
if check_neq then if check_neq then
eq(true, pcall(source, (dedent([[ eq(
true,
pcall(
source,
(dedent([[
let g:exc = 0 let g:exc = 0
try try
%s << EOF %s << EOF
@@ -61,7 +80,9 @@ describe('script_get-based command', function()
catch catch
let g:exc = v:exception let g:exc = v:exception
endtry endtry
]])):format(cmd, garbage))) ]])):format(cmd, garbage)
)
)
neq(0, meths.get_var('exc')) neq(0, meths.get_var('exc'))
end end
end) end)

View File

@@ -9,21 +9,21 @@ describe('sign', function()
-- place a sign with id 34 to first buffer -- place a sign with id 34 to first buffer
nvim('command', 'sign define Foo text=+ texthl=Delimiter linehl=Comment numhl=Number') nvim('command', 'sign define Foo text=+ texthl=Delimiter linehl=Comment numhl=Number')
local buf1 = nvim('eval', 'bufnr("%")') local buf1 = nvim('eval', 'bufnr("%")')
nvim('command', 'sign place 34 line=3 name=Foo buffer='..buf1) nvim('command', 'sign place 34 line=3 name=Foo buffer=' .. buf1)
-- create a second buffer and place the sign on it as well -- create a second buffer and place the sign on it as well
nvim('command', 'new') nvim('command', 'new')
local buf2 = nvim('eval', 'bufnr("%")') local buf2 = nvim('eval', 'bufnr("%")')
nvim('command', 'sign place 34 line=3 name=Foo buffer='..buf2) nvim('command', 'sign place 34 line=3 name=Foo buffer=' .. buf2)
-- now unplace without specifying a buffer -- now unplace without specifying a buffer
nvim('command', 'sign unplace 34') nvim('command', 'sign unplace 34')
eq("--- Signs ---\n", nvim('exec', 'sign place buffer='..buf1, true)) eq('--- Signs ---\n', nvim('exec', 'sign place buffer=' .. buf1, true))
eq("--- Signs ---\n", nvim('exec', 'sign place buffer='..buf2, true)) eq('--- Signs ---\n', nvim('exec', 'sign place buffer=' .. buf2, true))
end) end)
end) end)
end) end)
describe('define {id}', function() describe('define {id}', function()
it ('does not leak memory when specifying multiple times the same argument', function() it('does not leak memory when specifying multiple times the same argument', function()
nvim('command', 'sign define Foo culhl=Normal culhl=Normal') nvim('command', 'sign define Foo culhl=Normal culhl=Normal')
assert_alive() assert_alive()
end) end)

View File

@@ -52,13 +52,16 @@ describe(':source', function()
meths.set_option_value('shellslash', false, {}) meths.set_option_value('shellslash', false, {})
mkdir('Xshellslash') mkdir('Xshellslash')
write_file([[Xshellslash/Xstack.vim]], [[ write_file(
[[Xshellslash/Xstack.vim]],
[[
let g:stack1 = expand('<stack>') let g:stack1 = expand('<stack>')
set shellslash set shellslash
let g:stack2 = expand('<stack>') let g:stack2 = expand('<stack>')
set noshellslash set noshellslash
let g:stack3 = expand('<stack>') let g:stack3 = expand('<stack>')
]]) ]]
)
for _ = 1, 2 do for _ = 1, 2 do
command([[source Xshellslash/Xstack.vim]]) command([[source Xshellslash/Xstack.vim]])
@@ -67,13 +70,16 @@ describe(':source', function()
matches([[Xshellslash\Xstack%.vim]], meths.get_var('stack3')) matches([[Xshellslash\Xstack%.vim]], meths.get_var('stack3'))
end end
write_file([[Xshellslash/Xstack.lua]], [[ write_file(
[[Xshellslash/Xstack.lua]],
[[
vim.g.stack1 = vim.fn.expand('<stack>') vim.g.stack1 = vim.fn.expand('<stack>')
vim.o.shellslash = true vim.o.shellslash = true
vim.g.stack2 = vim.fn.expand('<stack>') vim.g.stack2 = vim.fn.expand('<stack>')
vim.o.shellslash = false vim.o.shellslash = false
vim.g.stack3 = vim.fn.expand('<stack>') vim.g.stack3 = vim.fn.expand('<stack>')
]]) ]]
)
for _ = 1, 2 do for _ = 1, 2 do
command([[source Xshellslash/Xstack.lua]]) command([[source Xshellslash/Xstack.lua]])
@@ -101,11 +107,11 @@ describe(':source', function()
eq("{'k': 'v'}", exec_capture('echo b')) eq("{'k': 'v'}", exec_capture('echo b'))
-- Script items are created only on script var access -- Script items are created only on script var access
eq("1", exec_capture('echo c')) eq('1', exec_capture('echo c'))
eq("0zBEEFCAFE", exec_capture('echo d')) eq('0zBEEFCAFE', exec_capture('echo d'))
exec('set cpoptions+=C') exec('set cpoptions+=C')
eq('Vim(let):E723: Missing end of Dictionary \'}\': ', exc_exec('source')) eq("Vim(let):E723: Missing end of Dictionary '}': ", exc_exec('source'))
end) end)
it('selection in current buffer', function() it('selection in current buffer', function()
@@ -132,14 +138,14 @@ describe(':source', function()
feed_command(':source') feed_command(':source')
eq('4', exec_capture('echo a')) eq('4', exec_capture('echo a'))
eq("{'K': 'V'}", exec_capture('echo b')) eq("{'K': 'V'}", exec_capture('echo b'))
eq("<SNR>1_C()", exec_capture('echo D()')) eq('<SNR>1_C()', exec_capture('echo D()'))
-- Source last line only -- Source last line only
feed_command(':$source') feed_command(':$source')
eq('Vim(echo):E117: Unknown function: s:C', exc_exec('echo D()')) eq('Vim(echo):E117: Unknown function: s:C', exc_exec('echo D()'))
exec('set cpoptions+=C') exec('set cpoptions+=C')
eq('Vim(let):E723: Missing end of Dictionary \'}\': ', exc_exec("'<,'>source")) eq("Vim(let):E723: Missing end of Dictionary '}': ", exc_exec("'<,'>source"))
end) end)
it('does not break if current buffer is modified while sourced', function() it('does not break if current buffer is modified while sourced', function()
@@ -163,12 +169,15 @@ describe(':source', function()
it('can source lua files', function() it('can source lua files', function()
local test_file = 'test.lua' local test_file = 'test.lua'
write_file(test_file, [[ write_file(
test_file,
[[
vim.g.sourced_lua = 1 vim.g.sourced_lua = 1
vim.g.sfile_value = vim.fn.expand('<sfile>') vim.g.sfile_value = vim.fn.expand('<sfile>')
vim.g.stack_value = vim.fn.expand('<stack>') vim.g.stack_value = vim.fn.expand('<stack>')
vim.g.script_value = vim.fn.expand('<script>') vim.g.script_value = vim.fn.expand('<script>')
]]) ]]
)
command('set shellslash') command('set shellslash')
command('source ' .. test_file) command('source ' .. test_file)
@@ -245,22 +254,22 @@ describe(':source', function()
local test_file = 'test.lua' local test_file = 'test.lua'
-- Does throw E484 for unreadable files -- Does throw E484 for unreadable files
local ok, result = pcall(exec_capture, ":source "..test_file ..'noexisting') local ok, result = pcall(exec_capture, ':source ' .. test_file .. 'noexisting')
eq(false, ok) eq(false, ok)
neq(nil, result:find("E484")) neq(nil, result:find('E484'))
-- Doesn't throw for parsing error -- Doesn't throw for parsing error
write_file (test_file, "vim.g.c = ") write_file(test_file, 'vim.g.c = ')
ok, result = pcall(exec_capture, ":source "..test_file) ok, result = pcall(exec_capture, ':source ' .. test_file)
eq(false, ok) eq(false, ok)
eq(nil, result:find("E484")) eq(nil, result:find('E484'))
os.remove(test_file) os.remove(test_file)
-- Doesn't throw for runtime error -- Doesn't throw for runtime error
write_file (test_file, "error('Cause error anyway :D')") write_file(test_file, "error('Cause error anyway :D')")
ok, result = pcall(exec_capture, ":source "..test_file) ok, result = pcall(exec_capture, ':source ' .. test_file)
eq(false, ok) eq(false, ok)
eq(nil, result:find("E484")) eq(nil, result:find('E484'))
os.remove(test_file) os.remove(test_file)
end) end)
end) end)

View File

@@ -1,8 +1,7 @@
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local luv = require('luv') local luv = require('luv')
local eq, eval, expect, exec = local eq, eval, expect, exec = helpers.eq, helpers.eval, helpers.expect, helpers.exec
helpers.eq, helpers.eval, helpers.expect, helpers.exec
local assert_alive = helpers.assert_alive local assert_alive = helpers.assert_alive
local clear = helpers.clear local clear = helpers.clear
local command = helpers.command local command = helpers.command
@@ -32,24 +31,24 @@ describe(':recover', function()
it('fails if given a non-existent swapfile', function() it('fails if given a non-existent swapfile', function()
local swapname = 'bogus_swapfile' local swapname = 'bogus_swapfile'
local swapname2 = 'bogus_swapfile.swp' local swapname2 = 'bogus_swapfile.swp'
eq('Vim(recover):E305: No swap file found for '..swapname, eq(
pcall_err(command, 'recover '..swapname)) -- Should not segfault. #2117 'Vim(recover):E305: No swap file found for ' .. swapname,
pcall_err(command, 'recover ' .. swapname)
) -- Should not segfault. #2117
-- Also check filename ending with ".swp". #9504 -- Also check filename ending with ".swp". #9504
eq('Vim(recover):E306: Cannot open '..swapname2, eq('Vim(recover):E306: Cannot open ' .. swapname2, pcall_err(command, 'recover ' .. swapname2)) -- Should not segfault. #2117
pcall_err(command, 'recover '..swapname2)) -- Should not segfault. #2117
assert_alive() assert_alive()
end) end)
end) end)
describe("preserve and (R)ecover with custom 'directory'", function() describe("preserve and (R)ecover with custom 'directory'", function()
local swapdir = luv.cwd()..'/Xtest_recover_dir' local swapdir = luv.cwd() .. '/Xtest_recover_dir'
local testfile = 'Xtest_recover_file1' local testfile = 'Xtest_recover_file1'
-- Put swapdir at the start of the 'directory' list. #1836 -- Put swapdir at the start of the 'directory' list. #1836
-- Note: `set swapfile` *must* go after `set directory`: otherwise it may -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
-- attempt to create a swapfile in different directory. -- attempt to create a swapfile in different directory.
local init = [[ local init = [[
set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[// set directory^=]] .. swapdir:gsub([[\]], [[\\]]) .. [[//
set swapfile fileformat=unix undolevels=-1 set swapfile fileformat=unix undolevels=-1
]] ]]
@@ -67,7 +66,7 @@ describe("preserve and (R)ecover with custom 'directory'", function()
local function setup_swapname() local function setup_swapname()
exec(init) exec(init)
command('edit! '..testfile) command('edit! ' .. testfile)
feed('isometext<esc>') feed('isometext<esc>')
exec('redir => g:swapname | silent swapname | redir END') exec('redir => g:swapname | silent swapname | redir END')
return eval('g:swapname') return eval('g:swapname')
@@ -75,23 +74,23 @@ describe("preserve and (R)ecover with custom 'directory'", function()
local function test_recover(swappath1) local function test_recover(swappath1)
-- Start another Nvim instance. -- Start another Nvim instance.
local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'}, true) local nvim2 = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed' }, true)
set_session(nvim2) set_session(nvim2)
exec(init) exec(init)
-- Use the "SwapExists" event to choose the (R)ecover choice at the dialog. -- Use the "SwapExists" event to choose the (R)ecover choice at the dialog.
command('autocmd SwapExists * let v:swapchoice = "r"') command('autocmd SwapExists * let v:swapchoice = "r"')
command('silent edit! '..testfile) command('silent edit! ' .. testfile)
exec('redir => g:swapname | silent swapname | redir END') exec('redir => g:swapname | silent swapname | redir END')
local swappath2 = eval('g:swapname') local swappath2 = eval('g:swapname')
expect('sometext') expect('sometext')
-- swapfile from session 1 should end in .swp -- swapfile from session 1 should end in .swp
eq(testfile..'.swp', string.match(swappath1, '[^%%]+$')) eq(testfile .. '.swp', string.match(swappath1, '[^%%]+$'))
-- swapfile from session 2 should end in .swo -- swapfile from session 2 should end in .swo
eq(testfile..'.swo', string.match(swappath2, '[^%%]+$')) eq(testfile .. '.swo', string.match(swappath2, '[^%%]+$'))
-- Verify that :swapname was not truncated (:help 'shortmess'). -- Verify that :swapname was not truncated (:help 'shortmess').
ok(nil == string.find(swappath1, '%.%.%.')) ok(nil == string.find(swappath1, '%.%.%.'))
ok(nil == string.find(swappath2, '%.%.%.')) ok(nil == string.find(swappath2, '%.%.%.'))
@@ -116,28 +115,27 @@ describe("preserve and (R)ecover with custom 'directory'", function()
screen0:attach() screen0:attach()
local child_server = new_pipename() local child_server = new_pipename()
funcs.termopen({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server }, { funcs.termopen({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server }, {
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) })
screen0:expect({any = pesc('[No Name]')}) -- Wait for the child process to start. screen0:expect({ any = pesc('[No Name]') }) -- Wait for the child process to start.
local child_session = helpers.connect(child_server) local child_session = helpers.connect(child_server)
set_session(child_session) set_session(child_session)
local swappath1 = setup_swapname() local swappath1 = setup_swapname()
set_session(nvim0) set_session(nvim0)
command('call chanclose(&channel)') -- Kill the child process. command('call chanclose(&channel)') -- Kill the child process.
screen0:expect({any = pesc('[Process exited 1]')}) -- Wait for the child process to stop. screen0:expect({ any = pesc('[Process exited 1]') }) -- Wait for the child process to stop.
test_recover(swappath1) test_recover(swappath1)
end) end)
end) end)
describe('swapfile detection', function() describe('swapfile detection', function()
local swapdir = luv.cwd()..'/Xtest_swapdialog_dir' local swapdir = luv.cwd() .. '/Xtest_swapdialog_dir'
local nvim0 local nvim0
-- Put swapdir at the start of the 'directory' list. #1836 -- Put swapdir at the start of the 'directory' list. #1836
-- Note: `set swapfile` *must* go after `set directory`: otherwise it may -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
-- attempt to create a swapfile in different directory. -- attempt to create a swapfile in different directory.
local init = [[ local init = [[
set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[// set directory^=]] .. swapdir:gsub([[\]], [[\\]]) .. [[//
set swapfile fileformat=unix nomodified undolevels=-1 nohidden set swapfile fileformat=unix nomodified undolevels=-1 nohidden
]] ]]
before_each(function() before_each(function()
@@ -155,67 +153,88 @@ describe('swapfile detection', function()
it('always show swapfile dialog #8840 #9027', function() it('always show swapfile dialog #8840 #9027', function()
local testfile = 'Xtest_swapdialog_file1' local testfile = 'Xtest_swapdialog_file1'
local expected_no_dialog = '^'..(' '):rep(256)..'|\n' local expected_no_dialog = '^' .. (' '):rep(256) .. '|\n'
for _=1,37 do for _ = 1, 37 do
expected_no_dialog = expected_no_dialog..'~'..(' '):rep(255)..'|\n' expected_no_dialog = expected_no_dialog .. '~' .. (' '):rep(255) .. '|\n'
end end
expected_no_dialog = expected_no_dialog..testfile..(' '):rep(216)..'0,0-1 All|\n' expected_no_dialog = expected_no_dialog .. testfile .. (' '):rep(216) .. '0,0-1 All|\n'
expected_no_dialog = expected_no_dialog..(' '):rep(256)..'|\n' expected_no_dialog = expected_no_dialog .. (' '):rep(256) .. '|\n'
exec(init) exec(init)
command('edit! '..testfile) command('edit! ' .. testfile)
feed('isometext<esc>') feed('isometext<esc>')
command('preserve') command('preserve')
-- Start another Nvim instance. -- Start another Nvim instance.
local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'}, true, nil, true) local nvim2 = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed' }, true, nil, true)
set_session(nvim2) set_session(nvim2)
local screen2 = Screen.new(256, 40) local screen2 = Screen.new(256, 40)
screen2:attach() screen2:attach()
exec(init) exec(init)
command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog). command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog).
-- With shortmess+=F -- With shortmess+=F
command('set shortmess+=F') command('set shortmess+=F')
feed(':edit '..testfile..'<CR>') feed(':edit ' .. testfile .. '<CR>')
screen2:expect{any=[[E325: ATTENTION.*]]..'\n'..[[Found a swap file by the name ".*]] screen2:expect {
..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]} any = [[E325: ATTENTION.*]]
feed('e') -- Chose "Edit" at the swap dialog. .. '\n'
.. [[Found a swap file by the name ".*]]
.. [[Xtest_swapdialog_dir[/\].*]]
.. testfile
.. [[%.swp"]],
}
feed('e') -- Chose "Edit" at the swap dialog.
screen2:expect(expected_no_dialog) screen2:expect(expected_no_dialog)
-- With :silent and shortmess+=F -- With :silent and shortmess+=F
feed(':silent edit %<CR>') feed(':silent edit %<CR>')
screen2:expect{any=[[Found a swap file by the name ".*]] screen2:expect {
..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]} any = [[Found a swap file by the name ".*]]
feed('e') -- Chose "Edit" at the swap dialog. .. [[Xtest_swapdialog_dir[/\].*]]
.. testfile
.. [[%.swp"]],
}
feed('e') -- Chose "Edit" at the swap dialog.
screen2:expect(expected_no_dialog) screen2:expect(expected_no_dialog)
-- With :silent! and shortmess+=F -- With :silent! and shortmess+=F
feed(':silent! edit %<CR>') feed(':silent! edit %<CR>')
screen2:expect{any=[[Found a swap file by the name ".*]] screen2:expect {
..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]} any = [[Found a swap file by the name ".*]]
feed('e') -- Chose "Edit" at the swap dialog. .. [[Xtest_swapdialog_dir[/\].*]]
.. testfile
.. [[%.swp"]],
}
feed('e') -- Chose "Edit" at the swap dialog.
screen2:expect(expected_no_dialog) screen2:expect(expected_no_dialog)
-- With API (via eval/Vimscript) call and shortmess+=F -- With API (via eval/Vimscript) call and shortmess+=F
feed(':call nvim_command("edit %")<CR>') feed(':call nvim_command("edit %")<CR>')
screen2:expect{any=[[Found a swap file by the name ".*]] screen2:expect {
..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]} any = [[Found a swap file by the name ".*]]
feed('e') -- Chose "Edit" at the swap dialog. .. [[Xtest_swapdialog_dir[/\].*]]
.. testfile
.. [[%.swp"]],
}
feed('e') -- Chose "Edit" at the swap dialog.
feed('<c-c>') feed('<c-c>')
screen2:expect(expected_no_dialog) screen2:expect(expected_no_dialog)
-- With API call and shortmess+=F -- With API call and shortmess+=F
async_meths.command('edit %') async_meths.command('edit %')
screen2:expect{any=[[Found a swap file by the name ".*]] screen2:expect {
..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]} any = [[Found a swap file by the name ".*]]
feed('e') -- Chose "Edit" at the swap dialog. .. [[Xtest_swapdialog_dir[/\].*]]
.. testfile
.. [[%.swp"]],
}
feed('e') -- Chose "Edit" at the swap dialog.
expect_msg_seq({ expect_msg_seq({
ignore={'redraw'}, ignore = { 'redraw' },
seqs={ seqs = {
{ {'notification', 'nvim_error_event', {0, 'Vim(edit):E325: ATTENTION'}}, { { 'notification', 'nvim_error_event', { 0, 'Vim(edit):E325: ATTENTION' } } },
} },
}
}) })
feed('<cr>') feed('<cr>')
@@ -226,7 +245,7 @@ describe('swapfile detection', function()
exec(init) exec(init)
command('edit Xfile1') command('edit Xfile1')
command("put ='some text...'") command("put ='some text...'")
command('preserve') -- Make sure the swap file exists. command('preserve') -- Make sure the swap file exists.
local nvimpid = funcs.getpid() local nvimpid = funcs.getpid()
local nvim1 = spawn(new_argv(), true, nil, true) local nvim1 = spawn(new_argv(), true, nil, true)
@@ -244,23 +263,23 @@ describe('swapfile detection', function()
it('selecting "q" in the attention prompt', function() it('selecting "q" in the attention prompt', function()
exec(init) exec(init)
command('edit Xfile1') command('edit Xfile1')
command('preserve') -- Make sure the swap file exists. command('preserve') -- Make sure the swap file exists.
local screen = Screen.new(75, 18) local screen = Screen.new(75, 18)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
[1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg [1] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
}) })
local nvim1 = spawn(new_argv(), true, nil, true) local nvim1 = spawn(new_argv(), true, nil, true)
set_session(nvim1) set_session(nvim1)
screen:attach() screen:attach()
exec(init) exec(init)
command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog). command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog).
feed(':split Xfile1\n') feed(':split Xfile1\n')
-- The default SwapExists handler does _not_ skip this prompt. -- The default SwapExists handler does _not_ skip this prompt.
screen:expect({ screen:expect({
any = pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^') any = pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^'),
}) })
feed('q') feed('q')
feed(':<CR>') feed(':<CR>')
@@ -275,14 +294,14 @@ describe('swapfile detection', function()
set_session(nvim2) set_session(nvim2)
screen:attach() screen:attach()
exec(init) exec(init)
command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog). command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog).
command('set more') command('set more')
command('au bufadd * let foo_w = wincol()') command('au bufadd * let foo_w = wincol()')
feed(':e Xfile1<CR>') feed(':e Xfile1<CR>')
screen:expect({any = pesc('{1:-- More --}^')}) screen:expect({ any = pesc('{1:-- More --}^') })
feed('<Space>') feed('<Space>')
screen:expect({ screen:expect({
any = pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^') any = pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^'),
}) })
feed('q') feed('q')
command([[echo 'hello']]) command([[echo 'hello']])
@@ -299,15 +318,15 @@ describe('swapfile detection', function()
local function test_swapfile_after_reboot(swapexists, on_swapfile_running) local function test_swapfile_after_reboot(swapexists, on_swapfile_running)
local screen = Screen.new(75, 30) local screen = Screen.new(75, 30)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
[1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg [1] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
[2] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg [2] = { background = Screen.colors.Red, foreground = Screen.colors.White }, -- ErrorMsg
}) })
screen:attach() screen:attach()
exec(init) exec(init)
if not swapexists then if not swapexists then
command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog). command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog).
end end
command('set nohidden') command('set nohidden')
@@ -361,10 +380,12 @@ describe('swapfile detection', function()
luv.fs_utime(swname, atime, atime) luv.fs_utime(swname, atime, atime)
feed(':edit Xswaptest<CR>') feed(':edit Xswaptest<CR>')
screen:expect({any = table.concat({ screen:expect({
pesc('{2:E325: ATTENTION}'), any = table.concat({
pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort: }^'), pesc('{2:E325: ATTENTION}'),
}, '.*')}) pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort: }^'),
}, '.*'),
})
feed('e') feed('e')
end end
@@ -372,12 +393,14 @@ describe('swapfile detection', function()
-- oldtest: Test_nocatch_process_still_running() -- oldtest: Test_nocatch_process_still_running()
it('swapfile created before boot vim-patch:8.2.2586', function() it('swapfile created before boot vim-patch:8.2.2586', function()
test_swapfile_after_reboot(false, function(screen) test_swapfile_after_reboot(false, function(screen)
screen:expect({any = table.concat({ screen:expect({
pesc('{2:E325: ATTENTION}'), any = table.concat({
'file name: .*Xswaptest', pesc('{2:E325: ATTENTION}'),
'process ID: %d* %(STILL RUNNING%)', 'file name: .*Xswaptest',
pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^'), 'process ID: %d* %(STILL RUNNING%)',
}, '.*')}) pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^'),
}, '.*'),
})
end) end)
end) end)
@@ -386,33 +409,35 @@ describe('swapfile detection', function()
screen:expect({ any = 'W325: Ignoring swapfile from Nvim process' }) screen:expect({ any = 'W325: Ignoring swapfile from Nvim process' })
end) end)
end) end)
end) end)
describe('quitting swapfile dialog on startup stops TUI properly', function() describe('quitting swapfile dialog on startup stops TUI properly', function()
local swapdir = luv.cwd()..'/Xtest_swapquit_dir' local swapdir = luv.cwd() .. '/Xtest_swapquit_dir'
local testfile = 'Xtest_swapquit_file1' local testfile = 'Xtest_swapquit_file1'
local otherfile = 'Xtest_swapquit_file2' local otherfile = 'Xtest_swapquit_file2'
-- Put swapdir at the start of the 'directory' list. #1836 -- Put swapdir at the start of the 'directory' list. #1836
-- Note: `set swapfile` *must* go after `set directory`: otherwise it may -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
-- attempt to create a swapfile in different directory. -- attempt to create a swapfile in different directory.
local init_dir = [[set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[//]] local init_dir = [[set directory^=]] .. swapdir:gsub([[\]], [[\\]]) .. [[//]]
local init_set = [[set swapfile fileformat=unix nomodified undolevels=-1 nohidden]] local init_set = [[set swapfile fileformat=unix nomodified undolevels=-1 nohidden]]
before_each(function() before_each(function()
clear({args = {'--cmd', init_dir, '--cmd', init_set}}) clear({ args = { '--cmd', init_dir, '--cmd', init_set } })
rmdir(swapdir) rmdir(swapdir)
mkdir(swapdir) mkdir(swapdir)
write_file(testfile, [[ write_file(
testfile,
[[
first first
second second
third third
]]) ]]
command('edit! '..testfile) )
command('edit! ' .. testfile)
feed('Gisometext<esc>') feed('Gisometext<esc>')
poke_eventloop() poke_eventloop()
clear() -- Leaves a swap file behind clear() -- Leaves a swap file behind
meths.ui_attach(80, 30, {}) meths.ui_attach(80, 30, {})
end) end)
after_each(function() after_each(function()
@@ -422,63 +447,100 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
end) end)
it('(Q)uit at first file argument', function() it('(Q)uit at first file argument', function()
local chan = funcs.termopen({nvim_prog, '-u', 'NONE', '-i', 'NONE', local chan = funcs.termopen(
'--cmd', init_dir, '--cmd', init_set, { nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', init_dir, '--cmd', init_set, testfile },
testfile}, { {
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) }
)
retry(nil, nil, function() retry(nil, nil, function()
eq('[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:', eq(
eval("getline('$')->trim(' ', 2)")) '[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:',
eval("getline('$')->trim(' ', 2)")
)
end) end)
meths.chan_send(chan, 'q') meths.chan_send(chan, 'q')
retry(nil, nil, function() retry(nil, nil, function()
eq({'', '[Process exited 1]', ''}, eq(
eval("[1, 2, '$']->map({_, lnum -> getline(lnum)->trim(' ', 2)})")) { '', '[Process exited 1]', '' },
eval("[1, 2, '$']->map({_, lnum -> getline(lnum)->trim(' ', 2)})")
)
end) end)
end) end)
it('(A)bort at second file argument with -p', function() it('(A)bort at second file argument with -p', function()
local chan = funcs.termopen({nvim_prog, '-u', 'NONE', '-i', 'NONE', local chan = funcs.termopen({
'--cmd', init_dir, '--cmd', init_set, nvim_prog,
'-p', otherfile, testfile}, { '-u',
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } 'NONE',
}) '-i',
'NONE',
'--cmd',
init_dir,
'--cmd',
init_set,
'-p',
otherfile,
testfile,
}, {
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
retry(nil, nil, function() retry(nil, nil, function()
eq('[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:', eq(
eval("getline('$')->trim(' ', 2)")) '[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:',
eval("getline('$')->trim(' ', 2)")
)
end) end)
meths.chan_send(chan, 'a') meths.chan_send(chan, 'a')
retry(nil, nil, function() retry(nil, nil, function()
eq({'', '[Process exited 1]', ''}, eq(
eval("[1, 2, '$']->map({_, lnum -> getline(lnum)->trim(' ', 2)})")) { '', '[Process exited 1]', '' },
eval("[1, 2, '$']->map({_, lnum -> getline(lnum)->trim(' ', 2)})")
)
end) end)
end) end)
it('(Q)uit at file opened by -t', function() it('(Q)uit at file opened by -t', function()
write_file(otherfile, ([[ write_file(
otherfile,
([[
!_TAG_FILE_ENCODING utf-8 // !_TAG_FILE_ENCODING utf-8 //
first %s /^ \zsfirst$/ first %s /^ \zsfirst$/
second %s /^ \zssecond$/ second %s /^ \zssecond$/
third %s /^ \zsthird$/]]):format(testfile, testfile, testfile)) third %s /^ \zsthird$/]]):format(testfile, testfile, testfile)
local chan = funcs.termopen({nvim_prog, '-u', 'NONE', '-i', 'NONE', )
'--cmd', init_dir, '--cmd', init_set, local chan = funcs.termopen({
'--cmd', 'set tags='..otherfile, '-tsecond'}, { nvim_prog,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } '-u',
}) 'NONE',
'-i',
'NONE',
'--cmd',
init_dir,
'--cmd',
init_set,
'--cmd',
'set tags=' .. otherfile,
'-tsecond',
}, {
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
retry(nil, nil, function() retry(nil, nil, function()
eq('[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:', eq(
eval("getline('$')->trim(' ', 2)")) '[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:',
eval("getline('$')->trim(' ', 2)")
)
end) end)
meths.chan_send(chan, 'q') meths.chan_send(chan, 'q')
retry(nil, nil, function() retry(nil, nil, function()
eq('Press ENTER or type command to continue', eq('Press ENTER or type command to continue', eval("getline('$')->trim(' ', 2)"))
eval("getline('$')->trim(' ', 2)"))
end) end)
meths.chan_send(chan, '\r') meths.chan_send(chan, '\r')
retry(nil, nil, function() retry(nil, nil, function()
eq({'', '[Process exited 1]', ''}, eq(
eval("[1, 2, '$']->map({_, lnum -> getline(lnum)->trim(' ', 2)})")) { '', '[Process exited 1]', '' },
eval("[1, 2, '$']->map({_, lnum -> getline(lnum)->trim(' ', 2)})")
)
end) end)
end) end)
end) end)

View File

@@ -8,10 +8,11 @@ describe(':syntax', function()
before_each(clear) before_each(clear)
describe('keyword', function() describe('keyword', function()
it('does not crash when group name contains unprintable characters', it('does not crash when group name contains unprintable characters', function()
function() eq(
eq('Vim(syntax):E669: Unprintable character in group name', 'Vim(syntax):E669: Unprintable character in group name',
exc_exec('syntax keyword \024 foo bar')) exc_exec('syntax keyword \024 foo bar')
)
end) end)
end) end)
end) end)

View File

@@ -22,7 +22,7 @@ describe(':trust', function()
before_each(function() before_each(function()
helpers.write_file('test_file', 'test') helpers.write_file('test_file', 'test')
clear{env={XDG_STATE_HOME=xstate}} clear { env = { XDG_STATE_HOME = xstate } }
end) end)
after_each(function() after_each(function()
@@ -72,7 +72,10 @@ describe(':trust', function()
local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust)) eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust))
matches('^Removed ".*test_file" from trust database%.$', exec_capture('trust ++remove test_file')) matches(
'^Removed ".*test_file" from trust database%.$',
exec_capture('trust ++remove test_file')
)
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
eq(string.format(''), vim.trim(trust)) eq(string.format(''), vim.trim(trust))
end) end)

View File

@@ -11,13 +11,15 @@ local function last_set_tests(cmd)
local script_location, script_file local script_location, script_file
-- All test cases below use the same nvim instance. -- All test cases below use the same nvim instance.
setup(function() setup(function()
clear{args={'-V1'}} clear { args = { '-V1' } }
script_file = 'test_verbose.lua' script_file = 'test_verbose.lua'
local current_dir = call_viml_function('getcwd', {}) local current_dir = call_viml_function('getcwd', {})
current_dir = call_viml_function('fnamemodify', {current_dir, ':~'}) current_dir = call_viml_function('fnamemodify', { current_dir, ':~' })
script_location = table.concat{current_dir, helpers.get_pathsep(), script_file} script_location = table.concat { current_dir, helpers.get_pathsep(), script_file }
write_file(script_file, [[ write_file(
script_file,
[[
vim.api.nvim_set_option_value('hlsearch', false, {}) vim.api.nvim_set_option_value('hlsearch', false, {})
vim.bo.expandtab = true vim.bo.expandtab = true
vim.opt.number = true vim.opt.number = true
@@ -45,7 +47,8 @@ function! s:return80()\
endfunction\ endfunction\
let &tw = s:return80()\ let &tw = s:return80()\
", true) ", true)
]]) ]]
)
exec(cmd .. ' ' .. script_file) exec(cmd .. ' ' .. script_file)
end) end)
@@ -55,54 +58,84 @@ let &tw = s:return80()\
it('"Last set" for option set by Lua', function() it('"Last set" for option set by Lua', function()
local result = exec_capture(':verbose set hlsearch?') local result = exec_capture(':verbose set hlsearch?')
eq(string.format([[ eq(
string.format(
[[
nohlsearch nohlsearch
Last set from %s line 1]], Last set from %s line 1]],
script_location), result) script_location
),
result
)
end) end)
it('"Last set" for option set by vim.o', function() it('"Last set" for option set by vim.o', function()
local result = exec_capture(':verbose set expandtab?') local result = exec_capture(':verbose set expandtab?')
eq(string.format([[ eq(
string.format(
[[
expandtab expandtab
Last set from %s line 2]], Last set from %s line 2]],
script_location), result) script_location
),
result
)
end) end)
it('"Last set" for option set by vim.opt', function() it('"Last set" for option set by vim.opt', function()
local result = exec_capture(':verbose set number?') local result = exec_capture(':verbose set number?')
eq(string.format([[ eq(
string.format(
[[
number number
Last set from %s line 3]], Last set from %s line 3]],
script_location), result) script_location
),
result
)
end) end)
it('"Last set" for mapping set by Lua', function() it('"Last set" for mapping set by Lua', function()
local result = exec_capture(':verbose map <leader>key1') local result = exec_capture(':verbose map <leader>key1')
eq(string.format([[ eq(
string.format(
[[
n \key1 * :echo "test"<CR> n \key1 * :echo "test"<CR>
Last set from %s line 4]], Last set from %s line 4]],
script_location), result) script_location
),
result
)
end) end)
it('"Last set" for mapping set by vim.keymap', function() it('"Last set" for mapping set by vim.keymap', function()
local result = exec_capture(':verbose map <leader>key2') local result = exec_capture(':verbose map <leader>key2')
eq(string.format([[ eq(
string.format(
[[
n \key2 * :echo "test"<CR> n \key2 * :echo "test"<CR>
Last set from %s line 5]], Last set from %s line 5]],
script_location), result) script_location
),
result
)
end) end)
it('"Last set" for autocmd by vim.api.nvim_exec', function() it('"Last set" for autocmd by vim.api.nvim_exec', function()
local result = exec_capture(':verbose autocmd test_group Filetype c') local result = exec_capture(':verbose autocmd test_group Filetype c')
eq(string.format([[ eq(
string.format(
[[
--- Autocommands --- --- Autocommands ---
test_group FileType test_group FileType
c setl cindent c setl cindent
Last set from %s line 7]], Last set from %s line 7]],
script_location), result) script_location
),
result
)
end) end)
it('"Last set" for command defined by nvim_command', function() it('"Last set" for command defined by nvim_command', function()
@@ -110,38 +143,58 @@ test_group FileType
pending('nvim_command does not set the script context') pending('nvim_command does not set the script context')
end end
local result = exec_capture(':verbose command Bdelete') local result = exec_capture(':verbose command Bdelete')
eq(string.format([[ eq(
string.format(
[[
Name Args Address Complete Definition Name Args Address Complete Definition
Bdelete 0 :bd Bdelete 0 :bd
Last set from %s line 13]], Last set from %s line 13]],
script_location), result) script_location
),
result
)
end) end)
it('"Last set" for command defined by nvim_create_user_command', function() it('"Last set" for command defined by nvim_create_user_command', function()
local result = exec_capture(':verbose command TestCommand') local result = exec_capture(':verbose command TestCommand')
eq(string.format([[ eq(
string.format(
[[
Name Args Address Complete Definition Name Args Address Complete Definition
TestCommand 0 :echo 'Hello' TestCommand 0 :echo 'Hello'
Last set from %s line 14]], Last set from %s line 14]],
script_location), result) script_location
),
result
)
end) end)
it('"Last set" for function', function() it('"Last set" for function', function()
local result = exec_capture(':verbose function Close_Window') local result = exec_capture(':verbose function Close_Window')
eq(string.format([[ eq(
string.format(
[[
function Close_Window() abort function Close_Window() abort
Last set from %s line 16 Last set from %s line 16
1 wincmd - 1 wincmd -
endfunction]], endfunction]],
script_location), result) script_location
),
result
)
end) end)
it('"Last set" works with anonymous sid', function() it('"Last set" works with anonymous sid', function()
local result = exec_capture(':verbose set tw?') local result = exec_capture(':verbose set tw?')
eq(string.format([[ eq(
string.format(
[[
textwidth=80 textwidth=80
Last set from %s line 22]], Last set from %s line 22]],
script_location), result) script_location
),
result
)
end) end)
end end
@@ -159,10 +212,13 @@ describe('lua verbose:', function()
setup(function() setup(function()
clear() clear()
script_file = 'test_luafile.lua' script_file = 'test_luafile.lua'
write_file(script_file, [[ write_file(
script_file,
[[
vim.api.nvim_set_option_value('hlsearch', false, {}) vim.api.nvim_set_option_value('hlsearch', false, {})
]]) ]]
exec(':source '..script_file) )
exec(':source ' .. script_file)
end) end)
teardown(function() teardown(function()
@@ -171,9 +227,11 @@ describe('lua verbose:', function()
it('is disabled when verbose = 0', function() it('is disabled when verbose = 0', function()
local result = exec_capture(':verbose set hlsearch?') local result = exec_capture(':verbose set hlsearch?')
eq([[ eq(
[[
nohlsearch nohlsearch
Last set from Lua]], result) Last set from Lua]],
result
)
end) end)
end) end)

View File

@@ -1,4 +1,4 @@
local helpers = require("test.functional.helpers")(after_each) local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear local clear = helpers.clear
local eq = helpers.eq local eq = helpers.eq
local funcs = helpers.funcs local funcs = helpers.funcs

View File

@@ -1,8 +1,7 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local luv = require('luv') local luv = require('luv')
local eq, eval, clear, write_file, source, insert = local eq, eval, clear, write_file, source, insert =
helpers.eq, helpers.eval, helpers.clear, helpers.write_file, helpers.eq, helpers.eval, helpers.clear, helpers.write_file, helpers.source, helpers.insert
helpers.source, helpers.insert
local pcall_err = helpers.pcall_err local pcall_err = helpers.pcall_err
local command = helpers.command local command = helpers.command
local feed_command = helpers.feed_command local feed_command = helpers.feed_command
@@ -40,9 +39,9 @@ describe(':write', function()
command('set backupcopy=auto') command('set backupcopy=auto')
write_file('test_bkc_file.txt', 'content0') write_file('test_bkc_file.txt', 'content0')
if is_os('win') then if is_os('win') then
command("silent !mklink test_bkc_link.txt test_bkc_file.txt") command('silent !mklink test_bkc_link.txt test_bkc_file.txt')
else else
command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") command('silent !ln -s test_bkc_file.txt test_bkc_link.txt')
end end
if eval('v:shell_error') ~= 0 then if eval('v:shell_error') ~= 0 then
pending('Cannot create symlink') pending('Cannot create symlink')
@@ -61,9 +60,9 @@ describe(':write', function()
command('set backupcopy=no') command('set backupcopy=no')
write_file('test_bkc_file.txt', 'content0') write_file('test_bkc_file.txt', 'content0')
if is_os('win') then if is_os('win') then
command("silent !mklink test_bkc_link.txt test_bkc_file.txt") command('silent !mklink test_bkc_link.txt test_bkc_file.txt')
else else
command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") command('silent !ln -s test_bkc_file.txt test_bkc_link.txt')
end end
if eval('v:shell_error') ~= 0 then if eval('v:shell_error') ~= 0 then
pending('Cannot create symlink') pending('Cannot create symlink')
@@ -77,46 +76,50 @@ describe(':write', function()
eq(eval("['content1']"), eval("readfile('test_bkc_link.txt')")) eq(eval("['content1']"), eval("readfile('test_bkc_link.txt')"))
end) end)
it("appends FIFO file", function() it('appends FIFO file', function()
-- mkfifo creates read-only .lnk files on Windows -- mkfifo creates read-only .lnk files on Windows
if is_os('win') or eval("executable('mkfifo')") == 0 then if is_os('win') or eval("executable('mkfifo')") == 0 then
pending('missing "mkfifo" command') pending('missing "mkfifo" command')
end end
local text = "some fifo text from write_spec" local text = 'some fifo text from write_spec'
assert(os.execute("mkfifo test_fifo")) assert(os.execute('mkfifo test_fifo'))
insert(text) insert(text)
-- Blocks until a consumer reads the FIFO. -- Blocks until a consumer reads the FIFO.
feed_command("write >> test_fifo") feed_command('write >> test_fifo')
-- Read the FIFO, this will unblock the :write above. -- Read the FIFO, this will unblock the :write above.
local fifo = assert(io.open("test_fifo")) local fifo = assert(io.open('test_fifo'))
eq(text.."\n", fifo:read("*all")) eq(text .. '\n', fifo:read('*all'))
fifo:close() fifo:close()
end) end)
it("++p creates missing parent directories", function() it('++p creates missing parent directories', function()
eq(0, eval("filereadable('p_opt.txt')")) eq(0, eval("filereadable('p_opt.txt')"))
command("write ++p p_opt.txt") command('write ++p p_opt.txt')
eq(1, eval("filereadable('p_opt.txt')")) eq(1, eval("filereadable('p_opt.txt')"))
os.remove("p_opt.txt") os.remove('p_opt.txt')
eq(0, eval("filereadable('p_opt.txt')")) eq(0, eval("filereadable('p_opt.txt')"))
command("write ++p ./p_opt.txt") command('write ++p ./p_opt.txt')
eq(1, eval("filereadable('p_opt.txt')")) eq(1, eval("filereadable('p_opt.txt')"))
os.remove("p_opt.txt") os.remove('p_opt.txt')
eq(0, eval("filereadable('test/write/p_opt.txt')")) eq(0, eval("filereadable('test/write/p_opt.txt')"))
command("write ++p test/write/p_opt.txt") command('write ++p test/write/p_opt.txt')
eq(1, eval("filereadable('test/write/p_opt.txt')")) eq(1, eval("filereadable('test/write/p_opt.txt')"))
eq(('Vim(write):E32: No file name'), pcall_err(command, 'write ++p test_write/')) eq('Vim(write):E32: No file name', pcall_err(command, 'write ++p test_write/'))
if not is_os('win') then if not is_os('win') then
eq(('Vim(write):E17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'), eq(
pcall_err(command, 'write ++p .')) ('Vim(write):E17: "' .. funcs.fnamemodify('.', ':p:h') .. '" is a directory'),
eq(('Vim(write):E17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'), pcall_err(command, 'write ++p .')
pcall_err(command, 'write ++p ./')) )
eq(
('Vim(write):E17: "' .. funcs.fnamemodify('.', ':p:h') .. '" is a directory'),
pcall_err(command, 'write ++p ./')
)
end end
end) end)
@@ -126,24 +129,27 @@ describe(':write', function()
eq(funcs.fnamemodify('.', ':p:h'), funcs.fnamemodify('.', ':p:h:~')) eq(funcs.fnamemodify('.', ':p:h'), funcs.fnamemodify('.', ':p:h:~'))
-- Message from check_overwrite -- Message from check_overwrite
if not is_os('win') then if not is_os('win') then
eq(('Vim(write):E17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'), eq(
pcall_err(command, 'write .')) ('Vim(write):E17: "' .. funcs.fnamemodify('.', ':p:h') .. '" is a directory'),
pcall_err(command, 'write .')
)
end end
meths.set_option_value('writeany', true, {}) meths.set_option_value('writeany', true, {})
-- Message from buf_write -- Message from buf_write
eq(('Vim(write):E502: "." is a directory'), pcall_err(command, 'write .')) eq('Vim(write):E502: "." is a directory', pcall_err(command, 'write .'))
funcs.mkdir(fname_bak) funcs.mkdir(fname_bak)
meths.set_option_value('backupdir', '.', {}) meths.set_option_value('backupdir', '.', {})
meths.set_option_value('backup', true, {}) meths.set_option_value('backup', true, {})
write_file(fname, 'content0') write_file(fname, 'content0')
command('edit ' .. fname) command('edit ' .. fname)
funcs.setline(1, 'TTY') funcs.setline(1, 'TTY')
eq('Vim(write):E510: Can\'t make backup file (add ! to override)', eq("Vim(write):E510: Can't make backup file (add ! to override)", pcall_err(command, 'write'))
pcall_err(command, 'write'))
meths.set_option_value('backup', false, {}) meths.set_option_value('backup', false, {})
funcs.setfperm(fname, 'r--------') funcs.setfperm(fname, 'r--------')
eq('Vim(write):E505: "Xtest-functional-ex_cmds-write" is read-only (add ! to override)', eq(
pcall_err(command, 'write')) 'Vim(write):E505: "Xtest-functional-ex_cmds-write" is read-only (add ! to override)',
pcall_err(command, 'write')
)
if is_os('win') then if is_os('win') then
eq(0, os.execute('del /q/f ' .. fname)) eq(0, os.execute('del /q/f ' .. fname))
eq(0, os.execute('rd /q/s ' .. fname_bak)) eq(0, os.execute('rd /q/s ' .. fname_bak))
@@ -154,7 +160,6 @@ describe(':write', function()
write_file(fname_bak, 'TTYX') write_file(fname_bak, 'TTYX')
skip(is_os('win'), [[FIXME: exc_exec('write!') outputs 0 in Windows]]) skip(is_os('win'), [[FIXME: exc_exec('write!') outputs 0 in Windows]])
luv.fs_symlink(fname_bak .. ('/xxxxx'):rep(20), fname) luv.fs_symlink(fname_bak .. ('/xxxxx'):rep(20), fname)
eq('Vim(write):E166: Can\'t open linked file for writing', eq("Vim(write):E166: Can't open linked file for writing", pcall_err(command, 'write!'))
pcall_err(command, 'write!'))
end) end)
end) end)

Some files were not shown because too many files have changed in this diff Show More