From 17cff16264f22cd88ff07750aad5046787dfb59b Mon Sep 17 00:00:00 2001 From: upstream Date: Sat, 3 Oct 2026 02:24:35 +0200 Subject: [PATCH] Upstream vscode-neovim/vscode-neovim state of the touched files before 28225f71a4 --- .../overrides/vscode-window-commands.vim | 158 +++++ .../integ/vscode-integration-specific.test.ts | 639 ++++++++++++++++++ 2 files changed, 797 insertions(+) create mode 100644 runtime/vscode/overrides/vscode-window-commands.vim create mode 100644 src/test/integ/vscode-integration-specific.test.ts diff --git a/runtime/vscode/overrides/vscode-window-commands.vim b/runtime/vscode/overrides/vscode-window-commands.vim new file mode 100644 index 0000000..824bd29 --- /dev/null +++ b/runtime/vscode/overrides/vscode-window-commands.vim @@ -0,0 +1,158 @@ + +function! s:split(...) abort + let direction = a:1 + let file = exists('a:2') ? a:2 : '' + call VSCodeCall(direction ==# 'h' ? 'workbench.action.splitEditorDown' : 'workbench.action.splitEditorRight') + if !empty(file) + call VSCodeExtensionNotify('open-file', expand(file), 'all') + endif +endfunction + +function! s:splitNew(...) + let file = a:2 + call s:split(a:1, empty(file) ? '__vscode_new__' : file) +endfunction + +function! s:closeOtherEditors() + call VSCodeNotify('workbench.action.closeEditorsInOtherGroups') + call VSCodeNotify('workbench.action.closeOtherEditors') +endfunction + +function! s:manageEditorHeight(...) + let count = a:1 + let to = a:2 + for i in range(1, count ? count : 1) + call VSCodeNotify(to ==# 'increase' ? 'workbench.action.increaseViewHeight' : 'workbench.action.decreaseViewHeight') + endfor +endfunction + +function! s:manageEditorWidth(...) + let count = a:1 + let to = a:2 + for i in range(1, count ? count : 1) + call VSCodeNotify(to ==# 'increase' ? 'workbench.action.increaseViewWidth' : 'workbench.action.decreaseViewWidth') + endfor +endfunction + +command! -complete=file -nargs=? Split call split('h', ) +command! -complete=file -nargs=? Vsplit call split('v', ) +command! -complete=file -nargs=? New call split('h', '__vscode_new__') +command! -complete=file -nargs=? Vnew call split('v', '__vscode_new__') +command! -bang Only if ==# '!' | call closeOtherEditors() | else | call VSCodeNotify('workbench.action.joinAllGroups') | endif + +AlterCommand sp[lit] Split +AlterCommand vs[plit] Vsplit +AlterCommand new New +AlterCommand vne[w] Vnew +AlterCommand on[ly] Only + +" buffer management +nnoremap n call splitNew('h', '__vscode_new__') +xnoremap n call splitNew('h', '__vscode_new__') + +nnoremap q call VSCodeNotify('workbench.action.closeActiveEditor') +xnoremap q call VSCodeNotify('workbench.action.closeActiveEditor') +nnoremap c call VSCodeNotify('workbench.action.closeActiveEditor') +xnoremap c call VSCodeNotify('workbench.action.closeActiveEditor') +nnoremap call VSCodeNotify('workbench.action.closeActiveEditor') +xnoremap call VSCodeNotify('workbench.action.closeActiveEditor') + +" window/splits management +nnoremap s call split('h') +xnoremap s call split('h') +nnoremap call split('h') +xnoremap call split('h') + +nnoremap v call split('v') +xnoremap v call split('v') +nnoremap call split('v') +xnoremap call split('v') + +nnoremap = call VSCodeNotify('workbench.action.evenEditorWidths') +xnoremap = call VSCodeNotify('workbench.action.evenEditorWidths') +nnoremap _ call VSCodeNotify('workbench.action.toggleEditorWidths') +xnoremap _ call VSCodeNotify('workbench.action.toggleEditorWidths') + +nnoremap + call manageEditorHeight(v:count, 'increase') +xnoremap + call manageEditorHeight(v:count, 'increase') +nnoremap - call manageEditorHeight(v:count, 'decrease') +xnoremap - call manageEditorHeight(v:count, 'decrease') +nnoremap > call manageEditorWidth(v:count, 'increase') +xnoremap > call manageEditorWidth(v:count, 'increase') +nnoremap < call manageEditorWidth(v:count, 'decrease') +xnoremap < call manageEditorWidth(v:count, 'decrease') + +nnoremap o call VSCodeNotify('workbench.action.joinAllGroups') +xnoremap o call VSCodeNotify('workbench.action.joinAllGroups') +nnoremap call VSCodeNotify('workbench.action.joinAllGroups') +xnoremap call VSCodeNotify('workbench.action.joinAllGroups') + +" window navigation +nnoremap j call VSCodeNotify('workbench.action.navigateDown') +xnoremap j call VSCodeNotify('workbench.action.navigateDown') +nnoremap k call VSCodeNotify('workbench.action.navigateUp') +xnoremap k call VSCodeNotify('workbench.action.navigateUp') +nnoremap h call VSCodeNotify('workbench.action.navigateLeft') +xnoremap h call VSCodeNotify('workbench.action.navigateLeft') +nnoremap l call VSCodeNotify('workbench.action.navigateRight') +xnoremap l call VSCodeNotify('workbench.action.navigateRight') + +nnoremap call VSCodeNotify('workbench.action.navigateDown') +xnoremap call VSCodeNotify('workbench.action.navigateDown') +nnoremap call VSCodeNotify('workbench.action.navigateUp') +xnoremap call VSCodeNotify('workbench.action.navigateUp') +nnoremap call VSCodeNotify('workbench.action.navigateLeft') +xnoremap call VSCodeNotify('workbench.action.navigateLeft') +nnoremap call VSCodeNotify('workbench.action.navigateRight') +xnoremap call VSCodeNotify('workbench.action.navigateRight') + +nnoremap call VSCodeNotify('workbench.action.moveEditorToBelowGroup') +xnoremap call VSCodeNotify('workbench.action.moveEditorToBelowGroup') +nnoremap call VSCodeNotify('workbench.action.moveEditorToAboveGroup') +xnoremap call VSCodeNotify('workbench.action.moveEditorToAboveGroup') +nnoremap call VSCodeNotify('workbench.action.moveEditorToLeftGroup') +xnoremap call VSCodeNotify('workbench.action.moveEditorToLeftGroup') +nnoremap call VSCodeNotify('workbench.action.moveEditorToRightGroup') +xnoremap call VSCodeNotify('workbench.action.moveEditorToRightGroup') + +nnoremap call VSCodeNotify('workbench.action.moveEditorToBelowGroup') +xnoremap call VSCodeNotify('workbench.action.moveEditorToBelowGroup') +nnoremap call VSCodeNotify('workbench.action.moveEditorToAboveGroup') +xnoremap call VSCodeNotify('workbench.action.moveEditorToAboveGroup') +nnoremap call VSCodeNotify('workbench.action.moveEditorToLeftGroup') +xnoremap call VSCodeNotify('workbench.action.moveEditorToLeftGroup') +nnoremap call VSCodeNotify('workbench.action.moveEditorToRightGroup') +xnoremap call VSCodeNotify('workbench.action.moveEditorToRightGroup') + +nnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupDown') +xnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupDown') +nnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupUp') +xnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupUp') +nnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupLeft') +xnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupLeft') +nnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupRight') +xnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupRight') + +nnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupDown') +xnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupDown') +nnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupUp') +xnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupUp') +nnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupLeft') +xnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupLeft') +nnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupRight') +xnoremap call VSCodeNotify('workbench.action.moveActiveEditorGroupRight') + +nnoremap w call VSCodeNotify('workbench.action.focusNextGroup') +xnoremap w call VSCodeNotify('workbench.action.focusNextGroup') +nnoremap call VSCodeNotify('workbench.action.focusNextGroup') +xnoremap call VSCodeNotify('workbench.action.focusNextGroup') +nnoremap W call VSCodeNotify('workbench.action.focusPreviousGroup') +xnoremap W call VSCodeNotify('workbench.action.focusPreviousGroup') +nnoremap p call VSCodeNotify('workbench.action.focusPreviousGroup') +xnoremap p call VSCodeNotify('workbench.action.focusPreviousGroup') + +nnoremap t call VSCodeNotify('workbench.action.focusFirstEditorGroup') +xnoremap t call VSCodeNotify('workbench.action.focusFirstEditorGroup') +nnoremap b call VSCodeNotify('workbench.action.focusLastEditorGroup') +xnoremap b call VSCodeNotify('workbench.action.focusLastEditorGroup') + diff --git a/src/test/integ/vscode-integration-specific.test.ts b/src/test/integ/vscode-integration-specific.test.ts new file mode 100644 index 0000000..25bb56e --- /dev/null +++ b/src/test/integ/vscode-integration-specific.test.ts @@ -0,0 +1,639 @@ +import path from "path"; +import os from "os"; +import fs from "fs"; +import { strict as assert } from "assert"; + +import vscode, { Selection } from "vscode"; +import { NeovimClient } from "neovim"; + +import { wait } from "../../utils"; + +import { + attachTestNvimClient, + assertContent, + setCursor, + sendVSCodeKeys, + closeAllActiveEditors, + sendEscapeKey, + closeNvimClient, + getVScodeCursor, + sendVSCodeKeysAtomic, + openTextDocument, + sendInsertKey, + sendVSCodeCommand, + sendNeovimKeys, + itSkipMacos, +} from "./integrationUtils"; + +describe("VSCode integration specific stuff", () => { + let client: NeovimClient; + before(async () => { + client = await attachTestNvimClient(); + }); + after(async () => { + await closeNvimClient(client); + await closeAllActiveEditors(); + }); + + beforeEach(async () => { + await closeAllActiveEditors(); + }); + + it("Doesnt move cursor on peek definition", async () => { + const doc = ( + await openTextDocument({ + content: 'declare function test(a: number): void;\n\ntest("")\n', + language: "typescript", + }) + ).document; + await setCursor(2, 1); + + // peek definition opens another editor. make sure the cursor won't be leaked into primary editor + await vscode.commands.executeCommand("editor.action.peekDefinition", doc.uri, new vscode.Position(2, 1)); + await wait(500); + await vscode.commands.executeCommand("closeReferenceSearch", doc.uri, new vscode.Position(2, 1)); + await wait(500); + await assertContent( + { + cursor: [2, 1], + }, + client, + ); + }); + + it("Moves on cursor on go definition", async () => { + const doc = ( + await openTextDocument({ + content: 'declare function test(a: number): void;\n\ntest("")\n', + language: "typescript", + }) + ).document; + await setCursor(2, 1); + + await vscode.commands.executeCommand("editor.action.goToTypeDefinition", doc.uri, new vscode.Position(2, 1)); + await wait(1000); + await assertContent( + { + cursor: [0, 17], + }, + client, + ); + }); + + // TODO: always fails on CI, possible something with screen dimensions? + it.skip("Editor cursor revealing", async () => { + await openTextDocument(path.join(__dirname, "../../../test_fixtures/cursor-revealing.txt")); + + await sendVSCodeKeys("90j"); + await assertContent({ cursor: [90, 0], vsCodeVisibleRange: { bottom: 90 } }, client); + + await sendVSCodeKeys("zt"); + await assertContent({ cursor: [90, 0], vsCodeVisibleRange: { top: 90 } }, client); + + // await sendVSCodeKeys("40k"); + // await assertContent({ cursor: [90, 0], vsCodeVisibleRange: { bottom: 50 } }, client); + }); + + it("Scrolling actions", async () => { + const editor = await openTextDocument(path.join(__dirname, "../../../test_fixtures/scrolltest.txt")); + + await sendVSCodeCommand("vscode-neovim.ctrl-f"); + + let visibleRange = editor.visibleRanges[0]; + const topLine = visibleRange.start.line; + const bottomLine = visibleRange.end.line; + const cursorLine = editor.selection.active.line; + // Viewport height differs across VS Code versions / CI; cursor should stay within the visible slice. + assert.ok( + cursorLine >= topLine && cursorLine <= bottomLine, + `cursor ${cursorLine} not in visible range ${topLine}-${bottomLine}`, + ); + await assertContent( + { + cursor: [cursorLine, 0], + }, + client, + ); + + await sendVSCodeKeys("L", 400); + visibleRange = editor.visibleRanges[0]; + const cursor = getVScodeCursor(editor); + assert.ok(cursor[0] <= visibleRange.end.line && cursor[0] >= visibleRange.end.line - 1); + await assertContent( + { + cursor, + }, + client, + ); + + await sendVSCodeKeys("M", 400); + visibleRange = editor.visibleRanges[0]; + await assertContent( + { + cursor: [editor.selection.active.line, 0], + }, + client, + ); + const middleline = visibleRange.start.line + (visibleRange.end.line - visibleRange.start.line) / 2; + assert.ok(editor.selection.active.line >= middleline - 1); + assert.ok(editor.selection.active.line <= middleline + 1); + + await sendVSCodeKeys("H", 400); + visibleRange = editor.visibleRanges[0]; + await assertContent( + { + cursor: [visibleRange.start.line, 0], + }, + client, + ); + }); + + // todo: sometimes it's failing, but most times works + it("Go to definition in other file - cursor is ok", async function () { + this.retries(3); + + const doc2 = (await openTextDocument(path.join(__dirname, "../../../test_fixtures/b.ts"))).document; + await setCursor(3, 1); + + await vscode.commands.executeCommand("editor.action.goToTypeDefinition", doc2.uri, new vscode.Position(2, 1)); + await wait(500); + + await assertContent( + { + cursor: [4, 16], + content: [ + 'export const a = "blah";', + "", + 'export const b = "blah";', + "", + "export function someFunc(): void;", + "", + ], + }, + client, + ); + }); + + itSkipMacos("Current mode is canceled when switching between editor panes", async () => { + await openTextDocument({ + content: "blah1", + }); + await wait(500); + const doc2 = await vscode.workspace.openTextDocument({ + content: "blah2", + }); + await vscode.window.showTextDocument(doc2, vscode.ViewColumn.Two); + await wait(500); + + await client.command("au BufEnter * stopinsert"); + await wait(500); + await sendVSCodeCommand("workbench.action.focusSecondEditorGroup", "", 1000); + await sendInsertKey("I"); + await assertContent( + { + content: ["blah2"], + cursorStyle: "line", + mode: "i", + }, + client, + ); + // make sure the changes will be synced with neovim + await sendVSCodeKeys("test", 1000); + await sendVSCodeCommand("workbench.action.focusFirstEditorGroup", "", 2000); + await assertContent( + { + content: ["blah1"], + cursorStyle: "block", + mode: "n", + }, + client, + ); + + await sendVSCodeKeys("V"); + await assertContent( + { + content: ["blah1"], + mode: "V", + }, + client, + ); + + await sendVSCodeCommand("workbench.action.focusSecondEditorGroup", "", 2000); + await assertContent( + { + content: ["testblah2"], + mode: "n", + }, + client, + ); + }); + + it("Current mode is canceled when switching between editor tabs", async () => { + const doc1 = await vscode.workspace.openTextDocument({ + content: "blah1", + }); + await vscode.window.showTextDocument(doc1, vscode.ViewColumn.One); + const doc2 = await vscode.workspace.openTextDocument({ + content: "blah2", + }); + await vscode.window.showTextDocument(doc2, vscode.ViewColumn.One); + await wait(500); + await client.command("au BufEnter * stopinsert"); + await wait(500); + + await sendInsertKey("I"); + await assertContent( + { + content: ["blah2"], + cursorStyle: "line", + mode: "i", + }, + client, + ); + // make sure the changes will be synced with neovim + await sendVSCodeKeys("test", 500); + await sendVSCodeCommand("workbench.action.previousEditorInGroup", "", 500); + await assertContent( + { + content: ["blah1"], + cursorStyle: "block", + mode: "n", + }, + client, + ); + + await sendVSCodeKeys("V"); + await assertContent( + { + content: ["blah1"], + mode: "V", + }, + client, + ); + + await sendVSCodeCommand("workbench.action.nextEditorInGroup", "", 500); + await assertContent( + { + content: ["testblah2"], + cursorStyle: "block", + mode: "n", + }, + client, + ); + }); + + it("Cursor is ok when go to def into editor in the other pane", async () => { + const doc1 = await vscode.workspace.openTextDocument(path.join(__dirname, "../../../test_fixtures/bb.ts")); + await vscode.window.showTextDocument(doc1, vscode.ViewColumn.One); + await wait(1500); + + const doc2 = await vscode.workspace.openTextDocument( + path.join(__dirname, "../../../test_fixtures/def-with-scroll.ts"), + ); + await vscode.window.showTextDocument(doc2, vscode.ViewColumn.Two, true); + await wait(1500); + + // make sure we're in first editor group + await vscode.commands.executeCommand("workbench.action.focusFirstEditorGroup"); + await wait(400); + + await sendVSCodeKeys("gg5j", 0); + await wait(1000); + + await vscode.commands.executeCommand( + "editor.action.revealDefinitionAside", + doc1.uri, + new vscode.Position(5, 1), + ); + await wait(1500); + + await assertContent( + { + cursor: [115, 16], + }, + client, + ); + }); + + // !Passes only when the runner is in foreground + itSkipMacos("Cursor is preserved if same doc is opened in two editor columns", async () => { + const doc = ( + await openTextDocument(path.join(__dirname, "../../../test_fixtures/cursor-preserved-between-columns.txt")) + ).document; + await wait(1000); + await sendVSCodeKeys("gg050j", 1000); + await vscode.window.showTextDocument(doc, vscode.ViewColumn.Two, false); + await wait(1000); + await sendVSCodeKeys("gg0100j", 1000); + + await sendVSCodeCommand("workbench.action.focusFirstEditorGroup", "", 2000); + await sendVSCodeKeys("l"); + await assertContent( + { + cursor: [50, 1], + }, + client, + ); + + await sendVSCodeCommand("workbench.action.focusSecondEditorGroup", "", 1000); + await sendVSCodeKeys("l"); + await assertContent( + { + cursor: [100, 1], + }, + client, + ); + }); + + it("Opens a file through e command", async () => { + const filePath = path.join(os.tmpdir(), Math.random().toString()); + fs.writeFileSync(filePath, ["line 1"].join("\n"), { + encoding: "utf8", + }); + + await openTextDocument({ content: "blah" }); + + await sendVSCodeKeysAtomic(":e " + filePath, 500); + await sendVSCodeCommand("vscode-neovim.commit-cmdline", "", 500); + await assertContent( + { + content: ["line 1"], + }, + client, + ); + }); + + it("Spawning command line from visual line mode produces vscode selection", async () => { + await openTextDocument({ content: ["a1", "b1", "c1"].join("\n") }); + await sendVSCodeKeys("Vj"); + await sendVSCodeCommand("workbench.action.quickOpen"); + await assertContent( + { + vsCodeSelections: [new vscode.Selection(0, 0, 1, 2)], + }, + client, + ); + await vscode.commands.executeCommand("workbench.action.closeQuickOpen"); + await sendEscapeKey(); + + await sendVSCodeKeys("GVk"); + await sendVSCodeCommand("workbench.action.quickOpen"); + await assertContent( + { + vsCodeSelections: [new vscode.Selection(2, 2, 1, 0)], + }, + client, + ); + await vscode.commands.executeCommand("workbench.action.closeQuickOpen"); + }); + + it("Spawning command line from visual mode produces vscode selection", async () => { + const documentContent = "Hello World!"; + await openTextDocument({ content: documentContent }); + await sendVSCodeKeys("v$"); + await sendVSCodeCommand("workbench.action.quickOpen"); + await assertContent( + { + vsCodeSelections: [new vscode.Selection(0, 0, 0, documentContent.length)], + }, + client, + ); + await vscode.commands.executeCommand("workbench.action.closeQuickOpen"); + await sendEscapeKey(); + + await sendVSCodeKeys("gvo"); + await sendVSCodeCommand("vscode-neovim.send", ""); + await assertContent( + { + vsCodeSelections: [new vscode.Selection(0, documentContent.length, 0, 0)], + }, + client, + ); + await vscode.commands.executeCommand("workbench.action.closeQuickOpen"); + }); + + it("Filetype detection", async function () { + this.retries(3); + + const doc1 = await vscode.workspace.openTextDocument(path.join(__dirname, "../../../test_fixtures/bb.ts")); + await vscode.window.showTextDocument(doc1, vscode.ViewColumn.One); + await wait(1500); + + const buf = await client.buffer; + const type = await client.request("nvim_buf_get_option", [buf.id, "filetype"]); + assert.strictEqual("typescript", type); + }); + + it("Filetype detection (jupyter notebook)", async function () { + this.retries(2); + + const note = await vscode.workspace.openNotebookDocument( + vscode.Uri.file(path.join(__dirname, "../../../test_fixtures/window-changed.ipynb")), + ); + await vscode.window.showNotebookDocument(note, { viewColumn: vscode.ViewColumn.One }); + await wait(1000); + + const buf = await client.buffer; + const type = await client.request("nvim_buf_get_option", [buf.id, "filetype"]); + assert.strictEqual("python", type); + }); + + it("Next search result works", async () => { + await openTextDocument(path.join(__dirname, "../../../test_fixtures/incsearch-scroll.ts")); + + await sendVSCodeCommand("workbench.action.findInFiles", { query: "blah" }, 500); + await sendVSCodeCommand("search.action.refreshSearchResults"); + await sendVSCodeCommand("workbench.action.focusFirstEditorGroup"); + await sendVSCodeCommand("search.action.focusNextSearchResult"); + await assertContent( + { + vsCodeSelections: [new Selection(115, 16, 115, 20)], + neovimCursor: [115, 19], + }, + client, + ); + + await sendVSCodeCommand("search.action.focusNextSearchResult"); + await assertContent( + { + vsCodeSelections: [new Selection(170, 16, 170, 20)], + neovimCursor: [170, 19], + }, + client, + ); + }); + + it("Edit on long lines works", async () => { + await openTextDocument(path.join(__dirname, "../../../test_fixtures/long-line.txt")); + + await sendVSCodeKeys("gg^"); + await sendVSCodeKeys("2jb"); + await assertContent( + { + cursor: [1, 1580], + }, + client, + ); + + await sendVSCodeKeys("iabc"); + await sendEscapeKey(); + await assertContent( + { + cursor: [1, 1582], + }, + client, + ); + + await sendVSCodeKeys("jhk"); + await assertContent( + { + cursor: [1, 10], + }, + client, + ); + + await sendVSCodeKeys("Aabc"); + await sendEscapeKey(); + await assertContent( + { + cursor: [1, 1589], + }, + client, + ); + + await sendVSCodeKeys("Iabc"); + await sendEscapeKey(); + await assertContent( + { + cursor: [1, 2], + }, + client, + ); + + await sendVSCodeKeys("$"); + await assertContent( + { + cursor: [1, 1592], + }, + client, + ); + }); + + it("cursorMove with wrappedLine should works #1498", async () => { + await openTextDocument({ content: " hello\n\nworld" }); + await wait(200); + await sendNeovimKeys(client, "ll", 200); + vscode.commands.executeCommand("cursorMove", { to: "down", by: "wrappedLine" }); + await wait(200); + vscode.commands.executeCommand("cursorMove", { to: "down", by: "wrappedLine" }); + await wait(200); + await assertContent({ cursor: [2, 2] }, client); + }); + + it("vim.ui.select works", async () => { + await client.lua(` + vim.ui.select({ 'red', 'green', 'blue' }, {}, function(item, idx) + vim.g._ret_item = item + vim.g._ret_idx = idx + end) + `); + // wait enough time for it to open + await wait(100); + // select the last item + await vscode.commands.executeCommand("workbench.action.quickOpenNavigateNext"); + await vscode.commands.executeCommand("workbench.action.quickOpenNavigateNext"); + await vscode.commands.executeCommand("workbench.action.acceptSelectedQuickOpenItem"); + // check the results + const actual_item = await client.getVar("_ret_item"); + const actual_idx = await client.getVar("_ret_idx"); + assert.strictEqual(actual_item, "blue"); + assert.strictEqual(actual_idx, 3); + }); + + it("vim.ui.select with format_item works", async () => { + await client.lua(` + vim.ui.select({{ label = 'apple', detail = 'red' }, { label = 'avocado', detail = 'green' }}, { + format_item = function(item) + return item.label + end + }, function(item, idx) + vim.g._ret_item = item + vim.g._ret_idx = idx + end) + `); + // wait enough time for it to open + await wait(100); + // select the first item + await vscode.commands.executeCommand("workbench.action.acceptSelectedQuickOpenItem"); + // check the results + const actual_item = (await client.getVar("_ret_item")) as { label: string; detail: string }; + const actual_idx = await client.getVar("_ret_idx"); + assert.ok(typeof actual_item === "object"); + assert.strictEqual(actual_item.label, "apple"); + assert.strictEqual(actual_item.detail, "red"); + assert.strictEqual(actual_idx, 1); + }); + + it("vim.ui.select cancel returns nil", async () => { + await client.lua(` + vim.ui.select({ 'red', 'green', 'blue' }, {}, function(item, idx) + vim.g._ret_item = item + vim.g._ret_idx = idx + end) + `); + // wait enough time for it to open + await wait(100); + // cancel the dialog + await vscode.commands.executeCommand("workbench.action.closeQuickOpen"); + // check the results + const actual_item = await client.getVar("_ret_item"); + const actual_idx = await client.getVar("_ret_idx"); + assert.strictEqual(actual_item, null); + assert.strictEqual(actual_idx, null); + }); + + it("vim.ui.input works", async () => { + await client.lua(` + vim.ui.input({ prompt = 'Enter a value: ', default = 'test' }, function(input) + vim.g._res = input + end) + `); + // wait enough time for it to open + await wait(100); + // confirm the value + await vscode.commands.executeCommand("workbench.action.acceptSelectedQuickOpenItem"); + // check the results + const actual_input = await client.getVar("_res"); + assert.strictEqual(actual_input, "test"); + }); + + it("vim.ui.input empty not nil", async () => { + await client.lua(` + vim.ui.input({ prompt = 'Enter a value: ' }, function(input) + vim.g._res = input + end) + `); + // wait enough time for it to open + await wait(100); + // confirm the value + await vscode.commands.executeCommand("workbench.action.acceptSelectedQuickOpenItem"); + // check the results + const actual_input = await client.getVar("_res"); + assert.strictEqual(actual_input, ""); + }); + + it("vim.ui.input cancel returns nil", async () => { + await client.lua(` + vim.ui.input({ prompt = 'Enter a value: ' }, function(input) + vim.g._res = input + end) + `); + // wait enough time for it to open + await wait(100); + // cancel the dialog + await vscode.commands.executeCommand("workbench.action.closeQuickOpen"); + // check the results + const actual_input = await client.getVar("_res"); + assert.strictEqual(actual_input, null); + }); +});