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/vim/_meta
/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/legacy/030_fileformats_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(STYLUA_PRG stylua ${LINT_REQUIRED})
set(STYLUA_DIRS runtime scripts src test/unit)
set(STYLUA_DIRS runtime scripts src test)
add_glob_target(
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
GLOB_DIRS runtime scripts src test
GLOB_PAT *.lua
TOUCH_STRATEGY SINGLE)
TOUCH_STRATEGY PER_DIR)
add_dependencies(lintlua-luacheck lua-dev-deps)
add_glob_target(
@ -244,7 +244,7 @@ add_glob_target(
FLAGS --color=always --check --respect-ignores
GLOB_DIRS ${STYLUA_DIRS}
GLOB_PAT *.lua
TOUCH_STRATEGY SINGLE)
TOUCH_STRATEGY PER_DIR)
add_custom_target(lintlua)
add_dependencies(lintlua lintlua-luacheck lintlua-stylua)
@ -255,7 +255,7 @@ add_glob_target(
FLAGS -x -a
GLOB_DIRS scripts
GLOB_PAT *.sh
TOUCH_STRATEGY SINGLE)
TOUCH_STRATEGY PER_DIR)
add_custom_target(lintcommit
COMMAND $<TARGET_FILE:nvim> -u NONE -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main)
@ -270,7 +270,8 @@ add_glob_target(
COMMAND ${STYLUA_PRG}
FLAGS --respect-ignores
GLOB_DIRS ${STYLUA_DIRS}
GLOB_PAT *.lua)
GLOB_PAT *.lua
TOUCH_STRATEGY PER_DIR)
add_custom_target(format)
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 assert_alive = helpers.assert_alive
describe('API: highlight',function()
describe('API: highlight', function()
clear()
Screen.new() -- initialize Screen.colors
@ -45,31 +45,35 @@ describe('API: highlight',function()
before_each(function()
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)
it("nvim_get_hl_by_id", function()
it('nvim_get_hl_by_id', function()
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')")
-- 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.
eq('Invalid highlight id: 30000', pcall_err(meths.get_hl_by_id, 30000, false))
-- Test all highlight properties.
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
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.
eq('Wrong type for argument 1 when calling nvim_get_hl_by_id, expecting Integer',
pcall_err(meths.get_hl_by_id, { nil }, false))
eq(
'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.
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 NewConstant ctermfg=green guifg=white guibg=blue')
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.
command('hi clear NewConstant')
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.
command('hi clear NewConstant')
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)
it("nvim_get_hl_by_name", function()
local expected_normal = { background = Screen.colors.Yellow,
foreground = Screen.colors.Red }
it('nvim_get_hl_by_name', function()
local expected_normal = { background = Screen.colors.Yellow, foreground = Screen.colors.Red }
-- 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_rgb, nvim("get_hl_by_name", 'NewHighlight', true))
eq(expected_cterm, nvim('get_hl_by_name', 'NewHighlight', false))
eq(expected_rgb, nvim('get_hl_by_name', 'NewHighlight', true))
-- Test `Normal` modified values.
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.
eq("Invalid highlight name: 'unknown_highlight'",
pcall_err(meths.get_hl_by_name , 'unknown_highlight', false))
eq(
"Invalid highlight name: 'unknown_highlight'",
pcall_err(meths.get_hl_by_name, 'unknown_highlight', false)
)
-- Test nil argument.
eq('Wrong type for argument 1 when calling nvim_get_hl_by_name, expecting String',
pcall_err(meths.get_hl_by_name , { nil }, false))
eq(
'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.
eq('Invalid highlight name',
pcall_err(meths.get_hl_by_name , '', false))
eq('Invalid highlight name', pcall_err(meths.get_hl_by_name, '', false))
-- Test "standout" attribute. #8054
eq({ underline = true, },
meths.get_hl_by_name('cursorline', 0));
eq({ underline = true }, meths.get_hl_by_name('cursorline', 0))
command('hi CursorLine cterm=standout,underline term=standout,underline gui=standout,underline')
command('set cursorline')
eq({ underline = true, standout = true, },
meths.get_hl_by_name('cursorline', 0));
eq({ underline = true, standout = true }, meths.get_hl_by_name('cursorline', 0))
-- Test cterm & Normal values. #18024 (tail) & #18980
-- 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, 'NotNormal', {ctermfg = 17, ctermbg = 213, nocombine = true})
meths.set_hl(0, 'Normal', { ctermfg = 17, ctermbg = 213 })
meths.set_hl(0, 'NotNormal', { ctermfg = 17, ctermbg = 213, nocombine = true })
-- 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, nocombine = true}, nvim("get_hl_by_name", 'NotNormal', 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)
)
end)
it('nvim_get_hl_id_by_name', function()
-- 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(0, funcs.hlID("Shrubbery"))
eq("Invalid highlight name: 'Shrubbery'", pcall_err(meths.get_hl_by_name, 'Shrubbery', true))
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)
eq(hl_id, funcs.hlID("Shrubbery"))
eq(hl_id, funcs.hlID('Shrubbery'))
command('hi Shrubbery guifg=#888888 guibg=#888888')
eq({foreground=tonumber("0x888888"), background=tonumber("0x888888")},
meths.get_hl_by_id(hl_id, true))
eq({foreground=tonumber("0x888888"), background=tonumber("0x888888")},
meths.get_hl_by_name("Shrubbery", true))
eq(
{ foreground = tonumber('0x888888'), background = tonumber('0x888888') },
meths.get_hl_by_id(hl_id, true)
)
eq(
{ foreground = tonumber('0x888888'), background = tonumber('0x888888') },
meths.get_hl_by_name('Shrubbery', true)
)
end)
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)
describe("API: set highlight", function()
describe('API: set highlight', function()
local highlight_color = {
fg = tonumber('0xff0000'),
bg = tonumber('0x0032aa'),
@ -207,7 +218,7 @@ describe("API: set highlight", function()
strikethrough = true,
altfont = true,
nocombine = true,
}
},
}
local highlight3_result_gui = {
background = highlight_color.bg,
@ -238,31 +249,35 @@ describe("API: set highlight", function()
before_each(clear)
it('validation', function()
eq("Invalid 'blend': out of range",
pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend=999}))
eq("Invalid 'blend': expected Integer, got Array",
pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend={}}))
eq(
"Invalid 'blend': out of range",
pcall_err(meths.set_hl, 0, 'Test_hl3', { fg = '#FF00FF', blend = 999 })
)
eq(
"Invalid 'blend': expected Integer, got Array",
pcall_err(meths.set_hl, 0, 'Test_hl3', { fg = '#FF00FF', blend = {} })
)
end)
it("can set gui highlight", function()
it('can set gui highlight', function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight1)
eq(highlight1, meths.get_hl_by_name('Test_hl', true))
end)
it("can set cterm highlight", function()
it('can set cterm highlight', function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight2_config)
eq(highlight2_result, meths.get_hl_by_name('Test_hl', false))
end)
it("can set empty cterm attr", function()
it('can set empty cterm attr', function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', { cterm = {} })
eq({}, meths.get_hl_by_name('Test_hl', false))
end)
it("cterm attr defaults to gui attr", function()
it('cterm attr defaults to gui attr', function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight1)
eq({
@ -271,14 +286,14 @@ describe("API: set highlight", function()
}, meths.get_hl_by_name('Test_hl', false))
end)
it("can overwrite attr for cterm", function()
it('can overwrite attr for cterm', function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight3_config)
eq(highlight3_result_gui, meths.get_hl_by_name('Test_hl', true))
eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false))
end)
it("only allows one underline attribute #22371", function()
it('only allows one underline attribute #22371', function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', {
underdouble = true,
@ -292,80 +307,76 @@ describe("API: set highlight", function()
eq({ underdotted = true }, meths.get_hl_by_name('Test_hl', true))
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)
eq('Test_hl xxx cterm=underline,reverse ctermfg=8 ctermbg=15 gui=underline,reverse',
exec_capture('highlight Test_hl'))
eq(
'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 })
eq('Test_hl xxx guibg=#0032aa',
exec_capture('highlight Test_hl'))
eq('Test_hl xxx guibg=#0032aa', exec_capture('highlight Test_hl'))
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',
exec_capture('highlight Test_hl2'))
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',
exec_capture('highlight Test_hl2')
)
-- Colors are stored with the name they are defined, but
-- with canonical casing
meths.set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue'})
eq('Test_hl3 xxx guifg=Blue guibg=Red',
exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue' })
eq('Test_hl3 xxx guifg=Blue guibg=Red', exec_capture('highlight Test_hl3'))
end)
it("can modify a highlight in the global namespace", function()
meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue'})
eq('Test_hl3 xxx guifg=Blue guibg=Red',
exec_capture('highlight Test_hl3'))
it('can modify a highlight in the global namespace', function()
meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue' })
eq('Test_hl3 xxx guifg=Blue guibg=Red', exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { bg = 'red' })
eq('Test_hl3 xxx guibg=Red',
exec_capture('highlight Test_hl3'))
eq('Test_hl3 xxx guibg=Red', exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { ctermbg = 9, ctermfg = 12})
eq('Test_hl3 xxx ctermfg=12 ctermbg=9',
exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { ctermbg = 9, ctermfg = 12 })
eq('Test_hl3 xxx ctermfg=12 ctermbg=9', exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { ctermbg = 'red' , ctermfg = 'blue'})
eq('Test_hl3 xxx ctermfg=12 ctermbg=9',
exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { ctermbg = 'red', ctermfg = 'blue' })
eq('Test_hl3 xxx ctermfg=12 ctermbg=9', exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { ctermbg = 9 })
eq('Test_hl3 xxx ctermbg=9',
exec_capture('highlight Test_hl3'))
eq('Test_hl3 xxx ctermbg=9', exec_capture('highlight Test_hl3'))
eq("Invalid highlight color: 'redd'",
pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='redd'}))
eq("Invalid highlight color: 'redd'", pcall_err(meths.set_hl, 0, 'Test_hl3', { fg = 'redd' }))
eq("Invalid highlight color: 'bleu'",
pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='bleu'}))
eq(
"Invalid highlight color: 'bleu'",
pcall_err(meths.set_hl, 0, 'Test_hl3', { ctermfg = 'bleu' })
)
meths.set_hl(0, 'Test_hl3', {fg='#FF00FF'})
eq('Test_hl3 xxx guifg=#ff00ff',
exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { fg = '#FF00FF' })
eq('Test_hl3 xxx guifg=#ff00ff', exec_capture('highlight Test_hl3'))
eq("Invalid highlight color: '#FF00FF'",
pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='#FF00FF'}))
eq(
"Invalid highlight color: '#FF00FF'",
pcall_err(meths.set_hl, 0, 'Test_hl3', { ctermfg = '#FF00FF' })
)
for _, fg_val in ipairs{ nil, 'NONE', 'nOnE', '', -1 } do
meths.set_hl(0, 'Test_hl3', {fg = fg_val})
eq('Test_hl3 xxx cleared',
exec_capture('highlight Test_hl3'))
for _, fg_val in ipairs { nil, 'NONE', 'nOnE', '', -1 } do
meths.set_hl(0, 'Test_hl3', { fg = fg_val })
eq('Test_hl3 xxx cleared', exec_capture('highlight Test_hl3'))
end
meths.set_hl(0, 'Test_hl3', {fg='#FF00FF', blend=50})
eq('Test_hl3 xxx guifg=#ff00ff blend=50',
exec_capture('highlight Test_hl3'))
meths.set_hl(0, 'Test_hl3', { fg = '#FF00FF', blend = 50 })
eq('Test_hl3 xxx guifg=#ff00ff blend=50', exec_capture('highlight Test_hl3'))
end)
it("correctly sets 'Normal' internal properties", function()
-- Normal has some special handling internally. #18024
meths.set_hl(0, 'Normal', {fg='#000083', bg='#0000F3'})
eq({foreground = 131, background = 243}, nvim("get_hl_by_name", 'Normal', true))
meths.set_hl(0, 'Normal', { fg = '#000083', bg = '#0000F3' })
eq({ foreground = 131, background = 243 }, nvim('get_hl_by_name', 'Normal', true))
end)
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()
end)
end)
@ -380,14 +391,16 @@ describe('API: get highlight', function()
local highlight1 = {
bg = highlight_color.bg,
fg = highlight_color.fg,
bold = true, italic = true,
cterm = {bold = true, italic = true},
bold = true,
italic = true,
cterm = { bold = true, italic = true },
}
local highlight2 = {
ctermbg = highlight_color.ctermbg,
ctermfg = highlight_color.ctermfg,
underline = true, reverse = true,
cterm = {underline = true, reverse = true},
underline = true,
reverse = true,
cterm = { underline = true, reverse = true },
}
local highlight3_config = {
bg = highlight_color.bg,
@ -413,8 +426,19 @@ describe('API: get highlight', function()
fg = highlight_color.fg,
ctermbg = highlight_color.ctermbg,
ctermfg = highlight_color.ctermfg,
bold = true, italic = true, reverse = true, underdashed = true, strikethrough = true, altfont = true,
cterm = {italic = true, nocombine = true, reverse = true, strikethrough = true, altfont = true}
bold = 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()
@ -434,17 +458,16 @@ describe('API: get highlight', function()
before_each(clear)
it('validation', function()
eq("Invalid 'name': expected String, got Integer",
pcall_err(meths.get_hl, 0, { name = 177 }))
eq("Invalid 'name': expected String, got Integer", pcall_err(meths.get_hl, 0, { name = 177 }))
eq('Highlight id out of bounds', pcall_err(meths.get_hl, 0, { name = 'Test set hl' }))
end)
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'))
meths.get_hl(0, {name = 'Bar', create = true})
meths.get_hl(0, { name = 'Bar', create = true })
eq(1, funcs.hlexists('Bar'))
meths.get_hl(0, {name = 'FooBar'})
meths.get_hl(0, { name = 'FooBar' })
eq(1, funcs.hlexists('FooBar'))
end)
@ -454,11 +477,11 @@ describe('API: get highlight', function()
meths.set_hl(ns, 'Test_hl_link', { link = 'Test_hl' })
eq({
Test_hl = {
bg = 11845374
bg = 11845374,
},
Test_hl_link = {
link = 'Test_hl'
}
link = 'Test_hl',
},
}, meths.get_hl(ns, {}))
end)
@ -502,8 +525,7 @@ describe('API: get highlight', function()
undercurl = true,
},
})
eq({ underdotted = true, cterm = { undercurl = true} },
meths.get_hl(ns, { name = 'Test_hl' }))
eq({ underdotted = true, cterm = { undercurl = true } }, meths.get_hl(ns, { name = 'Test_hl' }))
end)
it('can get a highlight in the global namespace', function()
@ -533,8 +555,13 @@ describe('API: get highlight', function()
command(
'hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold'
)
eq({ fg = 16711680, bg = 16776960, sp = 255, bold = true,
ctermbg = 10, cterm = { underline = true },
eq({
fg = 16711680,
bg = 16776960,
sp = 255,
bold = true,
ctermbg = 10,
cterm = { underline = true },
}, meths.get_hl(0, { id = hl_id }))
-- Test 0 argument
@ -547,16 +574,30 @@ describe('API: get highlight', function()
-- Test all highlight properties.
command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine')
eq({ fg = 16711680, bg = 16776960, sp = 255,
altfont = true, bold = true, italic = true, nocombine = true, reverse = true, strikethrough = true, underline = true,
ctermbg = 10, cterm = {underline = true},
eq({
fg = 16711680,
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 }))
-- Test undercurl
command('hi NewHighlight gui=undercurl')
eq({ fg = 16711680, bg = 16776960, sp = 255, undercurl = true,
ctermbg = 10,
cterm = {underline = true},
eq({
fg = 16711680,
bg = 16776960,
sp = 255,
undercurl = true,
ctermbg = 10,
cterm = { underline = true },
}, meths.get_hl(0, { id = hl_id }))
end)
@ -573,7 +614,10 @@ describe('API: get highlight', function()
command('hi Bar guifg=red')
command('hi Foo guifg=#00ff00 gui=bold,underline')
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)
it('can set link as well as other attributes', function()
@ -584,57 +628,57 @@ describe('API: get highlight', function()
end)
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)
local data = meths.get_hl(0, {})
eq(nil, data["@foobar.hubbabubba"])
eq(nil, data["@foobar"])
eq(nil, data['@foobar.hubbabubba'])
eq(nil, data['@foobar'])
command 'hi @foobar.hubbabubba gui=bold'
data = meths.get_hl(0, {})
eq({bold = true}, data["@foobar.hubbabubba"])
eq(nil, data["@foobar"])
eq({ bold = true }, data['@foobar.hubbabubba'])
eq(nil, data['@foobar'])
-- @foobar.hubbabubba was explicitly cleared and thus shows up
-- but @foobar was never touched, and thus doesn't
command 'hi clear @foobar.hubbabubba'
data = meths.get_hl(0, {})
eq({}, data["@foobar.hubbabubba"])
eq(nil, data["@foobar"])
eq({}, data['@foobar.hubbabubba'])
eq(nil, data['@foobar'])
end)
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' }))
end)
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, '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, 'FooBar', { default = true, fg = '#ffffff', cterm = { bold = true } })
meths.set_hl(
0,
'FooBarA',
{ default = true, fg = '#ffffff', cterm = { bold = true, italic = true } }
)
eq('Foo xxx cleared',
exec_capture('highlight Foo'))
eq({default = true}, meths.get_hl(0, {name = 'Foo'}))
eq('Bar xxx guifg=#ffffff',
exec_capture('highlight Bar'))
eq('FooBar xxx cterm=bold guifg=#ffffff',
exec_capture('highlight FooBar'))
eq('FooBarA xxx cterm=bold,italic guifg=#ffffff',
exec_capture('highlight FooBarA'))
eq('Foo xxx cleared', exec_capture('highlight Foo'))
eq({ default = true }, meths.get_hl(0, { name = 'Foo' }))
eq('Bar xxx guifg=#ffffff', exec_capture('highlight Bar'))
eq('FooBar xxx cterm=bold guifg=#ffffff', exec_capture('highlight FooBar'))
eq('FooBarA xxx cterm=bold,italic guifg=#ffffff', exec_capture('highlight FooBarA'))
end)
it('can override exist highlight group by force #20323', function()
local white = tonumber('ffffff', 16)
local green = tonumber('00ff00', 16)
meths.set_hl(0, 'Foo', { fg=white })
meths.set_hl(0, 'Foo', { fg=green, force = true })
eq({ fg = green },meths.get_hl(0, {name = 'Foo'}))
meths.set_hl(0, 'Bar', {link = 'Comment', default = true})
meths.set_hl(0, 'Bar', {link = 'Foo',default = true, force = true})
eq({link ='Foo', default = true}, meths.get_hl(0, {name = 'Bar'}))
meths.set_hl(0, 'Foo', { fg = white })
meths.set_hl(0, 'Foo', { fg = green, force = true })
eq({ fg = green }, meths.get_hl(0, { name = 'Foo' }))
meths.set_hl(0, 'Bar', { link = 'Comment', default = true })
meths.set_hl(0, 'Bar', { link = 'Foo', default = true, force = true })
eq({ link = 'Foo', default = true }, meths.get_hl(0, { name = 'Bar' }))
end)
end)
@ -647,9 +691,9 @@ describe('API: set/get highlight namespace', function()
end)
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('')
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)

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

View File

@ -43,16 +43,16 @@ describe('API', function()
end)
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("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("Invalid 'pid': 0", string.match(rv, "Invalid.*"))
eq("Invalid 'pid': 0", string.match(rv, 'Invalid.*'))
-- 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({}, rv)
end)
@ -69,16 +69,16 @@ describe('API', function()
end)
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("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("Invalid 'pid': 0", string.match(rv, "Invalid.*"))
eq("Invalid 'pid': 0", string.match(rv, 'Invalid.*'))
-- 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(NIL, rv)
end)

View File

@ -4,8 +4,8 @@
package.path = arg[1]
package.cpath = arg[2]
local StdioStream = require'test.client.uv_stream'.StdioStream
local Session = require'test.client.session'
local StdioStream = require 'test.client.uv_stream'.StdioStream
local Session = require 'test.client.session'
local stdio_stream = StdioStream.open()
local session = Session.new(stdio_stream)
@ -15,8 +15,8 @@ local function on_request(method, args)
return 'ok'
elseif method == 'write_stderr' then
io.stderr:write(args[1])
return "done!"
elseif method == "exit" then
return 'done!'
elseif method == 'exit' then
session:stop()
return vim.NIL
end
@ -24,7 +24,7 @@ end
local function on_notification(event, args)
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

View File

@ -1,8 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local assert_log = helpers.assert_log
local eq, clear, eval, command, nvim, next_msg =
helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.nvim,
helpers.next_msg
helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.nvim, helpers.next_msg
local meths = helpers.meths
local exec_lua = helpers.exec_lua
local retry = helpers.retry
@ -24,11 +23,11 @@ describe('notify', function()
describe('passing a valid channel id', function()
it('sends the notification/args to the corresponding channel', function()
eval('rpcnotify('..channel..', "test-event", 1, 2, 3)')
eq({'notification', 'test-event', {1, 2, 3}}, next_msg())
command('au FileType lua call rpcnotify('..channel..', "lua!")')
eval('rpcnotify(' .. channel .. ', "test-event", 1, 2, 3)')
eq({ 'notification', 'test-event', { 1, 2, 3 } }, next_msg())
command('au FileType lua call rpcnotify(' .. channel .. ', "lua!")')
command('set filetype=lua')
eq({'notification', 'lua!', {}}, next_msg())
eq({ 'notification', 'lua!', {} }, next_msg())
end)
end)
@ -38,20 +37,20 @@ describe('notify', function()
eval('rpcnotify(0, "event1", 1, 2, 3)')
eval('rpcnotify(0, "event2", 4, 5, 6)')
eval('rpcnotify(0, "event2", 7, 8, 9)')
eq({'notification', 'event2', {4, 5, 6}}, next_msg())
eq({'notification', 'event2', {7, 8, 9}}, next_msg())
eq({ 'notification', 'event2', { 4, 5, 6 } }, next_msg())
eq({ 'notification', 'event2', { 7, 8, 9 } }, next_msg())
nvim('unsubscribe', 'event2')
nvim('subscribe', 'event1')
eval('rpcnotify(0, "event2", 10, 11, 12)')
eval('rpcnotify(0, "event1", 13, 14, 15)')
eq({'notification', 'event1', {13, 14, 15}}, next_msg())
eq({ 'notification', 'event1', { 13, 14, 15 } }, next_msg())
end)
it('does not crash for deeply nested variable', function()
meths.set_var('l', {})
local nest_level = 1000
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()
eq('notification', msg[1])
eq('event', msg[2])
@ -77,9 +76,9 @@ describe('notify', function()
end)
it('unsubscribe non-existing event #8745', function()
clear{env={
NVIM_LOG_FILE=testlog,
}}
clear { env = {
NVIM_LOG_FILE = testlog,
} }
nvim('subscribe', 'event1')
nvim('unsubscribe', 'doesnotexist')
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()
local catchan = eval("jobstart(['cat'], {'rpc': v:true})")
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_subscribe", "daily_rant")
return vim.api.nvim_get_chan_info(...)
]], catchan))
]],
catchan
)
)
assert_alive()
eq({false, 'Invalid channel: '..catchan},
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 :(
eq(
{ false, 'Invalid channel: ' .. catchan },
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)

View File

@ -40,13 +40,13 @@ describe('server -> client', function()
describe('simple call', function()
it('works', function()
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()
end
local function on_request(method, args)
eq('scall', method)
eq({1, 2, 3}, args)
eq({ 1, 2, 3 }, args)
nvim('command', 'let g:result = [4, 5, 6]')
return eval('g:result')
end
@ -61,14 +61,14 @@ describe('server -> client', function()
-- elements following the empty string.
it('works', function()
local function on_setup()
eq({1, 2, '', 3, 'asdf'}, eval('rpcrequest('..cid..', "nstring")'))
eq({ 1, 2, '', 3, 'asdf' }, eval('rpcrequest(' .. cid .. ', "nstring")'))
stop()
end
local function on_request()
-- No need to evaluate the args, we are only interested in
-- a response that contains an array with an empty string.
return {1, 2, '', 3, 'asdf'}
return { 1, 2, '', 3, 'asdf' }
end
run(on_request, nil, on_setup)
end)
@ -81,7 +81,7 @@ describe('server -> client', function()
nvim('set_var', 'result2', 0)
nvim('set_var', 'result3', 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(8, nvim('get_var', 'result2'))
eq(16, nvim('get_var', 'result3'))
@ -95,11 +95,11 @@ describe('server -> client', function()
if n <= 16 then
local cmd
if n == 4 then
cmd = 'let g:result2 = rpcrequest('..cid..', "rcall", '..n..')'
cmd = 'let g:result2 = rpcrequest(' .. cid .. ', "rcall", ' .. n .. ')'
elseif n == 8 then
cmd = 'let g:result3 = rpcrequest('..cid..', "rcall", '..n..')'
cmd = 'let g:result3 = rpcrequest(' .. cid .. ', "rcall", ' .. n .. ')'
elseif n == 16 then
cmd = 'let g:result4 = rpcrequest('..cid..', "rcall", '..n..')'
cmd = 'let g:result4 = rpcrequest(' .. cid .. ', "rcall", ' .. n .. ')'
end
nvim('command', cmd)
end
@ -113,18 +113,18 @@ describe('server -> client', function()
it('does not delay notifications during pending request', function()
local received = false
local function on_setup()
eq("retval", funcs.rpcrequest(cid, "doit"))
eq('retval', funcs.rpcrequest(cid, 'doit'))
stop()
end
local function on_request(method)
if method == "doit" then
funcs.rpcnotify(cid, "headsup")
eq(true,received)
return "retval"
if method == 'doit' then
funcs.rpcnotify(cid, 'headsup')
eq(true, received)
return 'retval'
end
end
local function on_notification(method)
if method == "headsup" then
if method == 'headsup' then
received = true
end
end
@ -148,28 +148,28 @@ describe('server -> client', function()
-- of nvim's request stack).
pending('will close connection if not properly synchronized', function()
local function on_setup()
eq('notified!', eval('rpcrequest('..cid..', "notify")'))
eq('notified!', eval('rpcrequest(' .. cid .. ', "notify")'))
end
local function on_request(method)
if method == "notify" then
eq(1, eval('rpcnotify('..cid..', "notification")'))
if method == 'notify' then
eq(1, eval('rpcnotify(' .. cid .. ', "notification")'))
return 'notified!'
elseif method == "nested" then
elseif method == 'nested' then
-- do some busywork, so the first request will return
-- before this one
for _ = 1, 5 do
assert_alive()
end
eq(1, eval('rpcnotify('..cid..', "nested_done")'))
eq(1, eval('rpcnotify(' .. cid .. ', "nested_done")'))
return 'done!'
end
end
local function on_notification(method)
if method == "notification" then
eq('done!', eval('rpcrequest('..cid..', "nested")'))
elseif method == "nested_done" then
if method == 'notification' then
eq('done!', eval('rpcrequest(' .. cid .. ', "nested")'))
elseif method == 'nested_done' then
ok(false, 'never sent', 'sent')
end
end
@ -182,11 +182,17 @@ describe('server -> client', function()
describe('recursive (child) nvim client', 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'))
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()
nvim('command', "call rpcnotify(vim, 'vim_set_current_line', 'SOME TEXT')")
@ -198,25 +204,27 @@ describe('server -> client', function()
end)
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)
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]
eq(1, buf)
eval("rpcnotify(vim, 'buffer_set_line', "..buf..", 0, 'SOME TEXT')")
nvim('command', "call rpcrequest(vim, 'vim_eval', '0')") -- wait
eval("rpcnotify(vim, 'buffer_set_line', " .. buf .. ", 0, 'SOME TEXT')")
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)
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)
it('returns an error if the request failed', function()
eq("Vim:Error invoking 'does-not-exist' on channel 3:\nInvalid method: does-not-exist",
pcall_err(eval, "rpcrequest(vim, 'does-not-exist')"))
eq(
"Vim:Error invoking 'does-not-exist' on channel 3:\nInvalid method: does-not-exist",
pcall_err(eval, "rpcrequest(vim, 'does-not-exist')")
)
end)
end)
@ -236,13 +244,14 @@ describe('server -> client', function()
\ 'rpc': v:true
\ }
]])
meths.set_var("args", {
nvim_prog, '-ll',
meths.set_var('args', {
nvim_prog,
'-ll',
'test/functional/api/rpc_fixture.lua',
package.path,
package.cpath,
})
jobid = eval("jobstart(g:args, g:job_opts)")
jobid = eval('jobstart(g:args, g:job_opts)')
neq(0, jobid)
end)
@ -250,7 +259,9 @@ describe('server -> client', function()
pcall(funcs.jobstop, jobid)
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()
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))
end
eq('ok', rv)
funcs.rpcnotify(jobid, "ping")
eq({'notification', 'pong', {}}, next_msg())
eq("done!",funcs.rpcrequest(jobid, "write_stderr", "fluff\n"))
eq({'notification', 'stderr', {0, {'fluff', ''}}}, next_msg())
pcall(funcs.rpcrequest, jobid, "exit")
eq({'notification', 'stderr', {0, {''}}}, next_msg())
eq({'notification', 'exit', {0, 0}}, next_msg())
funcs.rpcnotify(jobid, 'ping')
eq({ 'notification', 'pong', {} }, next_msg())
eq('done!', funcs.rpcrequest(jobid, 'write_stderr', 'fluff\n'))
eq({ 'notification', 'stderr', { 0, { 'fluff', '' } } }, next_msg())
pcall(funcs.rpcrequest, jobid, 'exit')
eq({ 'notification', 'stderr', { 0, { '' } } }, next_msg())
eq({ 'notification', 'exit', { 0, 0 } }, next_msg())
end)
end)
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 serverpid = funcs.getpid()
local client = spawn(nvim_argv, false, nil, true)
@ -277,7 +288,7 @@ describe('server -> client', function()
local clientpid = funcs.getpid()
neq(serverpid, clientpid)
local id = funcs.sockconnect(mode, address, {rpc=true})
local id = funcs.sockconnect(mode, address, { rpc = true })
ok(id > 0)
funcs.rpcrequest(id, 'nvim_set_current_line', 'hello')
@ -303,7 +314,7 @@ describe('server -> client', function()
local server = spawn(nvim_argv)
set_session(server)
local address = funcs.serverlist()[1]
local first = string.sub(address,1,1)
local first = string.sub(address, 1, 1)
ok(first == '/' or first == '\\')
connect_test(server, 'pipe', address)
end)
@ -311,11 +322,11 @@ describe('server -> client', function()
it('via ipv4 address', function()
local server = spawn(nvim_argv)
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
pending('no ipv4 stack')
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)
end)
@ -326,15 +337,15 @@ describe('server -> client', function()
if not status then
pending('no ipv6 stack')
end
eq('::1:', string.sub(address,1,4))
eq('::1:', string.sub(address, 1, 4))
connect_test(server, 'tcp', address)
end)
it('via hostname', function()
local server = spawn(nvim_argv)
set_session(server)
local address = funcs.serverstart("localhost:")
eq('localhost:', string.sub(address,1,10))
local address = funcs.serverstart('localhost:')
eq('localhost:', string.sub(address, 1, 10))
connect_test(server, 'tcp', address)
end)
@ -345,7 +356,7 @@ describe('server -> client', function()
local client = spawn(nvim_argv, false, nil, true)
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, {})
assert_alive()
@ -357,15 +368,15 @@ describe('server -> client', function()
describe('connecting to its own pipe address', function()
it('does not deadlock', function()
local address = funcs.serverlist()[1]
local first = string.sub(address,1,1)
local first = string.sub(address, 1, 1)
ok(first == '/' or first == '\\')
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')
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])
end)

View File

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

View File

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

View File

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

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

View File

@ -26,23 +26,23 @@ describe('autocmd', function()
it(':tabnew, :split, :close events order, <afile>', function()
local expected = {
{'WinLeave', ''},
{'TabLeave', ''},
{'WinEnter', ''},
{'TabNew', 'testfile1'}, -- :tabnew
{'TabEnter', ''},
{'BufLeave', ''},
{'BufEnter', 'testfile1'}, -- :split
{'WinLeave', 'testfile1'},
{'WinEnter', 'testfile1'},
{'WinLeave', 'testfile1'},
{'WinClosed', '1002'}, -- :close, WinClosed <afile> = window-id
{'WinEnter', 'testfile1'},
{'WinLeave', 'testfile1'}, -- :bdelete
{'WinEnter', 'testfile1'},
{'BufLeave', 'testfile1'},
{'BufEnter', 'testfile2'},
{'WinClosed', '1000'},
{ 'WinLeave', '' },
{ 'TabLeave', '' },
{ 'WinEnter', '' },
{ 'TabNew', 'testfile1' }, -- :tabnew
{ 'TabEnter', '' },
{ 'BufLeave', '' },
{ 'BufEnter', 'testfile1' }, -- :split
{ 'WinLeave', 'testfile1' },
{ 'WinEnter', 'testfile1' },
{ 'WinLeave', 'testfile1' },
{ 'WinClosed', '1002' }, -- :close, WinClosed <afile> = window-id
{ 'WinEnter', 'testfile1' },
{ 'WinLeave', 'testfile1' }, -- :bdelete
{ 'WinEnter', 'testfile1' },
{ 'BufLeave', 'testfile1' },
{ 'BufEnter', 'testfile2' },
{ 'WinClosed', '1000' },
}
command('let g:evs = []')
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()
local expected = {
{'BufUnload', ''},
{'BufDelete', ''},
{'BufWipeout', ''},
{'BufEnter', 'testfile1'},
{ 'BufUnload', '' },
{ 'BufDelete', '' },
{ 'BufWipeout', '' },
{ 'BufEnter', 'testfile1' },
}
command('let g:evs = []')
command('autocmd BufEnter * :call add(g:evs, ["BufEnter", expand("<afile>")])')
@ -106,20 +106,23 @@ describe('autocmd', function()
local buf1 = eval("bufnr('%')")
command('new')
local buf2 = eval("bufnr('%')")
command('autocmd WinClosed <buffer> :call add(g:evs, ["WinClosed", expand("<abuf>")])'
-- Attempt recursion.
..' | bdelete '..buf2)
command(
'autocmd WinClosed <buffer> :call add(g:evs, ["WinClosed", expand("<abuf>")])'
-- Attempt recursion.
.. ' | bdelete '
.. buf2
)
command('tabedit testfile2')
command('tabedit testfile3')
command('bdelete '..buf2)
command('bdelete ' .. buf2)
-- Non-recursive: only triggered once.
eq({
{'WinClosed', '2'},
{ 'WinClosed', '2' },
}, eval('g:evs'))
command('bdelete '..buf1)
command('bdelete ' .. buf1)
eq({
{'WinClosed', '2'},
{'WinClosed', '1'},
{ 'WinClosed', '2' },
{ 'WinClosed', '1' },
}, eval('g:evs'))
end)
@ -130,7 +133,7 @@ describe('autocmd', function()
command('new')
command('close')
eq({
{'WinClosed', '1001'},
{ 'WinClosed', '1001' },
}, eval('g:evs'))
end)
@ -139,16 +142,15 @@ describe('autocmd', function()
end)
describe('BufLeave autocommand', function()
it('can wipe out the buffer created by :edit which triggered autocmd',
function()
it('can wipe out the buffer created by :edit which triggered autocmd', function()
meths.set_option_value('hidden', true, {})
curbufmeths.set_lines(0, 1, false, {
'start of test file xx',
'end of test file xx'})
'end of test file xx',
})
command('autocmd BufLeave * bwipeout yy')
eq('Vim(edit):E143: Autocommands unexpectedly deleted new buffer yy',
exc_exec('edit yy'))
eq('Vim(edit):E143: Autocommands unexpectedly deleted new buffer yy', exc_exec('edit yy'))
expect([[
start of test file xx
@ -156,7 +158,7 @@ describe('autocmd', function()
end)
end)
it('++once', function() -- :help autocmd-once
it('++once', function() -- :help autocmd-once
--
-- ":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 * :call add(g:foo, "Many2")')
command('autocmd TabNew * ++once :call add(g:foo, "Once3")')
eq(dedent([[
eq(
dedent([[
--- Autocommands ---
TabNew
@ -186,18 +189,21 @@ describe('autocmd', function()
:call add(g:foo, "Once2")
:call add(g:foo, "Many2")
:call add(g:foo, "Once3")]]),
funcs.execute('autocmd Tabnew'))
funcs.execute('autocmd Tabnew')
)
command('tabnew')
command('tabnew')
command('tabnew')
eq(expected, eval('g:foo'))
eq(dedent([[
eq(
dedent([[
--- Autocommands ---
TabNew
* :call add(g:foo, "Many1")
:call add(g:foo, "Many2")]]),
funcs.execute('autocmd Tabnew'))
funcs.execute('autocmd Tabnew')
)
--
-- ":autocmd ... ++once" handlers can be deleted.
@ -218,7 +224,9 @@ describe('autocmd', function()
}
command('let g:foo = []')
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'")
feed('0llhlh')
eq(expected, eval('g:foo'))
@ -231,15 +239,17 @@ describe('autocmd', function()
'Once2',
}
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, "Once2")')
command('tabnew')
eq(expected, eval('g:foo'))
eq(dedent([[
eq(
dedent([[
--- Autocommands ---]]),
funcs.execute('autocmd Tabnew'))
funcs.execute('autocmd Tabnew')
)
end)
it('internal `aucmd_win` window', function()
@ -250,9 +260,13 @@ describe('autocmd', function()
local screen = Screen.new(50, 10)
screen:attach()
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {background = Screen.colors.LightMagenta},
[3] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1},
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { background = Screen.colors.LightMagenta },
[3] = {
background = Screen.colors.LightMagenta,
bold = true,
foreground = Screen.colors.Blue1,
},
})
source([[
@ -276,7 +290,7 @@ describe('autocmd', function()
|
]])
feed(":enew | doautoall User<cr>")
feed(':enew | doautoall User<cr>')
screen:expect([[
{2:bb }|
{3:~ }|*4
@ -293,14 +307,16 @@ describe('autocmd', function()
eq(7, eval('g:test'))
-- API calls are blocked when aucmd_win is not in scope
eq('Vim(call):E5555: API call: Invalid window id: 1001',
pcall_err(command, "call nvim_set_current_win(g:winid)"))
eq(
'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
-- to reuse the same window, so check again
command("let g:test = v:null")
command("let g:had_value = v:null")
feed(":doautoall User<cr>")
command('let g:test = v:null')
command('let g:had_value = v:null')
feed(':doautoall User<cr>')
screen:expect([[
{2:bb }|
{3:~ }|*4
@ -318,17 +334,19 @@ describe('autocmd', function()
eq(0, eval('g:had_value'))
eq(7, eval('g:test'))
eq('Vim(call):E5555: API call: Invalid window id: 1001',
pcall_err(command, "call nvim_set_current_win(g:winid)"))
eq(
'Vim(call):E5555: API call: Invalid window id: 1001',
pcall_err(command, 'call nvim_set_current_win(g:winid)')
)
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)
screen:attach()
screen:set_default_attr_ids {
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {reverse = true},
[3] = {bold = true, reverse = true},
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { reverse = true },
[3] = { bold = true, reverse = true },
}
-- 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.
-- 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.api.nvim_buf_call(_G.buf, function()
_G.config = vim.api.nvim_win_get_config(0)
end)
return _G.config.relative
]])
]]
)
end)
describe('closing last non-floating window in tab from `aucmd_win`', function()
@ -388,14 +409,18 @@ describe('autocmd', function()
end)
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',
pcall_err(command, 'doautoall BufAdd'))
eq(
'BufAdd Autocommands for "Xa.txt": Vim(close):E814: Cannot close window, only autocmd window would remain',
pcall_err(command, 'doautoall BufAdd')
)
end)
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})
eq('BufAdd Autocommands for "Xa.txt": Vim(close):E814: Cannot close window, only autocmd window would remain',
pcall_err(command, 'doautoall BufAdd'))
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',
pcall_err(command, 'doautoall BufAdd')
)
end)
end)
@ -404,60 +429,88 @@ describe('autocmd', function()
vim.cmd('tabnew')
_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()
local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_close(win, true)
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()
local win = vim.api.nvim_get_current_win()
vim.cmd('tabnext')
vim.api.nvim_win_close(win, true)
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()
local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_hide(win)
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()
local win = vim.api.nvim_get_current_win()
vim.cmd('tabnext')
vim.api.nvim_win_hide(win)
end)
]]))
]]
)
)
end)
it(':doautocmd does not warn "No matching autocommands" #10689', function()
local screen = Screen.new(32, 3)
screen:attach()
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[1] = { bold = true, foreground = Screen.colors.Blue1 },
})
feed(':doautocmd User Foo<cr>')
screen:expect{grid=[[
screen:expect {
grid = [[
^ |
{1:~ }|
:doautocmd User Foo |
]]}
]],
}
feed(':autocmd! SessionLoadPost<cr>')
feed(':doautocmd SessionLoadPost<cr>')
screen:expect{grid=[[
screen:expect {
grid = [[
^ |
{1:~ }|
:doautocmd SessionLoadPost |
]]}
]],
}
end)
describe('v:event is readonly #18063', function()
it('during ChanOpen event', function()
command('autocmd ChanOpen * let v:event.info.id = 0')
funcs.jobstart({'cat'})
funcs.jobstart({ 'cat' })
retry(nil, nil, function()
eq('E46: Cannot change read-only variable "v:event.info"', meths.get_vvar('errmsg'))
end)
@ -473,15 +526,19 @@ describe('autocmd', function()
it('during RecordingLeave event', function()
command([[autocmd RecordingLeave * let v:event.regname = '']])
eq('RecordingLeave Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.regname"',
pcall_err(command, 'normal! qqq'))
eq(
'RecordingLeave Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.regname"',
pcall_err(command, 'normal! qqq')
)
end)
it('during TermClose event', function()
command('autocmd TermClose * let v:event.status = 0')
command('terminal')
eq('TermClose Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.status"',
pcall_err(command, 'bdelete!'))
eq(
'TermClose Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.status"',
pcall_err(command, 'bdelete!')
)
end)
end)
@ -549,9 +606,12 @@ describe('autocmd', function()
eq(0, funcs.exists('#WinNew'))
-- 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
]])
]]
)
eq(false, ok)
eq(true, not not string.find(msg, 'E983:'))
@ -559,7 +619,7 @@ describe('autocmd', function()
it('should have autocmds in filetypedetect group', function()
source [[filetype on]]
neq({}, meths.get_autocmds { group = "filetypedetect" })
neq({}, meths.get_autocmds { group = 'filetypedetect' })
end)
it('should allow comma-separated patterns', function()
@ -571,7 +631,7 @@ describe('autocmd', function()
augroup END
]]
eq(4, #meths.get_autocmds { event = "BufReadCmd", group = "TestingPatterns" })
eq(4, #meths.get_autocmds { event = 'BufReadCmd', group = 'TestingPatterns' })
end)
end)
@ -590,7 +650,7 @@ describe('autocmd', function()
})
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)
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()
command("autocmd BufEnter * if isdirectory(expand('<afile>')) | let g:dir_bufenter = 1 | endif")
request("nvim_command", "split .")
eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory.
eq(2, eval("bufnr('%')")) -- Switched to the dir buffer.
request('nvim_command', 'split .')
eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory.
eq(2, eval("bufnr('%')")) -- Switched to the dir buffer.
end)
it('triggered by "try|:split <dir>|endtry" in a function', function()
@ -27,21 +27,20 @@ describe('autocmd BufEnter', function()
endtry
endfunction
]])
command("call Test()")
eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory.
eq(2, eval("bufnr('%')")) -- Switched to the dir buffer.
command('call Test()')
eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory.
eq(2, eval("bufnr('%')")) -- Switched to the dir buffer.
end)
it('triggered by ":split normal|:help|:bw"', function()
helpers.add_builddir_to_rtp()
command("split normal")
command("wincmd j")
command("help")
command("wincmd L")
command("autocmd BufEnter normal let g:bufentered = 1")
command("bw")
command('split normal')
command('wincmd j')
command('help')
command('wincmd L')
command('autocmd BufEnter normal let g:bufentered = 1')
command('bw')
eq(1, eval('bufnr("%")')) -- The cursor is back to the bottom window
eq(0, eval("exists('g:bufentered')")) -- The autocmd hasn't been triggered
end)
end)

View File

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

View File

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

View File

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

View File

@ -19,9 +19,9 @@ describe('CursorMoved', function()
]])
eq({}, eval('g:log'))
command('new')
eq({'BufEnter2', 'CursorMoved2'}, eval('g:log'))
eq({ 'BufEnter2', 'CursorMoved2' }, eval('g:log'))
command('wincmd w')
eq({'BufEnter2', 'CursorMoved2', 'BufEnter1', 'CursorMoved1'}, eval('g:log'))
eq({ 'BufEnter2', 'CursorMoved2', 'BufEnter1', 'CursorMoved1' }, eval('g:log'))
end)
it('is not triggered by temporarily switching window', function()
@ -41,13 +41,13 @@ describe('CursorMoved', function()
vsplit foo
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({'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'))
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([[
let g:cursormoved = 0
autocmd! CursorMoved

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,10 +8,12 @@ local next_msg = helpers.next_msg
local is_os = helpers.is_os
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)
os.execute('kill -s '..signame..' -- '..pid..' >/dev/null')
os.execute('kill -s ' .. signame .. ' -- ' .. pid .. ' >/dev/null')
end
describe('autocmd Signal', function()
@ -20,19 +22,19 @@ describe('autocmd Signal', function()
it('matches *', function()
command('autocmd Signal * call rpcnotify(1, "foo")')
posix_kill('USR1', funcs.getpid())
eq({'notification', 'foo', {}}, next_msg())
eq({ 'notification', 'foo', {} }, next_msg())
end)
it('matches SIGUSR1', function()
command('autocmd Signal SIGUSR1 call rpcnotify(1, "foo")')
posix_kill('USR1', funcs.getpid())
eq({'notification', 'foo', {}}, next_msg())
eq({ 'notification', 'foo', {} }, next_msg())
end)
it('matches SIGWINCH', function()
command('autocmd Signal SIGWINCH call rpcnotify(1, "foo")')
posix_kill('WINCH', funcs.getpid())
eq({'notification', 'foo', {}}, next_msg())
eq({ 'notification', 'foo', {} }, next_msg())
end)
it('does not match unknown patterns', function()

View File

@ -7,62 +7,76 @@ describe('TabClosed', function()
describe('au TabClosed', function()
describe('with * as <afile>', 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
nvim('command', 'tabnew')
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: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:1:1:2\ntabclosed:1:1:1", nvim('exec', 'tabonly', true)) -- close tabs 1 and 2
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: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
end)
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', 'normal! 1gt')
eq({1, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
eq("tabclosed:2:2:1\ntabclosed:2:2:1", nvim('exec', 'bdelete Xtestfile', true))
eq({1, 1}, 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({ 1, 1 }, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
end)
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', '1tabedit Xtestfile2')
nvim('command', '1tabedit Xtestfile2')
-- Only one tab is closed, and the alternate file is used for the other.
eq({2, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
eq("tabclosed:2:2:2", nvim('exec', 'bdelete Xtestfile2', true))
eq({ 2, 3 }, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
eq('tabclosed:2:2:2', nvim('exec', 'bdelete Xtestfile2', true))
eq('Xtestfile1', nvim('eval', 'bufname("")'))
end)
end)
describe('with NR as <afile>', 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"')
repeat
nvim('command', 'tabnew')
nvim('command', 'tabnew')
until nvim('eval', 'tabpagenr()') == 7 -- current tab is now 7
-- 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
eq("tabclosed:2:2:5\ntabclosed:match", nvim('exec', '2tabclose', true))
eq('tabclosed:2:2:5\ntabclosed:match', nvim('exec', '2tabclose', true))
end)
end)
describe('with close', function()
it('is triggered', function()
nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".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("$")]'))
nvim(
'command',
'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,8 +27,8 @@ describe('v:exiting', function()
local function test_exiting(setup_fn)
local function on_setup()
command('autocmd VimLeavePre * call rpcrequest('..cid..', "exit", "VimLeavePre")')
command('autocmd VimLeave * call rpcrequest('..cid..', "exit", "VimLeave")')
command('autocmd VimLeavePre * call rpcrequest(' .. cid .. ', "exit", "VimLeavePre")')
command('autocmd VimLeave * call rpcrequest(' .. cid .. ', "exit", "VimLeave")')
setup_fn()
end
local requests_args = {}
@ -39,7 +39,7 @@ describe('v:exiting', function()
return ''
end
run(on_request, nil, on_setup)
eq({{'VimLeavePre'}, {'VimLeave'}}, requests_args)
eq({ { 'VimLeavePre' }, { 'VimLeave' } }, requests_args)
end
it('is 0 on normal exit', function()
@ -59,11 +59,16 @@ end)
describe(':cquit', function()
local function test_cq(cmdline, exit_code, redir_msg)
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()
assert_alive()
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'))
end
end

View File

@ -34,8 +34,7 @@ local spawn = helpers.spawn
local set_session = helpers.set_session
describe('fileio', function()
before_each(function()
end)
before_each(function() end)
after_each(function()
check_close()
os.remove('Xtest_startup_shada')
@ -51,25 +50,25 @@ describe('fileio', function()
rmdir('Xtest_backupdir with spaces')
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.
local function startup(extra_args)
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)
set_session(screen_nvim)
local screen = Screen.new(70, 10)
screen:attach()
screen:set_default_attr_ids({
[1] = {foreground = Screen.colors.NvimDarkGrey4};
[2] = {background = Screen.colors.NvimDarkGrey1, foreground = Screen.colors.NvimLightGrey3};
[3] = {foreground = Screen.colors.NvimLightCyan};
[1] = { foreground = Screen.colors.NvimDarkGrey4 },
[2] = { background = Screen.colors.NvimDarkGrey1, foreground = Screen.colors.NvimLightGrey3 },
[3] = { foreground = Screen.colors.NvimLightCyan },
})
return screen
end
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):
@ -80,8 +79,8 @@ describe('fileio', function()
eq(0, request('nvim__stats').fsync)
command('set swapfile')
command('set updatetime=1')
feed('Azub<esc>h') -- File is 'modified'.
sleep(3) -- Allow 'updatetime' to expire.
feed('Azub<esc>h') -- File is 'modified'.
sleep(3) -- Allow 'updatetime' to expire.
retry(3, nil, function()
eq(1, request('nvim__stats').fsync)
end)
@ -101,21 +100,26 @@ describe('fileio', function()
eq('foozubbaz', trim(read_file('Xtest_startup_file1')))
-- 4. Exit caused by deadly signal (+ 'swapfile').
local j = funcs.jobstart(vim.tbl_flatten({args, '--embed'}), {rpc=true})
funcs.rpcrequest(j, 'nvim_exec2', [[
local j = funcs.jobstart(vim.tbl_flatten({ args, '--embed' }), { rpc = true })
funcs.rpcrequest(
j,
'nvim_exec2',
[[
set nofsync directory=Xtest_startup_swapdir
edit Xtest_startup_file2
write
put ='fsyncd text'
]], {})
]],
{}
)
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()
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>')
screen:expect({any = 'fsyncd text'})
screen:expect({ any = 'fsyncd text' })
-- 5. SIGPWR signal.
-- oldtest: Test_signal_PWR()
@ -123,8 +127,14 @@ describe('fileio', function()
it('backup #9709', function()
skip(is_ci('cirrus'))
clear({ args={ '-i', 'Xtest_startup_shada',
'--cmd', 'set directory=Xtest_startup_swapdir' } })
clear({
args = {
'-i',
'Xtest_startup_shada',
'--cmd',
'set directory=Xtest_startup_swapdir',
},
})
command('write Xtest_startup_file1')
feed('ifoo<esc>')
@ -137,8 +147,8 @@ describe('fileio', function()
local foobar_contents = trim(read_file('Xtest_startup_file1'))
local bar_contents = trim(read_file('Xtest_startup_file1~'))
eq('foobar', foobar_contents);
eq('foo', bar_contents);
eq('foobar', foobar_contents)
eq('foo', bar_contents)
end)
it('backup with full path #11214', function()
@ -154,13 +164,16 @@ describe('fileio', function()
command('write')
-- Backup filename = fullpath, separators replaced with "%".
local backup_file_name = string.gsub(currentdir()..'/Xtest_startup_file1',
is_os('win') and '[:/\\]' or '/', '%%') .. '~'
local foo_contents = trim(read_file('Xtest_backupdir/'..backup_file_name))
local backup_file_name = string.gsub(
currentdir() .. '/Xtest_startup_file1',
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'))
eq('foobar', foobar_contents);
eq('foo', foo_contents);
eq('foobar', foobar_contents)
eq('foo', foo_contents)
end)
it('backup with full path with spaces', function()
@ -176,13 +189,16 @@ describe('fileio', function()
command('write')
-- Backup filename = fullpath, separators replaced with "%".
local backup_file_name = string.gsub(currentdir()..'/Xtest_startup_file1',
is_os('win') and '[:/\\]' or '/', '%%') .. '~'
local foo_contents = trim(read_file('Xtest_backupdir with spaces/'..backup_file_name))
local backup_file_name = string.gsub(
currentdir() .. '/Xtest_startup_file1',
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'))
eq('foobar', foobar_contents);
eq('foo', foo_contents);
eq('foobar', foobar_contents)
eq('foo', foo_contents)
end)
it('backup symlinked files #11349', function()
@ -202,11 +218,10 @@ describe('fileio', function()
command('write')
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')
end)
it('backup symlinked files in first available backupdir #11349', function()
skip(is_ci('cirrus'))
clear()
@ -228,7 +243,7 @@ describe('fileio', function()
command('write')
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')
end)
@ -247,7 +262,7 @@ describe('fileio', function()
table.insert(text, '')
eq(text, funcs.readfile(fname, 'b'))
end)
it('read invalid u8 over INT_MAX doesn\'t segfault', function()
it("read invalid u8 over INT_MAX doesn't segfault", function()
clear()
command('call writefile(0zFFFFFFFF, "Xtest-u8-int-max")')
-- This should not segfault
@ -257,18 +272,18 @@ describe('fileio', function()
it(':w! does not show "file has been changed" warning', function()
clear()
write_file("Xtest-overwrite-forced", 'foobar')
write_file('Xtest-overwrite-forced', 'foobar')
command('set nofixendofline')
local screen = Screen.new(40,4)
local screen = Screen.new(40, 4)
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[3] = {bold = true, foreground = Screen.colors.SeaGreen4}
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
[3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
})
screen:attach()
command("set shortmess-=F")
command('set shortmess-=F')
command("e Xtest-overwrite-forced")
command('e Xtest-overwrite-forced')
screen:expect([[
^foobar |
{1:~ }|*2
@ -276,14 +291,14 @@ describe('fileio', function()
]])
-- 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
-- Set the file's access/update time to be
-- 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)
-- use async feed_command because nvim basically hangs on the prompt
feed_command("w")
feed_command('w')
screen:expect([[
{2:WARNING: The file has been changed since}|
{2: reading it!!!} |
@ -291,15 +306,15 @@ describe('fileio', function()
^ |
]])
feed("n")
feed("<cr>")
feed('n')
feed('<cr>')
screen:expect([[
^foobar |
{1:~ }|*2
|
]])
-- Use a screen test because the warning does not set v:errmsg.
command("w!")
command('w!')
screen:expect([[
^foobar |
{1:~ }|*2
@ -333,7 +348,7 @@ describe('tmpdir', function()
end
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 has invalid permissions', testlog)
@ -344,9 +359,9 @@ describe('tmpdir', function()
-- "…/nvim.<user>/" is not a directory:
expect_exit(command, ':qall!')
rmdir(tmproot)
write_file(tmproot, '') -- Not a directory, vim_mktempdir() should skip it.
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
write_file(tmproot, '') -- Not a directory, vim_mktempdir() should skip it.
clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
-- Assert that broken tmpdir root was handled.
assert_log('tempdir root not a directory', testlog, 100)
@ -355,9 +370,9 @@ describe('tmpdir', function()
os.remove(testlog)
os.remove(tmproot)
mkdir(tmproot)
funcs.setfperm(tmproot, 'rwxr--r--') -- Invalid permissions, vim_mktempdir() should skip it.
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
funcs.setfperm(tmproot, 'rwxr--r--') -- Invalid permissions, vim_mktempdir() should skip it.
clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
-- Assert that broken tmpdir root was handled.
assert_log('tempdir root has invalid permissions', testlog, 100)
end)
@ -365,14 +380,14 @@ describe('tmpdir', function()
it('too long', function()
local bigname = ('%s/%s'):format(os_tmpdir, ('x'):rep(666))
mkdir(bigname)
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=bigname, } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = bigname } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
local len = (funcs.tempname()):len()
ok(len > 4 and len < 256, '4 < len < 256', tostring(len))
end)
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)
local function rm_tmpdir()
@ -406,12 +421,13 @@ describe('tmpdir', function()
end)
it('$NVIM_APPNAME relative path', function()
clear({ env={
NVIM_APPNAME='a/b',
NVIM_LOG_FILE=testlog,
TMPDIR=os_tmpdir,
} })
clear({
env = {
NVIM_APPNAME = 'a/b',
NVIM_LOG_FILE = testlog,
TMPDIR = os_tmpdir,
},
})
matches([=[.*[/\\]a%%b%.[^/\\]+]=], funcs.tempname())
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.
clear()
eq(0, request('nvim__stats').log_skip)
clear{env={CDPATH='~doesnotexist'}}
clear { env = { CDPATH = '~doesnotexist' } }
assert(request('nvim__stats').log_skip <= 13)
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.814 T2/child log_init:110: test log message
clear({env={
NVIM_LOG_FILE=testlog,
-- TODO: remove this after nvim_log #7062 is merged.
__NVIM_TEST_LOG='1'
}})
clear({
env = {
NVIM_LOG_FILE = testlog,
-- TODO: remove this after nvim_log #7062 is merged.
__NVIM_TEST_LOG = '1',
},
})
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([[
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()
eq(nil, luv.fs_stat(fname))
funcs.system(
{nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', '--headless',
'--cmd', 'set noswapfile shortmess+=IFW fileformats=unix',
'-s', '-', fname},
{':call setline(1, "42")', ':wqall!', ''})
funcs.system({
nvim_prog_abs(),
'-u',
'NONE',
'-i',
'NONE',
'--headless',
'--cmd',
'set noswapfile shortmess+=IFW fileformats=unix',
'-s',
'-',
fname,
}, { ':call setline(1, "42")', ':wqall!', '' })
eq(0, eval('v:shell_error'))
local attrs = luv.fs_stat(fname)
eq(#('42\n'), attrs.size)
eq(#'42\n', attrs.size)
end)
it('does not expand $VAR', function()
eq(nil, luv.fs_stat(fname))
eq(true, not not dollar_fname:find('%$%w+'))
write_file(dollar_fname, ':call setline(1, "100500")\n:wqall!\n')
funcs.system(
{nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', '--headless',
'--cmd', 'set noswapfile shortmess+=IFW fileformats=unix',
'-s', dollar_fname, fname})
funcs.system({
nvim_prog_abs(),
'-u',
'NONE',
'-i',
'NONE',
'--headless',
'--cmd',
'set noswapfile shortmess+=IFW fileformats=unix',
'-s',
dollar_fname,
fname,
})
eq(0, eval('v:shell_error'))
local attrs = luv.fs_stat(fname)
eq(#('100500\n'), attrs.size)
eq(#'100500\n', attrs.size)
end)
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)
screen:attach()
local args = {
nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE',
'--cmd', '"set noswapfile shortmess+=IFW fileformats=unix notermguicolors"',
'-s', '-'
nvim_prog_abs(),
'-u',
'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
-- data from the terminal #18181
funcs.termopen(string.format([[echo "" | %s]], table.concat(args, " ")), {
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }
funcs.termopen(string.format([[echo "" | %s]], table.concat(args, ' ')), {
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
screen:expect([[
screen:expect(
[[
^ |
~ |*4
{1:[No Name] 0,0-1 All}|
|*2
]], {
[1] = {reverse = true};
})
]],
{
[1] = { reverse = true },
}
)
feed('i:cq<CR>')
screen:expect([[
|
@ -101,12 +127,22 @@ describe('command-line option', function()
it('errors out when trying to use nonexistent file with -s', function()
eq(
'Cannot open for reading: "'..nonexistent_fname..'": no such file or directory\n',
funcs.system(
{nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', '--headless',
'--cmd', 'set noswapfile shortmess+=IFW fileformats=unix',
'--cmd', 'language C',
'-s', nonexistent_fname}))
'Cannot open for reading: "' .. nonexistent_fname .. '": no such file or directory\n',
funcs.system({
nvim_prog_abs(),
'-u',
'NONE',
'-i',
'NONE',
'--headless',
'--cmd',
'set noswapfile shortmess+=IFW fileformats=unix',
'--cmd',
'language C',
'-s',
nonexistent_fname,
})
)
eq(2, eval('v:shell_error'))
end)
@ -114,12 +150,25 @@ describe('command-line option', function()
write_file(fname, ':call setline(1, "1")\n:wqall!\n')
write_file(dollar_fname, ':call setline(1, "2")\n:wqall!\n')
eq(
'Attempt to open script file again: "-s '..dollar_fname..'"\n',
funcs.system(
{nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', '--headless',
'--cmd', 'set noswapfile shortmess+=IFW fileformats=unix',
'--cmd', 'language C',
'-s', fname, '-s', dollar_fname, fname_2}))
'Attempt to open script file again: "-s ' .. dollar_fname .. '"\n',
funcs.system({
nvim_prog_abs(),
'-u',
'NONE',
'-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(nil, luv.fs_stat(fname_2))
end)
@ -128,7 +177,7 @@ describe('command-line option', function()
it('nvim -v, :version', function()
matches('Run ":verbose version"', funcs.execute(':version'))
matches('Compilation: .*Run :checkhealth', funcs.execute(':verbose version'))
matches('Run "nvim %-V1 %-v"', funcs.system({nvim_prog_abs(), '-v'}))
matches('Compilation: .*Run :checkhealth', funcs.system({nvim_prog_abs(), '-V1', '-v'}))
matches('Run "nvim %-V1 %-v"', funcs.system({ nvim_prog_abs(), '-v' }))
matches('Compilation: .*Run :checkhealth', funcs.system({ nvim_prog_abs(), '-V1', '-v' }))
end)
end)

View File

@ -13,7 +13,7 @@ local write_file = helpers.write_file
local function join_path(...)
local pathsep = (is_os('win') and '\\' or '/')
return table.concat({...}, pathsep)
return table.concat({ ... }, pathsep)
end
describe('path collapse', function()
@ -23,40 +23,40 @@ describe('path collapse', function()
before_each(function()
targetdir = join_path('test', 'functional', 'fixtures')
clear()
command('edit '..join_path(targetdir, 'tty-test.c'))
command('edit ' .. join_path(targetdir, 'tty-test.c'))
expected_path = eval('expand("%:p")')
end)
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")'))
end)
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")'))
end)
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')
eq(expected_path, eval('expand("%:p")'))
end)
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")'))
end)
it('with ../ and different starting directory #7117', function()
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")'))
end)
it('with ./../ and different starting directory #7117', function()
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")'))
end)
end)
@ -67,16 +67,16 @@ describe('expand wildcard', function()
it('with special characters #24421', function()
local folders = is_os('win') and {
'{folder}',
'folder$name'
'folder$name',
} or {
'folder-name',
'folder#name'
'folder#name',
}
for _, folder in ipairs(folders) do
mkdir(folder)
local file = join_path(folder, 'file.txt')
write_file(file, '')
eq(file, eval('expand("'..folder..'/*")'))
eq(file, eval('expand("' .. folder .. '/*")'))
rmdir(folder)
end
end)
@ -131,14 +131,30 @@ describe('file search', function()
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
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([[\\LOCALHOST\c$\temp\test-file.txt]], [[LOCALHOST]], [[\\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]]
)
test_cfile(
[[\\LOCALHOST\c$\temp\test-file.txt]],
[[LOCALHOST]],
[[\\LOCALHOST\c$\temp\test-file.txt]]
)
-- not supported yet
test_cfile([[\\.\c:\temp\test-file.txt]], [[.]], [[\\.\c]])
-- not supported yet
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([[\\127.0.0.1\c$\temp\test-file.txt]], [[127.0.0.1]], [[\\127.0.0.1\c$\temp\test-file.txt]])
test_cfile(
[[\\.\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)
---@param funcname 'finddir' | 'findfile'

View File

@ -51,7 +51,10 @@ describe('Remote', function()
local client_starter = spawn(new_argv(), false, nil, true)
set_session(client_starter)
-- 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,
stderr_buffered = true,
on_stdout = function(_, data, _)
@ -60,7 +63,15 @@ describe('Remote', function()
on_stderr = function(_, data, _)
_G.Remote_stderr = table.concat(data, '\n')
end,
}) })]], nvim_prog, '--clean', '--headless', '--server', addr, ...))
}) })]],
nvim_prog,
'--clean',
'--headless',
'--server',
addr,
...
)
)
local res = exec_lua([[return { _G.Remote_stdout, _G.Remote_stderr }]])
client_starter:close()
set_session(server)
@ -95,7 +106,7 @@ describe('Remote', function()
end)
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)
eq(2, #funcs.getwininfo())
-- 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'
it('errors out when prefcond section is truncated', function()
meths.set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_PREFCOND)
-- │ ┌ Section flags (#SNF_REQUIRED or zero)
@ -35,11 +36,11 @@ describe('spellfile', function()
-- │ │ ┌ Condition regex (missing!)
.. '\000\001\001')
meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E758: Truncated spell file',
exc_exec('set spell'))
eq('Vim(set):E758: Truncated spell file', exc_exec('set spell'))
end)
it('errors out when prefcond regexp contains NUL byte', function()
meths.set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_PREFCOND)
-- │ ┌ Section flags (#SNF_REQUIRED or zero)
@ -55,11 +56,11 @@ describe('spellfile', function()
-- │ │ ┌ PREFIXTREE tree length
.. '\000\000\000\000\000\000\000\000\000\000\000\000')
meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E759: Format error in spell file',
exc_exec('set spell'))
eq('Vim(set):E759: Format error in spell file', exc_exec('set spell'))
end)
it('errors out when region contains NUL byte', function()
meths.set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_REGION)
-- │ ┌ Section flags (#SNF_REQUIRED or zero)
@ -72,11 +73,11 @@ describe('spellfile', function()
-- │ │ ┌ PREFIXTREE tree length
.. '\000\000\000\000\000\000\000\000\000\000\000\000')
meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E759: Format error in spell file',
exc_exec('set spell'))
eq('Vim(set):E759: Format error in spell file', exc_exec('set spell'))
end)
it('errors out when SAL section contains NUL byte', function()
meths.set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_SAL)
-- │ ┌ Section flags (#SNF_REQUIRED or zero)
@ -96,15 +97,12 @@ describe('spellfile', function()
-- │ │ ┌ PREFIXTREE tree length
.. '\000\000\000\000\000\000\000\000\000\000\000\000')
meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E759: Format error in spell file',
exc_exec('set spell'))
eq('Vim(set):E759: Format error in spell file', exc_exec('set spell'))
end)
it('errors out when spell header contains NUL bytes', function()
meths.set_option_value('runtimepath', testdir, {})
write_file(testdir .. '/spell/en.ascii.spl',
spellheader:sub(1, -3) .. '\000\000')
write_file(testdir .. '/spell/en.ascii.spl', spellheader:sub(1, -3) .. '\000\000')
meths.set_option_value('spelllang', 'en', {})
eq('Vim(set):E757: This does not look like a spell file',
exc_exec('set spell'))
eq('Vim(set):E757: This does not look like a spell file', exc_exec('set spell'))
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>>]])
-- K on the text "K_spec_out" resolves to `!echo fnord >> K_spec_out`.
feed('i'..test_file..'<ESC>K')
retry(nil, nil, function() eq(1, eval('filereadable("'..test_file..'")')) end)
eq({'fnord'}, eval("readfile('"..test_file.."')"))
feed('i' .. test_file .. '<ESC>K')
retry(nil, nil, function()
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).
helpers.sleep(500)
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()'))
end)
@ -60,9 +62,8 @@ describe('K', function()
it('empty string falls back to :help #19298', function()
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')
eq('E149: Sorry, no help for doesnotexist', meths.get_vvar('errmsg'))
end)
end)

View File

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

View File

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

View File

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

View File

@ -9,11 +9,11 @@ describe('gu and gU', function()
it('works in any locale with default casemap', function()
eq('internal,keepascii', eval('&casemap'))
insert("iI")
feed("VgU")
expect("II")
feed("Vgu")
expect("ii")
insert('iI')
feed('VgU')
expect('II')
feed('Vgu')
expect('ii')
end)
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')
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
end
@ -32,29 +32,29 @@ describe('gu and gU', function()
it('with default casemap', function()
eq('internal,keepascii', eval('&casemap'))
-- expect ASCII behavior
insert("iI")
feed("VgU")
expect("II")
feed("Vgu")
expect("ii")
insert('iI')
feed('VgU')
expect('II')
feed('Vgu')
expect('ii')
end)
it('with casemap=""', function()
command('set casemap=')
-- expect either Turkish locale behavior or ASCII behavior
local iupper = eval("toupper('i')")
if iupper == "İ" then
insert("iI")
feed("VgU")
expect("İI")
feed("Vgu")
expect("iı")
elseif iupper == "I" then
insert("iI")
feed("VgU")
expect("II")
feed("Vgu")
expect("ii")
if iupper == 'İ' then
insert('iI')
feed('VgU')
expect('İI')
feed('Vgu')
expect('iı')
elseif iupper == 'I' then
insert('iI')
feed('VgU')
expect('II')
feed('Vgu')
expect('ii')
else
error("expected toupper('i') to be either 'I' or 'İ'")
end

View File

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

View File

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

View File

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

View File

@ -66,11 +66,11 @@ describe('meta-keys #8226 #13042', function()
command('inoremap <A-j> alt-j')
feed('i<M-l> xxx <A-j><M-h>a<A-h>')
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.
command('iunmap <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>
command('0,$d')
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('t', eval('mode(1)'))
feed('<Esc>j')
eq({ 0, 2, 1, 0, }, funcs.getpos('.'))
eq({ 0, 2, 1, 0 }, funcs.getpos('.'))
eq('nt', eval('mode(1)'))
end)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,15 +21,23 @@ describe('u CTRL-R g- g+', function()
before_each(clear)
local function create_history(num_steps)
if num_steps == 0 then return end
if num_steps == 0 then
return
end
insert('1')
if num_steps == 1 then return end
if num_steps == 1 then
return
end
feed('o2<esc>')
feed('o3<esc>')
feed('u')
if num_steps == 2 then return end
if num_steps == 2 then
return
end
feed('o4<esc>')
if num_steps == 3 then return end
if num_steps == 3 then
return
end
feed('u')
end
@ -57,13 +65,23 @@ describe('u CTRL-R g- g+', function()
undo_and_redo(2, 'g-', 'g+', '1')
end)
it('undoes properly around a branch point', function()
undo_and_redo(3, 'u', '<C-r>', [[
undo_and_redo(
3,
'u',
'<C-r>',
[[
1
2]])
undo_and_redo(3, 'g-', 'g+', [[
2]]
)
undo_and_redo(
3,
'g-',
'g+',
[[
1
2
3]])
3]]
)
end)
it('can find the previous sequence after undoing to a branch', function()
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
-- hist_char2type which after fdb68e35e4c729c7ed097d8ade1da29e5b3f4b31
-- crashed.
it(cmd .. 's' .. prep .. ' the current line by default when feeding',
function()
it(cmd .. 's' .. prep .. ' the current line by default when feeding', function()
feed(':' .. cmd .. '\nabc\ndef\n.\n')
eq(ret1, buffer_contents())
end)
@ -63,8 +62,8 @@ describe('the first line is redrawn correctly after inserting text in an empty b
clear()
screen = Screen.new(20, 8)
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue},
[2] = {bold = true, reverse = true},
[1] = { bold = true, foreground = Screen.colors.Blue },
[2] = { bold = true, reverse = true },
})
screen:attach()
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 ok = helpers.ok
local clear = helpers.clear
describe(":argument", function()
describe(':argument', function()
before_each(function()
clear()
end)
it("does not restart :terminal buffer", function()
command("terminal")
helpers.feed([[<C-\><C-N>]])
command("argadd")
helpers.feed([[<C-\><C-N>]])
local bufname_before = funcs.bufname("%")
local bufnr_before = funcs.bufnr("%")
helpers.ok(nil ~= string.find(bufname_before, "^term://")) -- sanity
it('does not restart :terminal buffer', function()
command('terminal')
helpers.feed([[<C-\><C-N>]])
command('argadd')
helpers.feed([[<C-\><C-N>]])
local bufname_before = funcs.bufname('%')
local bufnr_before = funcs.bufnr('%')
helpers.ok(nil ~= string.find(bufname_before, '^term://')) -- sanity
command("argument 1")
helpers.feed([[<C-\><C-N>]])
command('argument 1')
helpers.feed([[<C-\><C-N>]])
local bufname_after = funcs.bufname("%")
local bufnr_after = funcs.bufnr("%")
eq("["..bufname_before.."]", helpers.eval('trim(execute("args"))'))
ok(funcs.line('$') > 1)
eq(bufname_before, bufname_after)
eq(bufnr_before, bufnr_after)
local bufname_after = funcs.bufname('%')
local bufnr_after = funcs.bufnr('%')
eq('[' .. bufname_before .. ']', helpers.eval('trim(execute("args"))'))
ok(funcs.line('$') > 1)
eq(bufname_before, bufname_after)
eq(bufnr_before, bufnr_after)
end)
end)

View File

@ -21,18 +21,30 @@ local directories = {
}
-- Shorthand writing to get the current working directory
local cwd = function(...) return call('getcwd', ...) end -- effective working dir
local wcwd = function() return cwd(0) end -- window dir
local tcwd = function() return cwd(-1, 0) end -- tab dir
local cwd = function(...)
return call('getcwd', ...)
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
local lwd = function(...) return call('haslocaldir', ...) end -- effective working dir
local wlwd = function() return lwd(0) end -- window dir
local tlwd = function() return lwd(-1, 0) end -- tab dir
local lwd = function(...)
return call('haslocaldir', ...)
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
-- Test both the `cd` and `chdir` variants
for _, cmd in ipairs {'cd', 'chdir'} do
for _, cmd in ipairs { 'cd', 'chdir' } do
describe(':' .. cmd, function()
before_each(function()
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
command('tabnew')
eq(globalDir, cwd())
eq(globalDir, tcwd()) -- has no tab-local directory
eq(globalDir, tcwd()) -- has no tab-local directory
eq(0, tlwd())
eq(globalDir, wcwd()) -- has no window-local directory
eq(globalDir, wcwd()) -- has no window-local directory
eq(0, wlwd())
-- Change tab-local working directory and verify it is different
command('silent t' .. cmd .. ' ' .. directories.tab)
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(cwd(), wcwd()) -- still no window-directory
eq(cwd(), wcwd()) -- still no window-directory
eq(0, wlwd())
-- Create a new window in this tab to test `:lcd`
command('new')
eq(1, tlwd()) -- Still tab-local working directory
eq(0, wlwd()) -- Still no window-local working directory
eq(1, tlwd()) -- Still tab-local working directory
eq(0, wlwd()) -- Still no window-local working directory
eq(globalDir .. pathsep .. directories.tab, cwd())
command('silent l' .. cmd .. ' ../' .. directories.window)
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
command('wincmd w')
eq(globalDir .. pathsep .. directories.tab, cwd())
eq(globalDir .. pathsep .. directories.tab, cwd())
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
command('tabnext')
eq(globalDir, cwd() )
eq(globalDir, cwd())
eq(0, tlwd())
eq(0, wlwd())
@ -207,31 +219,31 @@ for _, cmd in ipairs {'cd', 'chdir'} do
command('silent ' .. cmd .. ' ' .. directories.global)
eq(globalDir .. pathsep .. directories.global, cwd())
command('tabnext')
eq(globalDir .. pathsep .. directories.tab, cwd())
eq(globalDir .. pathsep .. directories.tab, cwd())
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
command('silent ' .. cmd .. ' ..')
eq(globalDir, cwd() )
eq(0 , tlwd())
eq(0 , wlwd())
eq(globalDir, cwd())
eq(0, tlwd())
eq(0, wlwd())
-- Which also affects the first tab
command('tabnext')
eq(globalDir, cwd())
-- But not in a window with its own local directory
command('tabnext | wincmd w')
eq(globalDir .. pathsep .. directories.window, cwd() )
eq(0 , tlwd())
eq(globalDir .. pathsep .. directories.window, cwd())
eq(0, tlwd())
eq(globalDir .. pathsep .. directories.window, wcwd())
end)
end)
end
-- Test legal parameters for 'getcwd' and 'haslocaldir'
for _, cmd in ipairs {'getcwd', 'haslocaldir'} do
describe(cmd..'()', function()
for _, cmd in ipairs { 'getcwd', 'haslocaldir' } do
describe(cmd .. '()', function()
before_each(function()
clear()
end)
@ -271,7 +283,7 @@ for _, cmd in ipairs {'getcwd', 'haslocaldir'} do
end)
end
describe("getcwd()", function ()
describe('getcwd()', function()
before_each(function()
clear()
mkdir(directories.global)
@ -281,11 +293,11 @@ describe("getcwd()", function ()
helpers.rmdir(directories.global)
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'))
command("cd "..directories.global)
command("call delete('../"..directories.global.."', 'd')")
eq("", helpers.eval("getcwd()"))
command('cd ' .. directories.global)
command("call delete('../" .. directories.global .. "', 'd')")
eq('', helpers.eval('getcwd()'))
end)
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 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
before_each(function()
clear()
screen = Screen.new(65, 8)
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[3] = {bold = true, foreground = Screen.colors.SeaGreen4},
[4] = {bold = true},
[5] = {background = Screen.colors.LightGrey},
[6] = {foreground = Screen.colors.Blue1},
[7] = {bold = true, reverse = true},
[8] = {background = Screen.colors.WebGray},
[9] = {background = Screen.colors.LightMagenta},
[10] = {foreground = Screen.colors.Red},
[1] = { bold = true, foreground = Screen.colors.Blue1 },
[2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
[3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
[4] = { bold = true },
[5] = { background = Screen.colors.LightGrey },
[6] = { foreground = Screen.colors.Blue1 },
[7] = { bold = true, reverse = true },
[8] = { background = Screen.colors.WebGray },
[9] = { background = Screen.colors.LightMagenta },
[10] = { foreground = Screen.colors.Red },
})
screen:attach()
@ -57,7 +57,7 @@ describe('mappings with <Cmd>', function()
feed('gg')
cmdmap('<F8>', 'startinsert')
cmdmap('<F9>', 'stopinsert')
command("abbr foo <Cmd>let g:y = 17<cr>bar")
command('abbr foo <Cmd>let g:y = 17<cr>bar')
end)
after_each(function()
@ -121,7 +121,7 @@ describe('mappings with <Cmd>', function()
feed('<F3>')
eq('foo…bar', eval('g:str'))
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>')
eq(str, eval('g:str'))
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)'))
-- operator-pending mode
feed("d<F3>")
feed('d<F3>')
eq('no', eval('m'))
-- did leave operator-pending mode
eq('n', eval('mode(1)'))
@ -171,21 +171,21 @@ describe('mappings with <Cmd>', function()
eq('i', eval('mode(1)'))
-- replace mode
feed("<Ins><F3>")
feed('<Ins><F3>')
eq('R', eval('m'))
eq('R', eval('mode(1)'))
feed('<esc>')
eq('n', eval('mode(1)'))
-- virtual replace mode
feed("gR<F3>")
feed('gR<F3>')
eq('Rv', eval('m'))
eq('Rv', eval('mode(1)'))
feed('<esc>')
eq('n', eval('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('mode(1)'))
feed('<esc>')
@ -212,15 +212,15 @@ describe('mappings with <Cmd>', function()
-- check v:count and v:register works
feed('<F2>')
eq({'n', 0, '"'}, eval('s'))
eq({ 'n', 0, '"' }, eval('s'))
feed('7<F2>')
eq({'n', 7, '"'}, eval('s'))
eq({ 'n', 7, '"' }, eval('s'))
feed('"e<F2>')
eq({'n', 0, 'e'}, eval('s'))
eq({ 'n', 0, 'e' }, eval('s'))
feed('5"k<F2>')
eq({'n', 5, 'k'}, eval('s'))
eq({ 'n', 5, 'k' }, eval('s'))
feed('"+2<F2>')
eq({'n', 2, '+'}, eval('s'))
eq({ 'n', 2, '+' }, eval('s'))
-- text object enters visual mode
feed('<F7>')
@ -249,7 +249,7 @@ describe('mappings with <Cmd>', function()
{4:-- INSERT --} |
]])
-- 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)'))
feed('<esc>')
@ -261,7 +261,7 @@ describe('mappings with <Cmd>', function()
|
]])
-- 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)'))
end)
@ -270,9 +270,11 @@ describe('mappings with <Cmd>', function()
command('noremap ,f <Cmd>nosuchcommand<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 ,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([[
^some short lines |
aa |
@ -282,9 +284,9 @@ describe('mappings with <Cmd>', function()
:normal ,x |
]])
eq('Vim:E492: Not an editor command: nosuchcommand', exc_exec("normal ,f"))
eq('very error', exc_exec("normal ,e"))
eq('Vim(echoerr):The message.', exc_exec("normal ,m"))
eq('Vim:E492: Not an editor command: nosuchcommand', exc_exec('normal ,f'))
eq('very error', exc_exec('normal ,e'))
eq('Vim(echoerr):The message.', exc_exec('normal ,m'))
feed('w')
screen:expect([[
some ^short lines |
@ -296,7 +298,7 @@ describe('mappings with <Cmd>', function()
]])
command(':%d')
eq('Vim(echoerr):Err', exc_exec("normal ,w"))
eq('Vim(echoerr):Err', exc_exec('normal ,w'))
screen:expect([[
^ |
0 |
@ -332,7 +334,7 @@ describe('mappings with <Cmd>', function()
-- can invoke operator, ending visual mode
feed('<F5>')
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
feed('ggvw<F6>')
@ -393,12 +395,12 @@ describe('mappings with <Cmd>', function()
-- visual mapping in select mode restart select mode after operator
feed('<F5>')
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
feed('<F2>')
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
feed('<esc>ggvw<c-g><F6>')
@ -468,17 +470,16 @@ describe('mappings with <Cmd>', function()
eq('i', eval('mode(1)'))
end)
it('works in operator-pending mode', function()
feed('d<F4>')
expect([[
lines
of test text]])
eq({'some short '}, funcs.getreg('"',1,1))
eq({ 'some short ' }, funcs.getreg('"', 1, 1))
feed('.')
expect([[
test text]])
eq({'lines', 'of '}, funcs.getreg('"',1,1))
eq({ 'lines', 'of ' }, funcs.getreg('"', 1, 1))
feed('uu')
expect([[
some short lines
@ -504,7 +505,7 @@ describe('mappings with <Cmd>', function()
feed('"bd<F7>')
expect([[
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
feed('d<F8>')
@ -514,7 +515,6 @@ describe('mappings with <Cmd>', function()
end)
it('works in insert mode', function()
-- works the same as <c-o>w<c-o>w
feed('iindeed <F4>little ')
screen:expect([[
@ -535,7 +535,6 @@ describe('mappings with <Cmd>', function()
{3:Press ENTER or type command to continue}^ |
]])
feed('<cr>')
eq('E605: Exception not caught: very error', eval('v:errmsg'))
-- still in insert
@ -562,7 +561,7 @@ describe('mappings with <Cmd>', function()
of stuff test text]])
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
screen:expect([[
@ -704,7 +703,6 @@ describe('mappings with <Cmd>', function()
]])
eq('i', eval('mode(1)'))
eq(9, eval('g:y'))
end)
it("doesn't crash when invoking cmdline mode recursively #8859", function()
@ -726,18 +724,20 @@ describe('mappings with <Cmd>', function()
]])
end)
it("works with <SID> mappings", function()
it('works with <SID> mappings', function()
command('new!')
write_file(tmpfile, [[
write_file(
tmpfile,
[[
map <f2> <Cmd>call <SID>do_it()<Cr>
function! s:do_it()
let g:x = 10
endfunction
]])
command('source '..tmpfile)
]]
)
command('source ' .. tmpfile)
feed('<f2>')
eq('', eval('v:errmsg'))
eq(10, eval('g:x'))
end)
end)

View File

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

View File

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

View File

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

View File

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

View File

@ -14,15 +14,15 @@ local exec_capture = helpers.exec_capture
local matches = helpers.matches
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)
for _,v in pairs(fn_tbl) do
eq(expected, use_eval and eval(v..'('..input..')') or funcs[v](input))
for _, v in pairs(fn_tbl) do
eq(expected, use_eval and eval(v .. '(' .. input .. ')') or funcs[v](input))
end
end
local function assert_matches_echo_dump(expected, input, use_eval)
for _,v in pairs(fn_tbl) do
matches(expected, use_eval and eval(v..'('..input..')') or funcs[v](input))
for _, v in pairs(fn_tbl) do
matches(expected, use_eval and eval(v .. '(' .. input .. ')') or funcs[v](input))
end
end
@ -85,14 +85,12 @@ describe(':echo :echon :echomsg :echoerr', function()
eq('v:null', funcs.StringErr(NIL))
end)
it('dumps values with at most six digits after the decimal point',
function()
it('dumps values with at most six digits after the decimal point', function()
assert_same_echo_dump('1.234568e-20', 1.23456789123456789123456789e-020)
assert_same_echo_dump('1.234568', 1.23456789123456789123456789)
end)
it('dumps values with at most seven digits before the decimal point',
function()
it('dumps values with at most seven digits before the decimal point', function()
assert_same_echo_dump('1234567.891235', 1234567.89123456789123456789)
assert_same_echo_dump('1.234568e7', 12345678.9123456789123456789)
end)
@ -115,8 +113,8 @@ describe(':echo :echon :echomsg :echoerr', function()
end)
it('dumps large values', function()
assert_same_echo_dump('2147483647', 2^31-1)
assert_same_echo_dump('-2147483648', -2^31)
assert_same_echo_dump('2147483647', 2 ^ 31 - 1)
assert_same_echo_dump('-2147483648', -2 ^ 31)
end)
end)
@ -198,75 +196,95 @@ describe(':echo :echon :echomsg :echoerr', function()
let TestDictRef = function('TestDict', d)
let d.tdr = TestDictRef
]])
eq(dedent([[
eq(
dedent([[
function('TestDict', {'tdr': function('TestDict', {...@1})})]]),
exec_capture('echo String(d.tdr)'))
exec_capture('echo String(d.tdr)')
)
end)
it('dumps automatically created partials', function()
assert_same_echo_dump(
"function('<SNR>1_Test2', {'f': function('<SNR>1_Test2')})",
'{"f": Test2_f}.f',
true)
true
)
assert_same_echo_dump(
"function('<SNR>1_Test2', [1], {'f': function('<SNR>1_Test2', [1])})",
'{"f": function(Test2_f, [1])}.f',
true)
true
)
end)
it('dumps manually created partials', function()
assert_same_echo_dump("function('Test3', [1, 2], {})",
"function('Test3', [1, 2], {})", true)
assert_same_echo_dump("function('Test3', [1, 2])",
"function('Test3', [1, 2])", true)
assert_same_echo_dump("function('Test3', {})",
"function('Test3', {})", true)
assert_same_echo_dump("function('Test3', [1, 2], {})", "function('Test3', [1, 2], {})", true)
assert_same_echo_dump("function('Test3', [1, 2])", "function('Test3', [1, 2])", true)
assert_same_echo_dump("function('Test3', {})", "function('Test3', {})", true)
end)
it('does not crash or halt when dumping partials with reference cycles in self',
function()
meths.set_var('d', {v=true})
eq(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}))'))
it('does not crash or halt when dumping partials with reference cycles in self', function()
meths.set_var('d', { v = true })
eq(
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}))')
)
end)
it('does not show errors when dumping partials referencing the same dictionary',
function()
it('does not show errors when dumping partials referencing the same dictionary', function()
command('let d = {}')
-- Regression for “eval/typval_encode: Dump empty dictionary before
-- 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)
-- properly”, results in crash.
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)
it('does not crash or halt when dumping partials with reference cycles in arguments',
function()
it('does not crash or halt when dumping partials with reference cycles in arguments', function()
meths.set_var('l', {})
eval('add(l, l)')
-- Regression: the below line used to crash (add returns original list and
-- there was error in dumping partials). Tested explicitly in
-- test/unit/api/private_helpers_spec.lua.
eval('add(l, function("Test1", l))')
eq(dedent([=[
function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])]=]),
exec_capture('echo String(function("Test1", l))'))
eq(
dedent(
[=[
function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])]=]
),
exec_capture('echo String(function("Test1", l))')
)
end)
it('does not crash or halt when dumping partials with reference cycles in self and arguments',
function()
meths.set_var('d', {v=true})
meths.set_var('l', {})
eval('add(l, l)')
eval('add(l, function("Test1", l))')
eval('add(l, function("Test1", d))')
eq(dedent([=[
{'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)
it(
'does not crash or halt when dumping partials with reference cycles in self and arguments',
function()
meths.set_var('d', { v = true })
meths.set_var('l', {})
eval('add(l, l)')
eval('add(l, function("Test1", l))')
eval('add(l, function("Test1", d))')
eq(
dedent(
[=[
{'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)
describe('used to represent lists', function()
@ -275,15 +293,15 @@ describe(':echo :echon :echomsg :echoerr', function()
end)
it('dumps non-empty list', function()
assert_same_echo_dump('[1, 2]', {1,2})
assert_same_echo_dump('[1, 2]', { 1, 2 })
end)
it('dumps nested lists', function()
assert_same_echo_dump('[[[[[]]]]]', {{{{{}}}}})
assert_same_echo_dump('[[[[[]]]]]', { { { { {} } } } })
end)
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)
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()
command('let d = {}')
assert_same_echo_dump('[{}, {}]', '[d, d]', true)
eq('[function(\'tr\', {}), {}]', eval('String([function("tr", d), d])'))
eq('[{}, function(\'tr\', {})]', eval('String([d, function("tr", d)])'))
eq("[function('tr', {}), {}]", eval('String([function("tr", d), d])'))
eq("[{}, function('tr', {})]", eval('String([d, function("tr", d)])'))
end)
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)
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})')
eq(0, exc_exec('echo String(d)'))
end)
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})')
eq('{\'d\': {...@0}}',
exec_capture('echo String(d)'))
eq('{\'out\': {\'d\': {...@1}}}',
exec_capture('echo String({"out": d})'))
eq("{'d': {...@0}}", exec_capture('echo String(d)'))
eq("{'out': {'d': {...@1}}}", exec_capture('echo String({"out": d})'))
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 ok = helpers.ok
local clear = helpers.clear
local feed = helpers.feed
describe(":edit", function()
describe(':edit', function()
before_each(function()
clear()
end)
it("without arguments does not restart :terminal buffer", function()
command("terminal")
feed([[<C-\><C-N>]])
local bufname_before = funcs.bufname("%")
local bufnr_before = funcs.bufnr("%")
helpers.ok(nil ~= string.find(bufname_before, "^term://")) -- sanity
it('without arguments does not restart :terminal buffer', function()
command('terminal')
feed([[<C-\><C-N>]])
local bufname_before = funcs.bufname('%')
local bufnr_before = funcs.bufnr('%')
helpers.ok(nil ~= string.find(bufname_before, '^term://')) -- sanity
command("edit")
command('edit')
local bufname_after = funcs.bufname("%")
local bufnr_after = funcs.bufnr("%")
ok(funcs.line('$') > 1)
eq(bufname_before, bufname_after)
eq(bufnr_before, bufnr_after)
local bufname_after = funcs.bufname('%')
local bufnr_after = funcs.bufnr('%')
ok(funcs.line('$') > 1)
eq(bufname_before, bufname_after)
eq(bufnr_before, bufnr_after)
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
describe('&encoding', function()
before_each(function()
clear()
-- 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()
feed_command('set encoding=utf-8')
eq("", eval('v:errmsg'))
eq('', eval('v:errmsg'))
clear('--cmd', 'set enc=utf-8')
eq("", eval('v:errmsg'))
eq('', eval('v:errmsg'))
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 eq = helpers.eq
local clear = helpers.clear
@ -20,15 +20,25 @@ describe('Ex cmds', function()
command(':later 9999999999999999999999999999999999999999')
command(':echo expand("#<9999999999999999999999999999999999999999")')
command(':lockvar 9999999999999999999999999999999999999999')
command(':winsize 9999999999999999999999999999999999999999 9999999999999999999999999999999999999999')
check_excmd_err(':tabnext 9999999999999999999999999999999999999999',
'Vim(tabnext):E475: Invalid argument: 9999999999999999999999999999999999999999')
check_excmd_err(':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'))
command(
':winsize 9999999999999999999999999999999999999999 9999999999999999999999999999999999999999'
)
check_excmd_err(
':tabnext 9999999999999999999999999999999999999999',
'Vim(tabnext):E475: Invalid argument: 9999999999999999999999999999999999999999'
)
check_excmd_err(
':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()
end)

View File

@ -8,7 +8,7 @@ local rmdir = helpers.rmdir
local mkdir = helpers.mkdir
describe(':file', function()
local swapdir = luv.cwd()..'/Xtest-file_spec'
local swapdir = luv.cwd() .. '/Xtest-file_spec'
before_each(function()
clear()
rmdir(swapdir)
@ -19,18 +19,17 @@ describe(':file', function()
rmdir(swapdir)
end)
it("rename does not lose swapfile #6487", function()
it('rename does not lose swapfile #6487', function()
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
-- attempt to create a swapfile in different directory.
command('set directory^='..swapdir..'//')
command('set directory^=' .. swapdir .. '//')
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.
command('file '..testfile_renamed)
eq(testfile_renamed..'.swp',
string.match(funcs.execute('swapname'), '[^%%]+$'))
command('file ' .. testfile_renamed)
eq(testfile_renamed .. '.swp', string.match(funcs.execute('swapname'), '[^%%]+$'))
end)
end)

View File

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

View File

@ -1,5 +1,5 @@
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 clear = helpers.clear
local eval, exc_exec = helpers.eval, helpers.exc_exec
@ -17,15 +17,18 @@ describe(':highlight', function()
end)
it('invalid color name', function()
eq('Vim(highlight):E421: Color name or number not recognized: ctermfg=#181818',
exc_exec("highlight normal ctermfg=#181818"))
eq('Vim(highlight):E421: Color name or number not recognized: ctermbg=#181818',
exc_exec("highlight normal ctermbg=#181818"))
eq(
'Vim(highlight):E421: Color name or number not recognized: ctermfg=#181818',
exc_exec('highlight normal ctermfg=#181818')
)
eq(
'Vim(highlight):E421: Color name or number not recognized: ctermbg=#181818',
exc_exec('highlight normal ctermbg=#181818')
)
end)
it('invalid group name', function()
eq('Vim(highlight):E411: Highlight group not found: foo',
exc_exec("highlight foo"))
eq('Vim(highlight):E411: Highlight group not found: foo', exc_exec('highlight foo'))
end)
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 ... '))
end)
end)
end)

View File

@ -8,27 +8,30 @@ local testprg = helpers.testprg
describe(':make', function()
clear()
before_each(function ()
before_each(function()
clear()
end)
describe('with powershell', function()
if not has_powershell() then
pending("not tested; powershell was not found", function() end)
pending('not tested; powershell was not found', function() end)
return
end
before_each(function ()
before_each(function()
helpers.set_shell_powershell()
end)
it('captures stderr & non zero exit code #14349', function ()
nvim('set_option_value', 'makeprg', testprg('shell-test')..' foo', {})
it('captures stderr & non zero exit code #14349', function()
nvim('set_option_value', 'makeprg', testprg('shell-test') .. ' foo', {})
local out = eval('execute("make")')
-- 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)
it('captures stderr & zero exit code #14349', function ()
it('captures stderr & zero exit code #14349', function()
nvim('set_option_value', 'makeprg', testprg('shell-test'), {})
local out = eval('execute("make")')
-- Ensure there are no "shell returned X" messages between
@ -36,7 +39,5 @@ describe(':make', function()
matches('LastExitCode%s+ready [$]%s+[(]', out)
matches('\n.*%: ready [$]', out)
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 eq = helpers.eq
@ -33,23 +33,27 @@ describe(':*map', function()
it('shows <Nop> as mapping rhs', function()
command('nmap asdf <Nop>')
eq([[
eq(
[[
n asdf <Nop>]],
exec_capture('nmap asdf'))
exec_capture('nmap asdf')
)
end)
it('mappings with description can be filtered', function()
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', 'asdf3', 'qwert', {desc='do the other thing'})
eq([[
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', 'asdf3', 'qwert', { desc = 'do the other thing' })
eq(
[[
n asdf3 qwert
do the other thing
n asdf1 qwert
do the one thing]],
exec_capture('filter the nmap'))
exec_capture('filter the nmap')
)
end)
it('<Plug> mappings ignore nore', function()
@ -75,7 +79,7 @@ n asdf1 qwert
nmap increase_x_remap 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('.')"))
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 funcs = helpers.funcs
describe(':emenu', function()
before_each(function()
clear()
command('nnoremenu Test.Test inormal<ESC>')
@ -41,26 +39,25 @@ describe(':emenu', function()
end)
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.
nvim('command', 'emenu Edit.Paste')
-- Invoke "Edit.Paste" in normal-mode.
nvim('command', 'emenu Edit.Paste')
-- Invoke "Edit.Paste" and "Test.Test" in command-mode.
feed(':')
nvim('command', 'emenu Edit.Paste')
nvim('command', 'emenu Test.Test')
-- Invoke "Edit.Paste" and "Test.Test" in command-mode.
feed(':')
nvim('command', 'emenu Edit.Paste')
nvim('command', 'emenu Test.Test')
expect([[
expect([[
this is a sentence
this]])
-- Assert that Edit.Paste pasted @" into the commandline.
eq('thiscmdmode', eval('getcmdline()'))
-- Assert that Edit.Paste pasted @" into the commandline.
eq('thiscmdmode', eval('getcmdline()'))
end)
end)
describe('menu_get', function()
before_each(function()
clear()
command([=[
@ -83,12 +80,12 @@ describe('menu_get', function()
end)
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:
-- print(require('vim.inspect')(m))
local expected = {
{
shortcut = "T",
shortcut = 'T',
hidden = 0,
submenus = {
{
@ -97,45 +94,45 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "insert",
silent = 0
rhs = 'insert',
silent = 0,
},
s = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "x",
silent = 0
rhs = 'x',
silent = 0,
},
n = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "inormal<Esc>",
silent = 0
rhs = 'inormal<Esc>',
silent = 0,
},
v = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "x",
silent = 0
rhs = 'x',
silent = 0,
},
c = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "cmdmode",
silent = 0
}
rhs = 'cmdmode',
silent = 0,
},
},
priority = 500,
name = "Test",
hidden = 0
name = 'Test',
hidden = 0,
},
{
priority = 500,
name = "Nested",
name = 'Nested',
submenus = {
{
mappings = {
@ -143,34 +140,34 @@ describe('menu_get', function()
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level1",
silent = 0
rhs = 'level1',
silent = 0,
},
v = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level1",
silent = 0
rhs = 'level1',
silent = 0,
},
s = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level1",
silent = 0
rhs = 'level1',
silent = 0,
},
n = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level1",
silent = 0
}
rhs = 'level1',
silent = 0,
},
},
priority = 500,
name = "test",
hidden = 0
name = 'test',
hidden = 0,
},
{
mappings = {
@ -178,67 +175,67 @@ describe('menu_get', function()
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level2",
silent = 0
rhs = 'level2',
silent = 0,
},
v = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level2",
silent = 0
rhs = 'level2',
silent = 0,
},
s = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level2",
silent = 0
rhs = 'level2',
silent = 0,
},
n = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level2",
silent = 0
}
rhs = 'level2',
silent = 0,
},
},
priority = 500,
name = "Nested2",
hidden = 0
}
name = 'Nested2',
hidden = 0,
},
},
hidden = 0
}
hidden = 0,
},
},
priority = 500,
name = "Test"
name = 'Test',
},
{
priority = 500,
name = "Export",
name = 'Export',
submenus = {
{
tooltip = "This is the tooltip",
tooltip = 'This is the tooltip',
hidden = 0,
name = "Script",
name = 'Script',
priority = 500,
mappings = {
n = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "p",
silent = 0
}
}
}
rhs = 'p',
silent = 0,
},
},
},
},
hidden = 0
hidden = 0,
},
{
priority = 500,
name = "Edit",
name = 'Edit',
submenus = {
{
mappings = {
@ -246,27 +243,27 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "<C-R>\"",
silent = 0
rhs = '<C-R>"',
silent = 0,
},
n = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "p",
silent = 0
}
rhs = 'p',
silent = 0,
},
},
priority = 500,
name = "Paste",
hidden = 0
}
name = 'Paste',
hidden = 0,
},
},
hidden = 0
hidden = 0,
},
{
priority = 500,
name = "]Export",
name = ']Export',
submenus = {
{
mappings = {
@ -274,72 +271,76 @@ describe('menu_get', function()
sid = 0,
noremap = 0,
enabled = 1,
rhs = "thisoneshouldbehidden",
silent = 0
rhs = 'thisoneshouldbehidden',
silent = 0,
},
v = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "thisoneshouldbehidden",
silent = 0
rhs = 'thisoneshouldbehidden',
silent = 0,
},
s = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "thisoneshouldbehidden",
silent = 0
rhs = 'thisoneshouldbehidden',
silent = 0,
},
n = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "thisoneshouldbehidden",
silent = 0
}
rhs = 'thisoneshouldbehidden',
silent = 0,
},
},
priority = 500,
name = "hidden",
hidden = 0
}
name = 'hidden',
hidden = 0,
},
},
hidden = 1
}
hidden = 1,
},
}
eq(expected, m)
end)
it('matching path, all modes', function()
local m = funcs.menu_get("Export", "a")
local expected = { {
hidden = 0,
name = "Export",
priority = 500,
submenus = { {
tooltip = "This is the tooltip",
local m = funcs.menu_get('Export', 'a')
local expected = {
{
hidden = 0,
name = "Script",
name = 'Export',
priority = 500,
mappings = {
n = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "p",
silent = 0
}
}
} }
} }
submenus = {
{
tooltip = 'This is the tooltip',
hidden = 0,
name = 'Script',
priority = 500,
mappings = {
n = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = 'p',
silent = 0,
},
},
},
},
},
}
eq(expected, m)
end)
it('no path, matching modes', function()
local m = funcs.menu_get("","i")
local m = funcs.menu_get('', 'i')
local expected = {
{
shortcut = "T",
shortcut = 'T',
hidden = 0,
submenus = {
{
@ -348,27 +349,27 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "insert",
silent = 0
}
rhs = 'insert',
silent = 0,
},
},
priority = 500,
name = "Test",
hidden = 0
name = 'Test',
hidden = 0,
},
},
priority = 500,
name = "Test"
}
name = 'Test',
},
}
eq(expected, m)
end)
it('matching path and modes', function()
local m = funcs.menu_get("Test","i")
local m = funcs.menu_get('Test', 'i')
local expected = {
{
shortcut = "T",
shortcut = 'T',
submenus = {
{
mappings = {
@ -376,26 +377,25 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "insert",
silent = 0
rhs = 'insert',
silent = 0,
},
},
priority = 500,
name = "Test",
hidden = 0
name = 'Test',
hidden = 0,
},
},
priority = 500,
name = "Test",
hidden = 0
}
name = 'Test',
hidden = 0,
},
}
eq(expected, m)
end)
end)
describe('menu_get', function()
before_each(function()
clear()
command('aunmenu *')
@ -412,10 +412,10 @@ describe('menu_get', function()
command('nnoremenu &Test.Test8 <NoP>')
command('nnoremenu &Test.Test9 ""')
local m = funcs.menu_get("");
local m = funcs.menu_get('')
local expected = {
{
shortcut = "T",
shortcut = 'T',
hidden = 0,
submenus = {
{
@ -425,12 +425,12 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "inormal<Esc>",
silent = 0
}
rhs = 'inormal<Esc>',
silent = 0,
},
},
name = "Test",
hidden = 0
name = 'Test',
hidden = 0,
},
{
priority = 500,
@ -439,12 +439,12 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "<Tab><Esc>",
silent = 0
}
rhs = '<Tab><Esc>',
silent = 0,
},
},
name = "Test2",
hidden = 0
name = 'Test2',
hidden = 0,
},
{
priority = 500,
@ -453,19 +453,19 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "yA<C-R>0<Tab>xyz<Esc>",
silent = 0
rhs = 'yA<C-R>0<Tab>xyz<Esc>',
silent = 0,
},
v = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "yA<C-R>0<Tab>xyz<Esc>",
silent = 0
}
rhs = 'yA<C-R>0<Tab>xyz<Esc>',
silent = 0,
},
},
name = "Test3",
hidden = 0
name = 'Test3',
hidden = 0,
},
{
priority = 500,
@ -474,12 +474,12 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "<C-R>*",
silent = 0
}
rhs = '<C-R>*',
silent = 0,
},
},
name = "Test4",
hidden = 0
name = 'Test4',
hidden = 0,
},
{
priority = 500,
@ -488,12 +488,12 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "<C-R>+",
silent = 0
}
rhs = '<C-R>+',
silent = 0,
},
},
name = "Test5",
hidden = 0
name = 'Test5',
hidden = 0,
},
{
priority = 500,
@ -502,12 +502,12 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "",
silent = 0
}
rhs = '',
silent = 0,
},
},
name = "Test6",
hidden = 0
name = 'Test6',
hidden = 0,
},
{
priority = 500,
@ -516,12 +516,12 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "",
silent = 0
}
rhs = '',
silent = 0,
},
},
name = "Test7",
hidden = 0
name = 'Test7',
hidden = 0,
},
{
priority = 500,
@ -530,12 +530,12 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "",
silent = 0
}
rhs = '',
silent = 0,
},
},
name = "Test8",
hidden = 0
name = 'Test8',
hidden = 0,
},
{
priority = 500,
@ -544,17 +544,17 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "\"\"",
silent = 0
}
rhs = '""',
silent = 0,
},
},
name = "Test9",
hidden = 0
}
name = 'Test9',
hidden = 0,
},
},
priority = 500,
name = "Test"
}
name = 'Test',
},
}
eq(m, expected)
@ -565,12 +565,12 @@ describe('menu_get', function()
command('nnoremenu &Test\\ 1.Test\\ 2 Wargl')
command('nnoremenu &Test4.Test<Tab>3 i space<Esc>')
local m = funcs.menu_get("");
local m = funcs.menu_get('')
local expected = {
{
shortcut = "T",
shortcut = 'T',
hidden = 0,
actext = "Y",
actext = 'Y',
submenus = {
{
mappings = {
@ -578,21 +578,21 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "inormal<Alt-j>",
silent = 0
}
rhs = 'inormal<Alt-j>',
silent = 0,
},
},
hidden = 0,
actext = "X x",
actext = 'X x',
priority = 500,
name = "Test"
}
name = 'Test',
},
},
priority = 500,
name = "Test"
name = 'Test',
},
{
shortcut = "T",
shortcut = 'T',
hidden = 0,
submenus = {
{
@ -602,19 +602,19 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "Wargl",
silent = 0
}
rhs = 'Wargl',
silent = 0,
},
},
name = "Test 2",
hidden = 0
}
name = 'Test 2',
hidden = 0,
},
},
priority = 500,
name = "Test 1"
name = 'Test 1',
},
{
shortcut = "T",
shortcut = 'T',
hidden = 0,
submenus = {
{
@ -623,19 +623,19 @@ describe('menu_get', function()
sid = 1,
noremap = 1,
enabled = 1,
rhs = "i space<Esc>",
silent = 0
}
rhs = 'i space<Esc>',
silent = 0,
},
},
hidden = 0,
actext = "3",
actext = '3',
priority = 500,
name = "Test"
}
name = 'Test',
},
},
priority = 500,
name = "Test4"
}
name = 'Test4',
},
}
eq(m, expected)

View File

@ -18,7 +18,9 @@ local mkdir = helpers.mkdir
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()
local session_file = file_prefix .. '.vim'

View File

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

View File

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

View File

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

View File

@ -1,13 +1,13 @@
require('os')
local luv = require('luv')
local helpers = require('test.functional.helpers')(after_each)
local eval = helpers.eval
local command = helpers.command
local eq, neq = helpers.eq, helpers.neq
local helpers = require('test.functional.helpers')(after_each)
local eval = helpers.eval
local command = helpers.command
local eq, neq = helpers.eq, helpers.neq
local tempfile = helpers.tmpname()
local source = helpers.source
local matches = helpers.matches
local source = helpers.source
local matches = helpers.matches
local read_file = helpers.read_file
-- 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)
for _, c in ipairs({'l', 'c'}) do
for _, c in ipairs({ 'l', 'c' }) do
local file = ('%s.%s'):format(file_base, c)
local filecmd = c .. 'file'
local getfcmd = c .. 'getfile'
local addfcmd = c .. 'addfile'
local getlist = (c == 'c') and funcs.getqflist or (
function() return funcs.getloclist(0) end)
local getlist = (c == 'c') and funcs.getqflist or function()
return funcs.getloclist(0)
end
describe((':%s*file commands'):format(c), function()
before_each(function()
write_file(file, ([[
write_file(
file,
([[
%s-1.res:700:10:Line 700
%s-2.res:800:15:Line 800
]]):format(file, file))
]]):format(file, file)
)
end)
after_each(function()
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
-- results. First line (i.e. `{lnum=…`) was obtained from legacy test.
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=800, end_lnum=0, col=15, end_col=0, text='Line 800', module='',
nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''},
{
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 = 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(('%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
command('set nohidden')
command('enew!')
curbufmeths.set_lines(1, 1, true, {'Quickfix'})
eq(('Vim(%s):E37: No write since last change (add ! to override)'):format(
filecmd),
exc_exec(('%s %s'):format(filecmd, file)))
curbufmeths.set_lines(1, 1, true, { 'Quickfix' })
eq(
('Vim(%s):E37: No write since last change (add ! to override)'):format(filecmd),
exc_exec(('%s %s'):format(filecmd, file))
)
write_file(file, ([[
write_file(
file,
([[
%s-3.res:900:30:Line 900
]]):format(file))
]]):format(file)
)
command(('%s %s'):format(addfcmd, file))
list[#list + 1] = {
lnum=900, end_lnum=0, col=30, end_col=0, text='Line 900', module='',
nr=-1, bufnr=5, valid=1, pattern='', vcol=0, ['type']='',
lnum = 900,
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(('%s-3.res'):format(file), funcs.bufname(list[3].bufnr))
write_file(file, ([[
write_file(
file,
([[
%s-1.res:222:77:Line 222
%s-2.res:333:88:Line 333
]]):format(file, file))
]]):format(file, file)
)
command('enew!')
command(('%s %s'):format(getfcmd, file))
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=333, end_lnum=0, col=88, end_col=0, text='Line 333', module='',
nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''},
{
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 = 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(('%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'])
silent ll
]])
eq({0, 6, 1, 0, 1}, funcs.getcurpos())
eq({ 0, 6, 1, 0, 1 }, funcs.getcurpos())
end)
it('BufAdd does not cause E16 when reusing quickfix buffer #18135', function()
@ -127,11 +196,14 @@ describe('quickfix', function()
end)
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)
screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
[1] = {reverse = true}, -- IncSearch
[0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
[1] = { reverse = true }, -- IncSearch
})
screen:attach()
feed('i→<Esc>:vimgrep →')

View File

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

View File

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

View File

@ -9,21 +9,21 @@ describe('sign', function()
-- place a sign with id 34 to first buffer
nvim('command', 'sign define Foo text=+ texthl=Delimiter linehl=Comment numhl=Number')
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
nvim('command', 'new')
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
nvim('command', 'sign unplace 34')
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=' .. buf1, true))
eq('--- Signs ---\n', nvim('exec', 'sign place buffer=' .. buf2, true))
end)
end)
end)
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')
assert_alive()
end)

View File

@ -52,13 +52,16 @@ describe(':source', function()
meths.set_option_value('shellslash', false, {})
mkdir('Xshellslash')
write_file([[Xshellslash/Xstack.vim]], [[
write_file(
[[Xshellslash/Xstack.vim]],
[[
let g:stack1 = expand('<stack>')
set shellslash
let g:stack2 = expand('<stack>')
set noshellslash
let g:stack3 = expand('<stack>')
]])
]]
)
for _ = 1, 2 do
command([[source Xshellslash/Xstack.vim]])
@ -67,13 +70,16 @@ describe(':source', function()
matches([[Xshellslash\Xstack%.vim]], meths.get_var('stack3'))
end
write_file([[Xshellslash/Xstack.lua]], [[
write_file(
[[Xshellslash/Xstack.lua]],
[[
vim.g.stack1 = vim.fn.expand('<stack>')
vim.o.shellslash = true
vim.g.stack2 = vim.fn.expand('<stack>')
vim.o.shellslash = false
vim.g.stack3 = vim.fn.expand('<stack>')
]])
]]
)
for _ = 1, 2 do
command([[source Xshellslash/Xstack.lua]])
@ -101,11 +107,11 @@ describe(':source', function()
eq("{'k': 'v'}", exec_capture('echo b'))
-- Script items are created only on script var access
eq("1", exec_capture('echo c'))
eq("0zBEEFCAFE", exec_capture('echo d'))
eq('1', exec_capture('echo c'))
eq('0zBEEFCAFE', exec_capture('echo d'))
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)
it('selection in current buffer', function()
@ -132,14 +138,14 @@ describe(':source', function()
feed_command(':source')
eq('4', exec_capture('echo a'))
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
feed_command(':$source')
eq('Vim(echo):E117: Unknown function: s:C', exc_exec('echo D()'))
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)
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()
local test_file = 'test.lua'
write_file(test_file, [[
write_file(
test_file,
[[
vim.g.sourced_lua = 1
vim.g.sfile_value = vim.fn.expand('<sfile>')
vim.g.stack_value = vim.fn.expand('<stack>')
vim.g.script_value = vim.fn.expand('<script>')
]])
]]
)
command('set shellslash')
command('source ' .. test_file)
@ -245,22 +254,22 @@ describe(':source', function()
local test_file = 'test.lua'
-- 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)
neq(nil, result:find("E484"))
neq(nil, result:find('E484'))
-- Doesn't throw for parsing error
write_file (test_file, "vim.g.c = ")
ok, result = pcall(exec_capture, ":source "..test_file)
write_file(test_file, 'vim.g.c = ')
ok, result = pcall(exec_capture, ':source ' .. test_file)
eq(false, ok)
eq(nil, result:find("E484"))
eq(nil, result:find('E484'))
os.remove(test_file)
-- Doesn't throw for runtime error
write_file (test_file, "error('Cause error anyway :D')")
ok, result = pcall(exec_capture, ":source "..test_file)
write_file(test_file, "error('Cause error anyway :D')")
ok, result = pcall(exec_capture, ':source ' .. test_file)
eq(false, ok)
eq(nil, result:find("E484"))
eq(nil, result:find('E484'))
os.remove(test_file)
end)
end)

View File

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

View File

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

View File

@ -22,7 +22,7 @@ describe(':trust', function()
before_each(function()
helpers.write_file('test_file', 'test')
clear{env={XDG_STATE_HOME=xstate}}
clear { env = { XDG_STATE_HOME = xstate } }
end)
after_each(function()
@ -72,7 +72,10 @@ describe(':trust', function()
local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. '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')
eq(string.format(''), vim.trim(trust))
end)

View File

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

View File

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

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