local t = require('test.testutil') local n = require('test.functional.testnvim')() local t_lsp = require('test.functional.plugin.lsp.testutil') local Screen = require('test.functional.ui.screen') local dedent = t.dedent local eq = t.eq local api = n.api local exec_lua = n.exec_lua local insert = n.insert local feed = n.feed local clear_notrace = t_lsp.clear_notrace local create_server_definition = t_lsp.create_server_definition describe('vim.lsp.inline_completion', function() local text = dedent([[ function fibonacci() ]]) local grid_without_candidates = dedent([[ function fibonacci() | ^ | {1:~ }|*11 | ]]) local grid_with_candidates = dedent([[ function fibonacci({1:n) {} | {1: if (n <= 0) return 0;} | {1: if (n === 1) return 1;} | | {1: let a = 0, b = 1, c;} | {1: for (let i = 2; i <= n; i++) {} | {1: c = a + b;} | {1: a = b;} | {1: b = c;} | {1: }} | {1: return b;} | {1:}} | ^ | {3:-- INSERT --} | ]]) local grid_applied_candidates = dedent([[ function fibonacci(n) { | if (n <= 0) return 0; | if (n === 1) return 1; | | let a = 0, b = 1, c; | for (let i = 2; i <= n; i++) { | c = a + b; | a = b; | b = c; | } | return b; | ^} | |*2 ]]) --- @type test.functional.ui.screen local screen --- @type integer local client_id before_each(function() clear_notrace() exec_lua(create_server_definition) screen = Screen.new() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { bold = true, foreground = Screen.colors.SeaGreen4 }, [3] = { bold = true }, }) client_id = exec_lua(function() _G.server = _G._create_server({ capabilities = { inlineCompletionProvider = true, }, handlers = { ['textDocument/inlineCompletion'] = function(_, _, callback) callback(nil, { items = { { command = { command = 'dummy', title = 'Completion Accepted', }, insertText = 'function fibonacci(n) {\n if (n <= 0) return 0;\n if (n === 1) return 1;\n\n let a = 0, b = 1, c;\n for (let i = 2; i <= n; i++) {\n c = a + b;\n a = b;\n b = c;\n }\n return b;\n}', range = { ['end'] = { character = 20, line = 0, }, start = { character = 0, line = 0, }, }, }, { command = { command = 'dummy', title = 'Completion Accepted', }, insertText = 'function fibonacci(n) {\n if (n <= 0) return 0;\n if (n === 1) return 1;\n\n let a = 0, b = 1, c;\n for (let i = 2; i <= n; i++) {\n c = a + b;\n a = b;\n b = c;\n }\n return c;\n}', range = { ['end'] = { character = 20, line = 0, }, start = { character = 0, line = 0, }, }, }, { command = { command = 'dummy', title = 'Completion Accepted', }, insertText = 'function fibonacci(n) {\n if (n < 0) {\n throw new Error("Input must be a non-negative integer.");\n }\n if (n === 0) return 0;\n if (n === 1) return 1;\n\n let a = 0, b = 1, c;\n for (let i = 2; i <= n; i++) {\n c = a + b;\n a = b;\n b = c;\n }\n return b;\n}', range = { ['end'] = { character = 20, line = 0, }, start = { character = 0, line = 0, }, }, }, }, }) end, }, }) return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) end) exec_lua(function() local client = assert(vim.lsp.get_client_by_id(client_id)) _G.called = false client.commands.dummy = function() _G.called = true end end) insert(text) feed('$') exec_lua(function() vim.lsp.inline_completion.enable() end) end) after_each(function() api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) end) describe('enable()', function() it('requests or abort when entered/left insert mode', function() screen:expect({ grid = grid_without_candidates }) feed('i') screen:expect({ grid = grid_with_candidates }) feed('') screen:expect({ grid = grid_without_candidates }) end) end) describe('get()', function() it('applies the current candidate', function() feed('i') screen:expect({ grid = grid_with_candidates }) exec_lua(function() vim.lsp.inline_completion.get() end) n.poke_eventloop() feed('') screen:expect({ grid = grid_applied_candidates }) end) it('accepts on_accept callback', function() feed('i') screen:expect({ grid = grid_with_candidates }) local result = exec_lua(function() ---@type vim.lsp.inline_completion.Item local result vim.lsp.inline_completion.get({ on_accept = function(item) result = item end, }) vim.wait(1000, function() return result ~= nil end) -- Wait for async callback. return result end) feed('') screen:expect({ grid = grid_without_candidates }) eq({ _index = 1, client_id = 1, command = { command = 'dummy', title = 'Completion Accepted', }, insert_text = dedent([[ function fibonacci(n) { if (n <= 0) return 0; if (n === 1) return 1; let a = 0, b = 1, c; for (let i = 2; i <= n; i++) { c = a + b; a = b; b = c; } return b; }]]), range = { end_ = { buf = 1, col = 20, row = 0, }, start = { buf = 1, col = 0, row = 0, }, }, }, result) end) end) describe('select()', function() it('selects the next candidate', function() feed('i') screen:expect({ grid = grid_with_candidates }) exec_lua(function() vim.lsp.inline_completion.select() end) screen:expect([[ function fibonacci({1:n) {} | {1: if (n <= 0) return 0;} | {1: if (n === 1) return 1;} | | {1: let a = 0, b = 1, c;} | {1: for (let i = 2; i <= n; i++) {} | {1: c = a + b;} | {1: a = b;} | {1: b = c;} | {1: }} | {1: return c;} | {1:}}{2: (2/3)} | ^ | {3:-- INSERT --} | ]]) exec_lua(function() vim.lsp.inline_completion.get() end) n.poke_eventloop() feed('') screen:expect([[ function fibonacci(n) { | if (n <= 0) return 0; | if (n === 1) return 1; | | let a = 0, b = 1, c; | for (let i = 2; i <= n; i++) { | c = a + b; | a = b; | b = c; | } | return c; | ^} | |*2 ]]) end) end) end)