From 377f3bfeca716ada246720a7974c49aee56fd382 Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Tue, 28 Oct 2025 10:20:27 +0100 Subject: [PATCH] fix(picker.diff): better filename parsing. See #2366 --- lua/snacks/picker/source/diff.lua | 10 ++----- lua/snacks/picker/util/init.lua | 50 ++----------------------------- tests/picker/diff_spec.lua | 15 ++++++++++ 3 files changed, 20 insertions(+), 55 deletions(-) diff --git a/lua/snacks/picker/source/diff.lua b/lua/snacks/picker/source/diff.lua index 1ae8b543..3966e9b4 100644 --- a/lua/snacks/picker/source/diff.lua +++ b/lua/snacks/picker/source/diff.lua @@ -106,14 +106,8 @@ function M.parse(lines) emit() local file ---@type string? if text:find("^diff") then - local parsed = Snacks.picker.util.parse_cmdline(text) - for i = 2, #parsed do - local arg = parsed[i] - if not arg:find("^%-") then - file = arg:match("^%a/(.*)") or arg - break - end - end + text = text:gsub("^diff%s*", ""):gsub("^%-%S+%s*", "") + file = text:match('^"%a/(.-)"') or text:match("^%a/(.-) %a/") or text:match("^%a/(.*)$") or text elseif text:find("^%-%-%-") then file = text:match("^%-%-%- %a/([^\t]+)") or text:match("^%-%-%- ([^\t]+)") end diff --git a/lua/snacks/picker/util/init.lua b/lua/snacks/picker/util/init.lua index a59ea85f..ff49f6fe 100644 --- a/lua/snacks/picker/util/init.lua +++ b/lua/snacks/picker/util/init.lua @@ -646,53 +646,9 @@ function M.globber(globs) end end ----@param cmdline string ----@return string[] -function M.parse_cmdline(cmdline) - local args = {} ---@type string[] - local current = "" - local in_quote = false - local quote_char = nil - local i = 1 - - while i <= #cmdline do - local char = cmdline:sub(i, i) - local next_char = cmdline:sub(i + 1, i + 1) - - if char == "\\" and next_char ~= "" then - -- Escaped character - take next char literally - current = current .. next_char - i = i + 2 - elseif not in_quote and (char == '"' or char == "'") then - -- Start quote - in_quote = true - quote_char = char - i = i + 1 - elseif in_quote and char == quote_char then - -- End quote - in_quote = false - quote_char = nil - i = i + 1 - elseif not in_quote and char:match("%s") then - -- Whitespace outside quotes - split arg - if current ~= "" then - args[#args + 1] = current - current = "" - end - i = i + 1 - else - -- Regular character or whitespace inside quotes - current = current .. char - i = i + 1 - end - end - - -- Add last arg if any - if current ~= "" then - args[#args + 1] = current - end - - return args +---@param buf number +function M.spinner(buf) + return require("snacks.picker.util.spinner").new(buf) end return M diff --git a/tests/picker/diff_spec.lua b/tests/picker/diff_spec.lua index 1ca64174..8d841f3d 100644 --- a/tests/picker/diff_spec.lua +++ b/tests/picker/diff_spec.lua @@ -235,6 +235,21 @@ describe("picker.diff", function() assert.equals("my file.txt", blocks[1].file) end) + it("handles files with spaces in name without quotes", function() + local lines = { + "diff --git a/my file.txt b/my file.txt", + "--- a/my file.txt", + "+++ b/my file.txt", + "@@ -1,1 +1,1 @@", + "-old", + "+new", + } + + local blocks = diff.parse(lines) + assert.equals(1, #blocks) + assert.equals("my file.txt", blocks[1].file) + end) + it("handles files in subdirectories", function() local lines = { "diff --git a/path/to/file.txt b/path/to/file.txt",