aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/config/paths.lua.in1
-rw-r--r--test/functional/api/command_spec.lua2
-rw-r--r--test/functional/api/keymap_spec.lua12
-rw-r--r--test/functional/api/vim_spec.lua19
-rw-r--r--test/functional/api/window_spec.lua26
-rw-r--r--test/functional/core/startup_spec.lua53
-rw-r--r--test/functional/editor/meta_key_spec.lua15
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua33
-rw-r--r--test/functional/fixtures/middle/filen.lua1
-rw-r--r--test/functional/fixtures/pack/foo/opt/funky/filen.lua12
-rw-r--r--test/functional/lua/diagnostic_spec.lua51
-rw-r--r--test/functional/lua/json_spec.lua133
-rw-r--r--test/functional/lua/ui_spec.lua46
-rw-r--r--test/functional/plugin/lsp/codelens_spec.lua28
-rw-r--r--test/functional/plugin/lsp_spec.lua192
-rw-r--r--test/functional/ui/decorations_spec.lua508
-rw-r--r--test/functional/ui/float_spec.lua316
-rw-r--r--test/functional/ui/mouse_spec.lua124
18 files changed, 1385 insertions, 187 deletions
diff --git a/test/config/paths.lua.in b/test/config/paths.lua.in
index 7fe5d8ad80..e3979981ba 100644
--- a/test/config/paths.lua.in
+++ b/test/config/paths.lua.in
@@ -19,5 +19,6 @@ if module.test_luajit_prg == '' then
end
end
table.insert(module.include_paths, "${CMAKE_BINARY_DIR}/include")
+table.insert(module.include_paths, "${CMAKE_BINARY_DIR}/src/nvim/auto")
return module
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index 37331d11c7..6f929ad1ca 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -21,7 +21,7 @@ describe('nvim_get_commands', function()
it('validates input', function()
eq('builtin=true not implemented', pcall_err(meths.get_commands,
{builtin=true}))
- eq('unexpected key: foo', pcall_err(meths.get_commands,
+ eq("Invalid key: 'foo'", pcall_err(meths.get_commands,
{foo='blah'}))
end)
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index 4194945645..dd8eef7ca0 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -436,16 +436,16 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
end)
it('error on invalid optnames', function()
- eq('Invalid key: silentt',
+ eq("Invalid key: 'silentt'",
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {silentt = true}))
- eq('Invalid key: sidd',
+ eq("Invalid key: 'sidd'",
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {sidd = false}))
- eq('Invalid key: nowaiT',
+ eq("Invalid key: 'nowaiT'",
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {nowaiT = false}))
end)
it('error on <buffer> option key', function()
- eq('Invalid key: buffer',
+ eq("Invalid key: 'buffer'",
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {buffer = true}))
end)
@@ -454,8 +454,8 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
-- note: need '%' to escape hyphens, which have special meaning in lua
it('throws an error when given non-boolean value for '..opt, function()
local opts = {}
- opts[opt] = 2
- eq('Gave non-boolean value for an opt: '..opt,
+ opts[opt] = 'fooo'
+ eq(opt..' is not a boolean',
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', opts))
end)
end
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index ffef6a6066..6bcf8dd91f 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -12,10 +12,12 @@ local funcs = helpers.funcs
local iswin = helpers.iswin
local meths = helpers.meths
local matches = helpers.matches
+local mkdir_p = helpers.mkdir_p
local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed
local is_os = helpers.is_os
local parse_context = helpers.parse_context
local request = helpers.request
+local rmdir = helpers.rmdir
local source = helpers.source
local next_msg = helpers.next_msg
local tmpname = helpers.tmpname
@@ -1117,7 +1119,7 @@ describe('API', function()
describe('nvim_get_context', function()
it('validates args', function()
- eq('unexpected key: blah',
+ eq("Invalid key: 'blah'",
pcall_err(nvim, 'get_context', {blah={}}))
eq('invalid value for key: types',
pcall_err(nvim, 'get_context', {types=42}))
@@ -1574,6 +1576,18 @@ describe('API', function()
end)
describe('nvim_list_runtime_paths', function()
+ setup(function()
+ local pathsep = helpers.get_pathsep()
+ mkdir_p('Xtest'..pathsep..'a')
+ mkdir_p('Xtest'..pathsep..'b')
+ end)
+ teardown(function()
+ rmdir 'Xtest'
+ end)
+ before_each(function()
+ meths.set_current_dir 'Xtest'
+ end)
+
it('returns nothing with empty &runtimepath', function()
meths.set_option('runtimepath', '')
eq({}, meths.list_runtime_paths())
@@ -1601,8 +1615,7 @@ describe('API', function()
local long_path = ('/a'):rep(8192)
meths.set_option('runtimepath', long_path)
local paths_list = meths.list_runtime_paths()
- neq({long_path}, paths_list)
- eq({long_path:sub(1, #(paths_list[1]))}, paths_list)
+ eq({}, paths_list)
end)
end)
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index c49d6405f4..11755a9d97 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -1,8 +1,9 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq,
- ok, feed, insert, eval = helpers.clear, helpers.nvim, helpers.curbuf,
+ ok, feed, insert, eval, tabpage = helpers.clear, helpers.nvim, helpers.curbuf,
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
- helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval
+ helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval,
+ helpers.tabpage
local poke_eventloop = helpers.poke_eventloop
local curwinmeths = helpers.curwinmeths
local funcs = helpers.funcs
@@ -11,6 +12,7 @@ local NIL = helpers.NIL
local meths = helpers.meths
local command = helpers.command
local pcall_err = helpers.pcall_err
+local assert_alive = helpers.assert_alive
-- check if str is visible at the beginning of some line
local function is_visible(str)
@@ -206,7 +208,7 @@ describe('API/win', function()
end)
end)
- describe('{get,set}_option', function()
+ describe('nvim_win_get_option, nvim_win_set_option', function()
it('works', function()
curwin('set_option', 'colorcolumn', '4,3')
eq('4,3', curwin('get_option', 'colorcolumn'))
@@ -224,6 +226,18 @@ describe('API/win', function()
pcall_err(curwin, 'get_option', 'statusline'))
eq('', eval('&l:statusline')) -- confirm local value was not copied
end)
+
+ it('after switching windows #15390', function()
+ nvim('command', 'tabnew')
+ local tab1 = unpack(nvim('list_tabpages'))
+ local win1 = unpack(tabpage('list_wins', tab1))
+ window('set_option', win1, 'statusline', 'window-status')
+ nvim('command', 'split')
+ nvim('command', 'wincmd J')
+ nvim('command', 'wincmd j')
+ eq('window-status', window('get_option', win1, 'statusline'))
+ assert_alive()
+ end)
end)
describe('get_position', function()
@@ -354,13 +368,13 @@ describe('API/win', function()
local win = meths.open_win(0, true, {
relative='editor', row=10, col=10, width=50, height=10
})
- local tabpage = eval('tabpagenr()')
+ local tab = eval('tabpagenr()')
command('tabprevious')
eq(1, eval('tabpagenr()'))
meths.win_close(win, false)
- eq(1001, meths.tabpage_get_win(tabpage).id)
- helpers.assert_alive()
+ eq(1001, meths.tabpage_get_win(tab).id)
+ assert_alive()
end)
end)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index ff93f88a2d..bf2559f8d7 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -20,6 +20,7 @@ local retry = helpers.retry
local rmdir = helpers.rmdir
local sleep = helpers.sleep
local iswin = helpers.iswin
+local startswith = helpers.startswith
local write_file = helpers.write_file
local meths = helpers.meths
@@ -310,7 +311,8 @@ describe('startup', function()
end)
local function pack_clear(cmd)
- clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}}
+ -- add packages after config dir in rtp but before config/after
+ clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', 'let paths=split(&rtp, ",")', '--cmd', 'let &rtp = paths[0]..",test/functional/fixtures,test/functional/fixtures/middle,"..join(paths[1:],",")', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}}
end
@@ -351,12 +353,57 @@ describe('startup', function()
it("handles the correct order with start packages and after/", function()
pack_clear [[ lua _G.test_loadorder = {} vim.cmd "runtime! filen.lua" ]]
- eq({'ordinary', 'FANCY', 'ordinary after', 'FANCY after'}, exec_lua [[ return _G.test_loadorder ]])
+ eq({'ordinary', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with start packages and after/ after startup", function()
+ pack_clear [[ lua _G.test_loadorder = {} ]]
+ command [[ runtime! filen.lua ]]
+ eq({'ordinary', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with globpath(&rtp, ...)", function()
+ pack_clear [[ set loadplugins | lua _G.test_loadorder = {} ]]
+ command [[
+ for x in globpath(&rtp, "filen.lua",1,1)
+ call v:lua.dofile(x)
+ endfor
+ ]]
+ eq({'ordinary', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+
+ local rtp = meths.get_option'rtp'
+ ok(startswith(rtp, 'test/functional/fixtures/nvim,test/functional/fixtures/pack/*/start/*,test/functional/fixtures/start/*,test/functional/fixtures,test/functional/fixtures/middle,'), 'rtp='..rtp)
end)
it("handles the correct order with opt packages and after/", function()
pack_clear [[ lua _G.test_loadorder = {} vim.cmd "packadd! superspecial\nruntime! filen.lua" ]]
- eq({'ordinary', 'SuperSpecial', 'FANCY', 'SuperSpecial after', 'ordinary after', 'FANCY after'}, exec_lua [[ return _G.test_loadorder ]])
+ eq({'ordinary', 'SuperSpecial', 'FANCY', 'mittel', 'FANCY after', 'SuperSpecial after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with opt packages and after/ after startup", function()
+ pack_clear [[ lua _G.test_loadorder = {} ]]
+ command [[
+ packadd! superspecial
+ runtime! filen.lua
+ ]]
+ eq({'ordinary', 'SuperSpecial', 'FANCY', 'mittel', 'FANCY after', 'SuperSpecial after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with opt packages and globpath(&rtp, ...)", function()
+ pack_clear [[ set loadplugins | lua _G.test_loadorder = {} ]]
+ command [[
+ packadd! superspecial
+ for x in globpath(&rtp, "filen.lua",1,1)
+ call v:lua.dofile(x)
+ endfor
+ ]]
+ eq({'ordinary', 'SuperSpecial', 'FANCY', 'mittel', 'SuperSpecial after', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with a package that changes packpath", function()
+ pack_clear [[ lua _G.test_loadorder = {} vim.cmd "packadd! funky\nruntime! filen.lua" ]]
+ eq({'ordinary', 'funky!', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ eq({'ordinary', 'funky!', 'mittel', 'ordinary after'}, exec_lua [[ return _G.nested_order ]])
end)
end)
diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua
index 2a9541ba96..c219204409 100644
--- a/test/functional/editor/meta_key_spec.lua
+++ b/test/functional/editor/meta_key_spec.lua
@@ -11,15 +11,20 @@ describe('meta-keys #8226 #13042', function()
end)
it('ALT/META, normal-mode', function()
- -- Unmapped ALT-chords behave as ESC+c
+ -- Unmapped ALT-chord behaves as ESC+c.
insert('hello')
feed('0<A-x><M-x>')
expect('llo')
+ -- Unmapped ALT-chord resolves isolated (non-ALT) ESC mapping. #13086 #15869
+ command('nnoremap <ESC> A<lt>ESC><Esc>')
+ command('nnoremap ; A;<Esc>')
+ feed('<A-;><M-;>')
+ expect('llo<ESC>;<ESC>;')
-- Mapped ALT-chord behaves as mapped.
command('nnoremap <M-l> Ameta-l<Esc>')
command('nnoremap <A-j> Aalt-j<Esc>')
feed('<A-j><M-l>')
- expect('lloalt-jmeta-l')
+ expect('llo<ESC>;<ESC>;alt-jmeta-l')
end)
it('ALT/META, visual-mode', function()
@@ -27,11 +32,15 @@ describe('meta-keys #8226 #13042', function()
insert('peaches')
feed('viw<A-x>viw<M-x>')
expect('peach')
+ -- Unmapped ALT-chord resolves isolated (non-ALT) ESC mapping. #13086 #15869
+ command('vnoremap <ESC> A<lt>ESC>')
+ feed('viw<A-;><ESC>viw<M-;><ESC>')
+ expect('peach<ESC>;<ESC>;')
-- Mapped ALT-chord behaves as mapped.
command('vnoremap <M-l> Ameta-l<Esc>')
command('vnoremap <A-j> Aalt-j<Esc>')
feed('viw<A-j>viw<M-l>')
- expect('peachalt-jmeta-l')
+ expect('peach<ESC>;<ESC>;alt-jmeta-l')
end)
it('ALT/META insert-mode', function()
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index 9579525502..8e03d9a46e 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -43,11 +43,11 @@ end
local function read_message()
local line = io.read("*l")
local length = line:lower():match("content%-length:%s*(%d+)")
- return vim.fn.json_decode(io.read(2 + length):sub(2))
+ return vim.json.decode(io.read(2 + length):sub(2))
end
local function send(payload)
- io.stdout:write(format_message_with_content_length(vim.fn.json_encode(payload)))
+ io.stdout:write(format_message_with_content_length(vim.json.encode(payload)))
end
local function respond(id, err, result)
@@ -564,6 +564,35 @@ function tests.decode_nil()
}
end
+
+function tests.code_action_with_resolve()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ codeActionProvider = {
+ resolveProvider = true
+ }
+ }
+ }
+ end;
+ body = function()
+ notify('start')
+ local cmd = {
+ title = 'Command 1',
+ command = 'dummy1'
+ }
+ expect_request('textDocument/codeAction', function()
+ return nil, { cmd, }
+ end)
+ expect_request('codeAction/resolve', function()
+ return nil, cmd
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
-- Tests will be indexed by TEST_NAME
local kill_timer = vim.loop.new_timer()
diff --git a/test/functional/fixtures/middle/filen.lua b/test/functional/fixtures/middle/filen.lua
new file mode 100644
index 0000000000..fce50cc776
--- /dev/null
+++ b/test/functional/fixtures/middle/filen.lua
@@ -0,0 +1 @@
+table.insert(_G.test_loadorder, "mittel")
diff --git a/test/functional/fixtures/pack/foo/opt/funky/filen.lua b/test/functional/fixtures/pack/foo/opt/funky/filen.lua
new file mode 100644
index 0000000000..a33b83c2a7
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/opt/funky/filen.lua
@@ -0,0 +1,12 @@
+table.insert(_G.test_loadorder, "funky!")
+
+if not _G.nesty then
+ _G.nesty = true
+ local save_order = _G.test_loadorder
+ _G.test_loadorder = {}
+ _G.vim.o.pp = "" -- funky!
+ vim.cmd [[runtime! filen.lua ]]
+ _G.nested_order = _G.test_loadorder
+ _G.test_loadorder = save_order
+ _G.nesty = nil
+end
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index 9397af9d9f..45aa4915cd 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -874,6 +874,26 @@ describe('vim.diagnostic', function()
return count_extmarks(diagnostic_bufnr, diagnostic_ns)
]])
end)
+
+ it('sets signs', function()
+ local result = exec_lua [[
+ vim.diagnostic.config({
+ signs = true,
+ })
+
+ local diagnostics = {
+ make_error('Error', 1, 1, 1, 2),
+ make_warning('Warning', 3, 3, 3, 3),
+ }
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+
+ return vim.fn.sign_getplaced(diagnostic_bufnr, {group = '*'})[1].signs
+ ]]
+
+ eq({2, 'DiagnosticSignError'}, {result[1].lnum, result[1].name})
+ eq({4, 'DiagnosticSignWarn'}, {result[2].lnum, result[2].name})
+ end)
end)
describe('show_line_diagnostics()', function()
@@ -995,37 +1015,6 @@ describe('vim.diagnostic', function()
end)
end)
- describe('set_signs()', function()
- -- TODO(tjdevries): Find out why signs are not displayed when set from Lua...??
- pending('sets signs by default', function()
- exec_lua [[
- vim.diagnostic.config({
- update_in_insert = true,
- signs = true,
- })
-
- local diagnostics = {
- make_error('Delayed Diagnostic', 1, 1, 1, 2),
- make_error('Delayed Diagnostic', 3, 3, 3, 3),
- }
-
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
-
- vim.diagnostic._set_signs(diagnostic_ns, diagnostic_bufnr, diagnostics)
- -- return vim.fn.sign_getplaced()
- ]]
-
- nvim("input", "o")
- nvim("input", "<esc>")
-
- -- TODO(tjdevries): Find a way to get the signs to display in the test...
- eq(nil, exec_lua [[
- return im.fn.sign_getplaced()[1].signs
- ]])
- end)
- end)
-
describe('setloclist()', function()
it('sets diagnostics in lnum order', function()
local loc_list = exec_lua [[
diff --git a/test/functional/lua/json_spec.lua b/test/functional/lua/json_spec.lua
new file mode 100644
index 0000000000..fbb21bfd57
--- /dev/null
+++ b/test/functional/lua/json_spec.lua
@@ -0,0 +1,133 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local NIL = helpers.NIL
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+
+describe('vim.json.decode function', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('parses null, true, false', function()
+ eq(NIL, exec_lua([[return vim.json.decode('null')]]))
+ eq(true, exec_lua([[return vim.json.decode('true')]]))
+ eq(false, exec_lua([[return vim.json.decode('false')]]))
+ end)
+
+ it('parses integer numbers', function()
+ eq(100000, exec_lua([[return vim.json.decode('100000')]]))
+ eq(-100000, exec_lua([[return vim.json.decode('-100000')]]))
+ eq(100000, exec_lua([[return vim.json.decode(' 100000 ')]]))
+ eq(-100000, exec_lua([[return vim.json.decode(' -100000 ')]]))
+ eq(0, exec_lua([[return vim.json.decode('0')]]))
+ eq(0, exec_lua([[return vim.json.decode('-0')]]))
+ end)
+
+ it('parses floating-point numbers', function()
+ -- This behavior differs from vim.fn.json_decode, which return '100000.0'
+ eq('100000', exec_lua([[return tostring(vim.json.decode('100000.0'))]]))
+ eq(100000.5, exec_lua([[return vim.json.decode('100000.5')]]))
+ eq(-100000.5, exec_lua([[return vim.json.decode('-100000.5')]]))
+ eq(-100000.5e50, exec_lua([[return vim.json.decode('-100000.5e50')]]))
+ eq(100000.5e50, exec_lua([[return vim.json.decode('100000.5e50')]]))
+ eq(100000.5e50, exec_lua([[return vim.json.decode('100000.5e+50')]]))
+ eq(-100000.5e-50, exec_lua([[return vim.json.decode('-100000.5e-50')]]))
+ eq(100000.5e-50, exec_lua([[return vim.json.decode('100000.5e-50')]]))
+ eq(100000e-50, exec_lua([[return vim.json.decode('100000e-50')]]))
+ eq(0.5, exec_lua([[return vim.json.decode('0.5')]]))
+ eq(0.005, exec_lua([[return vim.json.decode('0.005')]]))
+ eq(0.005, exec_lua([[return vim.json.decode('0.00500')]]))
+ eq(0.5, exec_lua([[return vim.json.decode('0.00500e+002')]]))
+ eq(0.00005, exec_lua([[return vim.json.decode('0.00500e-002')]]))
+
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0e0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0e+0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0e-0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0e-0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0e-2')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0e+2')]]))
+
+ eq(0.0, exec_lua([[return vim.json.decode('0.0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0.0e0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0.0e+0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0.0e-0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0e-0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0e-2')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0e+2')]]))
+ end)
+
+ it('parses containers', function()
+ eq({1}, exec_lua([[return vim.json.decode('[1]')]]))
+ eq({NIL, 1}, exec_lua([[return vim.json.decode('[null, 1]')]]))
+ eq({['1']=2}, exec_lua([[return vim.json.decode('{"1": 2}')]]))
+ eq({['1']=2, ['3']={{['4']={['5']={{}, 1}}}}},
+ exec_lua([[return vim.json.decode('{"1": 2, "3": [{"4": {"5": [ [], 1]}}]}')]]))
+ end)
+
+ it('parses strings properly', function()
+ eq('\n', exec_lua([=[return vim.json.decode([["\n"]])]=]))
+ eq('', exec_lua([=[return vim.json.decode([[""]])]=]))
+ eq('\\/"\t\b\n\r\f', exec_lua([=[return vim.json.decode([["\\\/\"\t\b\n\r\f"]])]=]))
+ eq('/a', exec_lua([=[return vim.json.decode([["\/a"]])]=]))
+ -- Unicode characters: 2-byte, 3-byte
+ eq('«',exec_lua([=[return vim.json.decode([["«"]])]=]))
+ eq('ફ',exec_lua([=[return vim.json.decode([["ફ"]])]=]))
+ end)
+
+ it('parses surrogate pairs properly', function()
+ eq('\240\144\128\128', exec_lua([[return vim.json.decode('"\\uD800\\uDC00"')]]))
+ end)
+
+ it('accepts all spaces in every position where space may be put', function()
+ local s = ' \t\n\r \t\r\n \n\t\r \n\r\t \r\t\n \r\n\t\t \n\r\t \r\n\t\n \r\t\n\r \t\r \n\t\r\n \n \t\r\n \r\t\n\t \r\n\t\r \n\r \t\n\r\t \r \t\n\r \n\t\r\t \n\r\t\n \r\n \t\r\n\t'
+ local str = ('%s{%s"key"%s:%s[%s"val"%s,%s"val2"%s]%s,%s"key2"%s:%s1%s}%s'):gsub('%%s', s)
+ eq({key={'val', 'val2'}, key2=1}, exec_lua([[return vim.json.decode(...)]], str))
+ end)
+
+end)
+
+describe('vim.json.encode function', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('dumps strings', function()
+ eq('"Test"', exec_lua([[return vim.json.encode('Test')]]))
+ eq('""', exec_lua([[return vim.json.encode('')]]))
+ eq('"\\t"', exec_lua([[return vim.json.encode('\t')]]))
+ eq('"\\n"', exec_lua([[return vim.json.encode('\n')]]))
+ -- vim.fn.json_encode return \\u001B
+ eq('"\\u001b"', exec_lua([[return vim.json.encode('\27')]]))
+ eq('"þÿþ"', exec_lua([[return vim.json.encode('þÿþ')]]))
+ end)
+
+ it('dumps numbers', function()
+ eq('0', exec_lua([[return vim.json.encode(0)]]))
+ eq('10', exec_lua([[return vim.json.encode(10)]]))
+ eq('-10', exec_lua([[return vim.json.encode(-10)]]))
+ end)
+
+ it('dumps floats', function()
+ eq('10.5', exec_lua([[return vim.json.encode(10.5)]]))
+ eq('-10.5', exec_lua([[return vim.json.encode(-10.5)]]))
+ eq('-1e-05', exec_lua([[return vim.json.encode(-1e-5)]]))
+ end)
+
+ it('dumps lists', function()
+ eq('[]', exec_lua([[return vim.json.encode({})]]))
+ eq('[[]]', exec_lua([[return vim.json.encode({{}})]]))
+ eq('[[],[]]', exec_lua([[return vim.json.encode({{}, {}})]]))
+ end)
+
+ it('dumps dictionaries', function()
+ eq('{}', exec_lua([[return vim.json.encode(vim.empty_dict())]]))
+ eq('{"d":[]}', exec_lua([[return vim.json.encode({d={}})]]))
+ end)
+
+ it('dumps vim.NIL', function()
+ eq('null', exec_lua([[return vim.json.encode(vim.NIL)]]))
+ end)
+
+end)
diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua
new file mode 100644
index 0000000000..94f1b5840b
--- /dev/null
+++ b/test/functional/lua/ui_spec.lua
@@ -0,0 +1,46 @@
+local helpers = require('test.functional.helpers')(after_each)
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local clear = helpers.clear
+
+describe('vim.ui', function()
+ before_each(function()
+ clear()
+ end)
+
+
+ describe('select', function()
+ it('can select an item', function()
+ local result = exec_lua[[
+ local items = {
+ { name = 'Item 1' },
+ { name = 'Item 2' },
+ }
+ local opts = {
+ format_item = function(entry)
+ return entry.name
+ end
+ }
+ local selected
+ local cb = function(item)
+ selected = item
+ end
+ -- inputlist would require input and block the test;
+ local choices
+ vim.fn.inputlist = function(x)
+ choices = x
+ return 1
+ end
+ vim.ui.select(items, opts, cb)
+ vim.wait(100, function() return selected ~= nil end)
+ return {selected, choices}
+ ]]
+ eq({ name = 'Item 1' }, result[1])
+ eq({
+ 'Select one of:',
+ '1: Item 1',
+ '2: Item 2',
+ }, result[2])
+ end)
+ end)
+end)
diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua
index e48a0ad260..c8b75e65fc 100644
--- a/test/functional/plugin/lsp/codelens_spec.lua
+++ b/test/functional/plugin/lsp/codelens_spec.lua
@@ -58,5 +58,33 @@ describe('vim.lsp.codelens', function()
]], bufnr)
eq({[1] = {'Lens1', 'LspCodeLens'}}, virtual_text_chunks)
+
+ end)
+ it('codelens uses client commands', function()
+ local fake_uri = "file:///fake/uri"
+ local cmd = exec_lua([[
+ fake_uri = ...
+ local bufnr = vim.uri_to_bufnr(fake_uri)
+ vim.fn.bufload(bufnr)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0, },
+ ['end'] = { line = 0, character = 8 }
+ },
+ command = { title = 'Lens1', command = 'Dummy' }
+ },
+ }
+ vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
+ local cmd_called = nil
+ vim.lsp.commands['Dummy'] = function(command)
+ cmd_called = command
+ end
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.lsp.codelens.run()
+ return cmd_called
+ ]], fake_uri)
+ eq({ command = 'Dummy', title = 'Lens1' }, cmd)
end)
end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 27f2d2536f..8f9b194690 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -132,37 +132,38 @@ local function test_rpc_server(config)
end
describe('LSP', function()
- describe('server_name specified', function()
- before_each(function()
- clear_notrace()
- -- Run an instance of nvim on the file which contains our "scripts".
- -- Pass TEST_NAME to pick the script.
- local test_name = "basic_init"
- exec_lua([=[
- lsp = require('vim.lsp')
- local test_name, fixture_filename, logfile = ...
- function test__start_client()
- return lsp.start_client {
- cmd_env = {
- NVIM_LOG_FILE = logfile;
- };
- cmd = {
- vim.v.progpath, '-Es', '-u', 'NONE', '--headless',
- "-c", string.format("lua TEST_NAME = %q", test_name),
- "-c", "luafile "..fixture_filename;
- };
- root_dir = vim.loop.cwd();
- }
- end
- TEST_CLIENT1 = test__start_client()
- ]=], test_name, fake_lsp_code, fake_lsp_logfile)
- end)
+ before_each(function()
+ clear_notrace()
- after_each(function()
- exec_lua("lsp._vim_exit_handler()")
- -- exec_lua("lsp.stop_all_clients(true)")
- end)
+ -- Run an instance of nvim on the file which contains our "scripts".
+ -- Pass TEST_NAME to pick the script.
+ local test_name = "basic_init"
+ exec_lua([=[
+ lsp = require('vim.lsp')
+ local test_name, fixture_filename, logfile = ...
+ function test__start_client()
+ return lsp.start_client {
+ cmd_env = {
+ NVIM_LOG_FILE = logfile;
+ };
+ cmd = {
+ vim.v.progpath, '-Es', '-u', 'NONE', '--headless',
+ "-c", string.format("lua TEST_NAME = %q", test_name),
+ "-c", "luafile "..fixture_filename;
+ };
+ root_dir = vim.loop.cwd();
+ }
+ end
+ TEST_CLIENT1 = test__start_client()
+ ]=], test_name, fake_lsp_code, fake_lsp_logfile)
+ end)
+ after_each(function()
+ exec_lua("lsp._vim_exit_handler()")
+ -- exec_lua("lsp.stop_all_clients(true)")
+ end)
+
+ describe('server_name specified', function()
it('start_client(), stop_client()', function()
retry(nil, 4000, function()
eq(1, exec_lua('return #lsp.get_active_clients()'))
@@ -334,7 +335,6 @@ describe('LSP', function()
}
end)
it('workspace/configuration returns NIL per section if client was started without config.settings', function()
- clear_notrace()
fake_lsp_server_setup('workspace/configuration no settings')
eq({ NIL, NIL, }, exec_lua [[
local result = {
@@ -2022,83 +2022,6 @@ describe('LSP', function()
end)
end)
- describe('lsp.util.make_floating_popup_options', function()
- before_each(function()
- exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local winheight = vim.fn.winheight(0)
- for i = 1, winheight do
- vim.api.nvim_buf_set_lines(bufnr, 0, 0, false, {''})
- end
- vim.api.nvim_win_set_buf(0, bufnr)
- vim.api.nvim_win_set_cursor(0, {winheight, 0})
- ]]
- end)
-
- local function popup_row(opts)
- return exec_lua([[
- return vim.lsp.util.make_floating_popup_options(...).row
- ]], 2, 2, opts)
- end
-
- local err_pattern = "^Error executing lua: %.%.%./util%.lua:0: invalid floating preview border: .*%. :help vim%.api%.nvim_open_win%(%)$"
-
- it('calculates default border height correctly', function()
- eq(0, popup_row())
- end)
-
- it('calculates string border height correctly', function()
- eq(0, popup_row({border = 'none'}))
- eq(-2, popup_row({border = 'single'}))
- eq(-2, popup_row({border = 'double'}))
- eq(-2, popup_row({border = 'rounded'}))
- eq(-2, popup_row({border = 'solid'}))
- eq(-1, popup_row({border = 'shadow'}))
- end)
-
- it('error on invalid string border', function()
- matches(err_pattern, pcall_err(popup_row, {border = ''}))
- matches(err_pattern, pcall_err(popup_row, {border = 'invalid'}))
- end)
-
- it('error on invalid array border length', function()
- matches(err_pattern, pcall_err(popup_row, {border = {}}))
- matches(err_pattern, pcall_err(popup_row, {border = {'', '', ''}}))
- matches(err_pattern, pcall_err(popup_row, {border = {'', '', '', '', ''}}))
- end)
-
- it('error on invalid array border member type', function()
- matches(err_pattern, pcall_err(popup_row, {border = {0}}))
- end)
-
- it('calculates 8-array border height correctly', function()
- eq(0, popup_row({border = {'', '', '', '', '', '', '', ''}}))
- eq(-2, popup_row({border = {'', '~', '', '~', '', '~', '', '~'}}))
- eq(-1, popup_row({border = {'', '', '', '~', '', '~', '', ''}}))
- eq(0, popup_row({border = {'', '', '', {'~', 'NormalFloat'}, '', '', '', {'~', 'NormalFloat'}}}))
- eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}, '', '', '', {'~', 'NormalFloat'}, '', ''}}))
- end)
-
- it('calculates 4-array border height correctly', function()
- eq(0, popup_row({border = {'', '', '', ''}}))
- eq(-2, popup_row({border = {'', '~', '', '~'}}))
- eq(0, popup_row({border = {'', '', '', {'~', 'NormalFloat'}}}))
- eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}, '', ''}}))
- end)
-
- it('calculates 2-array border height correctly', function()
- eq(0, popup_row({border = {'', ''}}))
- eq(-2, popup_row({border = {'', '~'}}))
- eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}}}))
- end)
-
- it('calculates 1-array border height correctly', function()
- eq(0, popup_row({border = {''}}))
- eq(-2, popup_row({border = {'~'}}))
- eq(-2, popup_row({border = {{'~', 'NormalFloat'}}}))
- end)
- end)
-
describe('lsp.util._make_floating_popup_size', function()
before_each(function()
exec_lua [[ contents =
@@ -2376,26 +2299,43 @@ describe('LSP', function()
describe('vim.lsp.buf.code_action', function()
it('Calls client side command if available', function()
- eq(1, exec_lua [[
- local dummy_calls = 0
- vim.lsp.commands.dummy = function()
- dummy_calls = dummy_calls + 1
- end
- local actions = {
- {
- title = 'Dummy command',
- command = 'dummy',
- },
- }
- -- inputlist would require input and block the test;
- vim.fn.inputlist = function()
- return 1
+ local client
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = 'code_action_with_resolve',
+ on_init = function(client_)
+ client = client_
+ end,
+ on_setup = function()
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end,
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx})
+ if ctx.method == 'start' then
+ exec_lua([[
+ vim.lsp.commands['dummy1'] = function(cmd)
+ vim.lsp.commands['dummy2'] = function()
+ end
+ end
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.fn.inputlist = function()
+ return 1
+ end
+ vim.lsp.buf.code_action()
+ ]])
+ elseif ctx.method == 'shutdown' then
+ eq('function', exec_lua[[return type(vim.lsp.commands['dummy2'])]])
+ client.stop()
+ end
end
- local params = {}
- local handler = require'vim.lsp.handlers'['textDocument/codeAction']
- handler(nil, actions, { method = 'textDocument/codeAction', params = params }, nil)
- return dummy_calls
- ]])
+ }
end)
end)
describe('vim.lsp.commands', function()
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 4373d17890..8074f91215 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -790,3 +790,511 @@ end]]
helpers.assert_alive()
end)
end)
+
+describe('decorations: virtual lines', function()
+ local screen, ns
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 12)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {bold=true, foreground=Screen.colors.Blue};
+ [2] = {foreground = Screen.colors.Cyan4};
+ [3] = {background = Screen.colors.Yellow1};
+ [4] = {bold = true};
+ [5] = {background = Screen.colors.Yellow, foreground = Screen.colors.Blue};
+ [6] = {foreground = Screen.colors.Blue};
+ [7] = {foreground = Screen.colors.SlateBlue};
+ [8] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue};
+ [9] = {foreground = Screen.colors.Brown};
+ }
+
+ ns = meths.create_namespace 'test'
+ end)
+
+ local example_text = [[
+if (h->n_buckets < new_n_buckets) { // expand
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t));
+ h->keys = new_keys;
+ if (kh_is_map && val_size) {
+ char *new_vals = krealloc( h->vals_buf, new_n_buckets * val_size);
+ h->vals_buf = new_vals;
+ }
+}]]
+
+ it('works with one line', function()
+ insert(example_text)
+ feed 'gg'
+ meths.buf_set_extmark(0, ns, 1, 33, {
+ virt_lines={ {{">> ", "NonText"}, {"krealloc", "Identifier"}, {": change the size of an allocation"}}};
+ virt_lines_above=true;
+ })
+
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+
+ feed '/krealloc<cr>'
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ khkey_t *new_keys = (khkey_t *){3:^krealloc}((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ /krealloc |
+ ]]}
+
+ -- virtual line remains anchored to the extmark
+ feed 'i<cr>'
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ {3:^krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ {4:-- INSERT --} |
+ ]]}
+
+ feed '<esc>3+'
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ ^char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 5, 0, {
+ virt_lines = { {{"^^ REVIEW:", "Todo"}, {" new_vals variable seems unneccesary?", "Comment"}} };
+ })
+ -- TODO: what about the cursor??
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buck^ets * val_size); |
+ {5:^^ REVIEW:}{6: new_vals variable seems unneccesary?} |
+ h->vals_buf = new_vals; |
+ } |
+ |
+ ]]}
+
+ meths.buf_clear_namespace(0, ns, 0, -1)
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buck^ets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+ end)
+
+
+ it('works with text at the beginning of the buffer', function()
+ insert(example_text)
+ feed 'gg'
+
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ {1:~ }|
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 0, 0, {
+ virt_lines={
+ {{"refactor(khash): ", "Special"}, {"take size of values as parameter"}};
+ {{"Author: Dev Devsson, "}, {"Tue Aug 31 10:13:37 2021", "Comment"}};
+ };
+ virt_lines_above=true;
+ right_gravity=false;
+ })
+
+ -- placing virt_text on topline does not automatically cause a scroll
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ {1:~ }|
+ |
+ ]], unchanged=true}
+
+ feed '<c-b>'
+ screen:expect{grid=[[
+ {7:refactor(khash): }take size of values as parameter |
+ Author: Dev Devsson, {6:Tue Aug 31 10:13:37 2021} |
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ |
+ ]]}
+ end)
+
+ it('works with text et the end of the buffer', function()
+ insert(example_text)
+ feed 'G'
+
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ {1:~ }|
+ |
+ ]]}
+
+ local id = meths.buf_set_extmark(0, ns, 7, 0, {
+ virt_lines={{{"Grugg"}}};
+ right_gravity=false;
+ })
+
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ Grugg |
+ |
+ ]]}
+
+ meths.buf_del_extmark(0, ns, id)
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with a block scrolling up', function()
+ screen:try_resize(30, 7)
+ insert("aa\nbb\ncc\ndd\nee\nff\ngg\nhh")
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 6, 0, {
+ virt_lines={
+ {{"they see me"}};
+ {{"scrolling", "Special"}};
+ {{"they"}};
+ {{"hatin'", "Special"}};
+ };
+ })
+
+ screen:expect{grid=[[
+ ^aa |
+ bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ they see me |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^dd |
+ ee |
+ ff |
+ gg |
+ they see me |
+ {7:scrolling} |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^ee |
+ ff |
+ gg |
+ they see me |
+ {7:scrolling} |
+ they |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^ff |
+ gg |
+ they see me |
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^gg |
+ they see me |
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ hh |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ they see me |
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ they |
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with sign and numbercolumns', function()
+ insert(example_text)
+ feed 'gg'
+ command 'set number signcolumn=yes'
+ screen:expect{grid=[[
+ {8: }{9: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
+ {8: }{9: }d |
+ {8: }{9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
+ {8: }{9: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
+ {8: }{9: }t)); |
+ {8: }{9: 3 } h->keys = new_keys; |
+ {8: }{9: 4 } if (kh_is_map && val_size) { |
+ {8: }{9: 5 } char *new_vals = krealloc( h->vals_buf, |
+ {8: }{9: }new_n_buckets * val_size); |
+ {8: }{9: 6 } h->vals_buf = new_vals; |
+ {8: }{9: 7 } } |
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 2, 0, {
+ virt_lines={
+ {{"Some special", "Special"}};
+ {{"remark about codes", "Comment"}};
+ };
+ })
+
+ screen:expect{grid=[[
+ {8: }{9: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
+ {8: }{9: }d |
+ {8: }{9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
+ {8: }{9: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
+ {8: }{9: }t)); |
+ {8: }{9: 3 } h->keys = new_keys; |
+ {8: }{9: }{7:Some special} |
+ {8: }{9: }{6:remark about codes} |
+ {8: }{9: 4 } if (kh_is_map && val_size) { |
+ {8: }{9: 5 } char *new_vals = krealloc( h->vals_buf, |
+ {8: }{9: }new_n_buckets * val_size); |
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 2, 0, {
+ virt_lines={
+ {{"Some special", "Special"}};
+ {{"remark about codes", "Comment"}};
+ };
+ virt_lines_leftcol=true;
+ })
+ screen:expect{grid=[[
+ {8: }{9: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
+ {8: }{9: }d |
+ {8: }{9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
+ {8: }{9: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
+ {8: }{9: }t)); |
+ {8: }{9: 3 } h->keys = new_keys; |
+ {7:Some special} |
+ {6:remark about codes} |
+ {8: }{9: 4 } if (kh_is_map && val_size) { |
+ {8: }{9: 5 } char *new_vals = krealloc( h->vals_buf, |
+ {8: }{9: }new_n_buckets * val_size); |
+ |
+ ]]}
+ end)
+
+
+ it('works with hard tabs', function()
+ insert(example_text)
+ feed 'gg'
+ meths.buf_set_extmark(0, ns, 1, 0, {
+ virt_lines={ {{">>", "NonText"}, {"\tvery\ttabby", "Identifier"}, {"text\twith\ttabs"}}};
+ })
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ {1:>>}{2: very tabby}text with tabs |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+
+ command 'set tabstop=4'
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ {1:>>}{2: very tabby}text with tabs |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+ end)
+
+end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index ccf5f963d1..e57c63bb0f 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -109,6 +109,21 @@ describe('float window', function()
assert_alive()
end)
+ it('closed immediately by autocmd after win_enter #15548', function()
+ eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately',
+ pcall_err(exec_lua, [[
+ vim.cmd "autocmd BufLeave * ++once quit!"
+ local buf = vim.api.nvim_create_buf(true, true)
+ vim.api.nvim_open_win(buf, true, {
+ relative = "win",
+ row = 0, col = 0,
+ width = 1, height = 1,
+ noautocmd = false,
+ })
+ ]]))
+ assert_alive()
+ end)
+
it('opened with correct height', function()
local height = exec_lua([[
vim.api.nvim_set_option("winheight", 20)
@@ -1514,7 +1529,7 @@ describe('float window', function()
it('API has proper error messages', function()
local buf = meths.create_buf(false,false)
- eq("Invalid key 'bork'",
+ eq("Invalid key: 'bork'",
pcall_err(meths.open_win,buf, false, {width=20,height=2,bork=true}))
eq("'win' key is only valid with relative='win'",
pcall_err(meths.open_win,buf, false, {width=20,height=2,relative='editor',row=0,col=0,win=0}))
@@ -1527,13 +1542,15 @@ describe('float window', function()
eq("'relative' requires 'row'/'col' or 'bufpos'",
pcall_err(meths.open_win,buf, false, {width=20,height=2,relative='editor'}))
eq("'width' key must be a positive Integer",
- pcall_err(meths.open_win,buf, false, {width=-1,height=2,relative='editor'}))
+ pcall_err(meths.open_win,buf, false, {width=-1,height=2,relative='editor', row=0, col=0}))
eq("'height' key must be a positive Integer",
- pcall_err(meths.open_win,buf, false, {width=20,height=-1,relative='editor'}))
+ pcall_err(meths.open_win,buf, false, {width=20,height=-1,relative='editor', row=0, col=0}))
eq("'height' key must be a positive Integer",
- pcall_err(meths.open_win,buf, false, {width=20,height=0,relative='editor'}))
- eq("Must specify 'width' and 'height'",
- pcall_err(meths.open_win,buf, false, {relative='editor'}))
+ pcall_err(meths.open_win,buf, false, {width=20,height=0,relative='editor', row=0, col=0}))
+ eq("Must specify 'width'",
+ pcall_err(meths.open_win,buf, false, {relative='editor', row=0, col=0}))
+ eq("Must specify 'height'",
+ pcall_err(meths.open_win,buf, false, {relative='editor', row=0, col=0, width=2}))
end)
it('can be placed relative window or cursor', function()
@@ -1866,6 +1883,293 @@ describe('float window', function()
end
end)
+ it('always anchor to corner including border', function()
+ screen:try_resize(40,13)
+ meths.buf_set_lines(0, 0, -1, true, {'just some example text', 'some more example text'})
+ feed('ggeee')
+ command('below split')
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ]])
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {5:[No Name] [+] }|
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+
+ local buf = meths.create_buf(false, false)
+ meths.buf_set_lines(buf, 0, -1, true, {' halloj! ',
+ ' BORDAA '})
+ local win = meths.open_win(buf, false, {relative='cursor', width=9, height=2, row=1, col=-2, border="double"})
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 6
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [6] = {{id = 1003}, "NW", 4, 1, 14, true}
+ }}
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {5:[No Name] [+] }|
+ just some exampl^e text |
+ some more exam{5:╔═════════╗} |
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+
+ meths.win_set_config(win, {relative='cursor', row=0, col=-2, anchor='NE'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 6
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [6] = {{id = 1003}, "NE", 4, 0, 14, true}
+ }}
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {5:[No Name] [+] }|
+ jus{5:╔═════════╗}pl^e text |
+ som{5:║}{1: halloj! }{5:║}ple text |
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+
+ meths.win_set_config(win, {relative='cursor', row=1, col=-2, anchor='SE'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 6
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [6] = {{id = 1003}, "SE", 4, 1, 14, true}
+ }}
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }{5:╔═════════╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {5:[No║}{1: BORDAA }{5:║ }|
+ jus{5:╚═════════╝}pl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+
+ meths.win_set_config(win, {relative='cursor', row=0, col=-2, anchor='SW'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 6
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [6] = {{id = 1003}, "SW", 4, 0, 14, true}
+ }}
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }{5:╔═════════╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {5:[No Name] [+] ╚═════════╝ }|
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+ end)
+
it('can be placed relative text in a window', function()
screen:try_resize(30,5)
local firstwin = meths.get_current_win().id
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 7bca741ae3..d3fe38ef52 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1384,4 +1384,128 @@ describe('ui/mouse/input', function()
end) -- level 3 - wrapped
end)
+
+ it('getmousepos works correctly', function()
+ local winwidth = meths.get_option('winwidth')
+ -- Set winwidth=1 so that window sizes don't change.
+ meths.set_option('winwidth', 1)
+ command('tabedit')
+ local tabpage = meths.get_current_tabpage()
+ insert('hello')
+ command('vsplit')
+ local opts = {
+ relative='editor',
+ width=12,
+ height=1,
+ col=8,
+ row=1,
+ anchor='NW',
+ style='minimal',
+ border='single',
+ focusable=1
+ }
+ local float = meths.open_win(meths.get_current_buf(), false, opts)
+ command('redraw')
+ local lines = meths.get_option('lines')
+ local columns = meths.get_option('columns')
+
+ -- Test that screenrow and screencol are set properly for all positions.
+ for row = 0, lines - 1 do
+ for col = 0, columns - 1 do
+ -- Skip the X button that would close the tab.
+ if row ~= 0 or col ~= columns - 1 then
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ meths.set_current_tabpage(tabpage)
+ local mousepos = funcs.getmousepos()
+ eq(row + 1, mousepos.screenrow)
+ eq(col + 1, mousepos.screencol)
+ -- All other values should be 0 when clicking on the command line.
+ if row == lines - 1 then
+ eq(0, mousepos.winid)
+ eq(0, mousepos.winrow)
+ eq(0, mousepos.wincol)
+ eq(0, mousepos.line)
+ eq(0, mousepos.column)
+ end
+ end
+ end
+ end
+
+ -- Test that mouse position values are properly set for the floating window
+ -- with a border. 1 is added to the height and width to account for the
+ -- border.
+ for win_row = 0, opts.height + 1 do
+ for win_col = 0, opts.width + 1 do
+ local row = win_row + opts.row
+ local col = win_col + opts.col
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ local mousepos = funcs.getmousepos()
+ eq(float.id, mousepos.winid)
+ eq(win_row + 1, mousepos.winrow)
+ eq(win_col + 1, mousepos.wincol)
+ local line = 0
+ local column = 0
+ if win_row > 0 and win_row < opts.height + 1
+ and win_col > 0 and win_col < opts.width + 1 then
+ -- Because of border, win_row and win_col don't need to be
+ -- incremented by 1.
+ line = math.min(win_row, funcs.line('$'))
+ column = math.min(win_col, #funcs.getline(line) + 1)
+ end
+ eq(line, mousepos.line)
+ eq(column, mousepos.column)
+ end
+ end
+
+ -- Test that mouse position values are properly set for the floating
+ -- window, after removing the border.
+ opts.border = 'none'
+ meths.win_set_config(float, opts)
+ command('redraw')
+ for win_row = 0, opts.height - 1 do
+ for win_col = 0, opts.width - 1 do
+ local row = win_row + opts.row
+ local col = win_col + opts.col
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ local mousepos = funcs.getmousepos()
+ eq(float.id, mousepos.winid)
+ eq(win_row + 1, mousepos.winrow)
+ eq(win_col + 1, mousepos.wincol)
+ local line = math.min(win_row + 1, funcs.line('$'))
+ local column = math.min(win_col + 1, #funcs.getline(line) + 1)
+ eq(line, mousepos.line)
+ eq(column, mousepos.column)
+ end
+ end
+
+ -- Test that mouse position values are properly set for ordinary windows.
+ -- Set the float to be unfocusable instead of closing, to additionally test
+ -- that getmousepos does not consider unfocusable floats. (see discussion
+ -- in PR #14937 for details).
+ opts.focusable = false
+ meths.win_set_config(float, opts)
+ command('redraw')
+ for nr = 1, 2 do
+ for win_row = 0, funcs.winheight(nr) - 1 do
+ for win_col = 0, funcs.winwidth(nr) - 1 do
+ local row = win_row + funcs.win_screenpos(nr)[1] - 1
+ local col = win_col + funcs.win_screenpos(nr)[2] - 1
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ local mousepos = funcs.getmousepos()
+ eq(funcs.win_getid(nr), mousepos.winid)
+ eq(win_row + 1, mousepos.winrow)
+ eq(win_col + 1, mousepos.wincol)
+ local line = math.min(win_row + 1, funcs.line('$'))
+ local column = math.min(win_col + 1, #funcs.getline(line) + 1)
+ eq(line, mousepos.line)
+ eq(column, mousepos.column)
+ end
+ end
+ end
+
+ -- Restore state and release mouse.
+ command('tabclose!')
+ meths.set_option('winwidth', winwidth)
+ meths.input_mouse('left', 'release', '', 0, 0, 0)
+ end)
end)