From 37e9111d94746be2e3d951f991d344f7bcca86de Mon Sep 17 00:00:00 2001 From: Mika Vilpas Date: Wed, 1 Jan 2025 16:11:58 +0200 Subject: [PATCH] fix: not providing completions for a project root with spaces Issue ===== When working in a project whose project_root_marker path contained space characters (maybe even other special characters), the plugin would not provide any completions. This was caused by extra escaping of the path in the command that was run in the background. Solution ======== Correctly escape the spaces and provide completions. test: can run the debug command in a shell --- integration-tests/MyTestDirectory.ts | 21 ++++++++++ .../e2e/blink-ripgrep/basic_spec.cy.ts | 40 +++++++++++++++++++ .../dir with spaces/file with spaces.txt | 1 + .../other file with spaces.txt | 1 + lua/blink-ripgrep/init.lua | 15 +------ lua/blink-ripgrep/ripgrep_command.lua | 32 ++++++++++----- 6 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 integration-tests/test-environment/limited/dir with spaces/file with spaces.txt create mode 100644 integration-tests/test-environment/limited/dir with spaces/other file with spaces.txt diff --git a/integration-tests/MyTestDirectory.ts b/integration-tests/MyTestDirectory.ts index 2a73cb2..714a3b3 100644 --- a/integration-tests/MyTestDirectory.ts +++ b/integration-tests/MyTestDirectory.ts @@ -66,6 +66,24 @@ export const MyTestDirectorySchema = z.object({ name: z.literal("limited/"), type: z.literal("directory"), contents: z.object({ + "dir with spaces": z.object({ + name: z.literal("dir with spaces/"), + type: z.literal("directory"), + contents: z.object({ + "file with spaces.txt": z.object({ + name: z.literal("file with spaces.txt"), + type: z.literal("file"), + extension: z.literal("txt"), + stem: z.literal("file with spaces."), + }), + "other file with spaces.txt": z.object({ + name: z.literal("other file with spaces.txt"), + type: z.literal("file"), + extension: z.literal("txt"), + stem: z.literal("other file with spaces."), + }), + }), + }), "main-project-file.lua": z.object({ name: z.literal("main-project-file.lua"), type: z.literal("file"), @@ -136,6 +154,9 @@ export const testDirectoryFiles = z.enum([ "config-modifications/use_manual_mode.lua", "config-modifications", "initial-file.txt", + "limited/dir with spaces/file with spaces.txt", + "limited/dir with spaces/other file with spaces.txt", + "limited/dir with spaces", "limited/main-project-file.lua", "limited/subproject/example.clj", "limited/subproject/file1.lua", diff --git a/integration-tests/cypress/e2e/blink-ripgrep/basic_spec.cy.ts b/integration-tests/cypress/e2e/blink-ripgrep/basic_spec.cy.ts index ea1587d..7618d3e 100644 --- a/integration-tests/cypress/e2e/blink-ripgrep/basic_spec.cy.ts +++ b/integration-tests/cypress/e2e/blink-ripgrep/basic_spec.cy.ts @@ -249,6 +249,46 @@ describe("searching inside projects", () => { }) }) +describe("debug mode", () => { + it("can execute the debug command in a shell", () => { + cy.visit("/") + cy.startNeovim({ + // also test that the plugin can handle spaces in the file path + filename: "limited/dir with spaces/file with spaces.txt", + }).then(() => { + // wait until text on the start screen is visible + cy.contains("this is file with spaces.txt") + cy.runExCommand({ command: `!mkdir "%:h/.git"` }) + + // clear the current line and enter insert mode + cy.typeIntoTerminal("cc") + + cy.typeIntoTerminal("spa") + cy.contains("spaceroni-macaroni") + + cy.runExCommand({ command: "messages" }).then((result) => { + // make sure the logged command can be run in a shell + expect(result.value) + cy.log(result.value ?? "") + + cy.typeIntoTerminal("{esc}:term{enter}", { delay: 3 }) + cy.contains("term://") + + // start insert mode + cy.typeIntoTerminal("a") + + cy.typeIntoTerminal(result.value ?? "") + cy.typeIntoTerminal("{enter}") + + // The results will lbe 5-10 lines of jsonl. + // Somewhere in the results, we should see the match, if the search was + // successful. + cy.contains(`spaceroni-macaroni`) + }) + }) + }) +}) + function createFakeGitDirectoriesToLimitRipgrepScope() { cy.runExCommand({ command: `!mkdir %:h/.git` }) cy.runExCommand({ diff --git a/integration-tests/test-environment/limited/dir with spaces/file with spaces.txt b/integration-tests/test-environment/limited/dir with spaces/file with spaces.txt new file mode 100644 index 0000000..36c425b --- /dev/null +++ b/integration-tests/test-environment/limited/dir with spaces/file with spaces.txt @@ -0,0 +1 @@ +this is file with spaces.txt diff --git a/integration-tests/test-environment/limited/dir with spaces/other file with spaces.txt b/integration-tests/test-environment/limited/dir with spaces/other file with spaces.txt new file mode 100644 index 0000000..561dceb --- /dev/null +++ b/integration-tests/test-environment/limited/dir with spaces/other file with spaces.txt @@ -0,0 +1 @@ +spaceroni-macaroni diff --git a/lua/blink-ripgrep/init.lua b/lua/blink-ripgrep/init.lua index 3cceccf..b20c2fa 100644 --- a/lua/blink-ripgrep/init.lua +++ b/lua/blink-ripgrep/init.lua @@ -175,18 +175,7 @@ function RgSource:get_completions(context, resolve) cmd = command.get_command(prefix, RgSource.config) if RgSource.config.debug then - -- print the command to :messages for hacky debugging, but don't show it - -- in the ui so that it doesn't interrupt the user's work - local debug_cmd = vim.deepcopy(cmd) - - -- The pattern is not compatible with shell syntax, so escape it - -- separately. The user should be able to copy paste it into their posix - -- compatible terminal. - local pattern = debug_cmd[9] - debug_cmd[9] = "'" .. pattern .. "'" - - local things = table.concat(debug_cmd, " ") - vim.api.nvim_exec2("echomsg " .. vim.fn.string(things), {}) + command.debugify_for_shell(cmd) end end @@ -222,8 +211,6 @@ function RgSource:get_completions(context, resolve) docstring = docstring .. line.text .. "\n" end - -- the implementation for render_detail_and_documentation: - -- ../../integration-tests/test-environment/.repro/data/nvim/lazy/blink.cmp/lua/blink/cmp/windows/lib/docs.lua ---@diagnostic disable-next-line: missing-fields items[matchkey] = { documentation = { diff --git a/lua/blink-ripgrep/ripgrep_command.lua b/lua/blink-ripgrep/ripgrep_command.lua index efc0ca9..1f31788 100644 --- a/lua/blink-ripgrep/ripgrep_command.lua +++ b/lua/blink-ripgrep/ripgrep_command.lua @@ -20,19 +20,29 @@ function RipgrepCommand.get_command(prefix, options) table.insert(cmd, "--") table.insert(cmd, prefix .. "[\\w_-]+") - local final = { - -- NOTE: 2024-11-28 the logic is documented in the README file, and - -- should be kept up to date - vim.fn.fnameescape( - vim.fs.root(0, options.project_root_marker) or vim.fn.getcwd() - ), - } - - for _, option in ipairs(final) do - table.insert(cmd, option) - end + local root = (vim.fs.root(0, options.project_root_marker) or vim.fn.getcwd()) + table.insert(cmd, root) return cmd end +-- Change the command from `get_command` to a string that can be executed in a +-- shell +---@param cmd string[] +function RipgrepCommand.debugify_for_shell(cmd) + -- print the command to :messages for hacky debugging, but don't show it + -- in the ui so that it doesn't interrupt the user's work + local debug_cmd = vim.deepcopy(cmd) + + -- The pattern is not compatible with shell syntax, so escape it + -- separately. The user should be able to copy paste it into their posix + -- compatible terminal. + local pattern = debug_cmd[9] + debug_cmd[9] = "'" .. pattern .. "'" + debug_cmd[10] = vim.fn.fnameescape(debug_cmd[10]) + + local things = table.concat(debug_cmd, " ") + vim.api.nvim_exec2("echomsg " .. vim.fn.string(things), {}) +end + return RipgrepCommand