Skip to content

Commit 5255aa2

Browse files
jamestrewclason
authored andcommitted
fix(git_status): parse NUL-delimited git status output
Problem: `git status --porcelain` will wrap file paths with "special characters" (eg `\n`, spaces) in double quotes which complicates downstream parsing of results. Furthermore, if a file path HAS a newline char, the existing approach for getting results by splitting by `\n` is completely broken. Solution: Switch to `git status -z`. `-z` is more machine parse-able than plain `--porcelain` as git will no longer treat paths with special characters specially, delimiting results by NUL (the only non-valid character in unix paths) rather than LF while keeping the benefit of `--porcelain` (stable across git versions and user config). Adds support for this in `async_oneshot_finder`/`LinesPipe` via a new `split_char` option.
1 parent ad7d958 commit 5255aa2

4 files changed

Lines changed: 9 additions & 9 deletions

File tree

lua/telescope/_.lua

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,9 @@ function LinesPipe:read()
147147
return read_rx()
148148
end
149149

150-
function LinesPipe:iter(schedule)
151-
if schedule == nil then
152-
schedule = true
153-
end
150+
function LinesPipe:iter(schedule, opts)
151+
schedule = vim.F.if_nil(schedule, true)
152+
local split_char = vim.F.if_nil(opts and opts.split_char, "\n")
154153

155154
local text = nil
156155
local index = nil
@@ -167,8 +166,7 @@ function LinesPipe:iter(schedule)
167166
return (previous or "") .. read
168167
end
169168

170-
local next_value = nil
171-
next_value = function()
169+
local function next_value()
172170
if schedule then
173171
async.util.scheduler()
174172
end
@@ -178,7 +176,7 @@ function LinesPipe:iter(schedule)
178176
end
179177

180178
local start = index
181-
index = string.find(text, "\n", index, true)
179+
index = string.find(text, split_char, index, true)
182180

183181
if index == nil then
184182
text = get_next_text(string.sub(text, start or 1))

lua/telescope/builtin/__git.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,14 +371,15 @@ git.status = function(opts)
371371
return
372372
end
373373

374-
local args = { "status", "--porcelain=v1", "--", "." }
374+
local args = { "status", "-z", "--", "." }
375375

376376
local gen_new_finder = function()
377377
if vim.F.if_nil(opts.expand_dir, true) then
378378
table.insert(args, #args - 1, "-uall")
379379
end
380380
local git_cmd = git_command(args, opts)
381381
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_status(opts))
382+
opts.split_char = "\0"
382383
return finders.new_oneshot_job(git_cmd, opts)
383384
end
384385

lua/telescope/finders.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ finders.new_oneshot_job = function(command_list, opts)
199199

200200
cwd = opts.cwd,
201201
maximum_results = opts.maximum_results,
202+
split_char = opts.split_char,
202203

203204
fn_command = function()
204205
return {

lua/telescope/finders/async_oneshot_finder.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ return function(opts)
6363
process_result(v)
6464
end
6565
end
66-
for line in stdout:iter(false) do
66+
for line in stdout:iter(false, { split_char = opts.split_char }) do
6767
num_results = num_results + 1
6868

6969
if num_results % await_count then

0 commit comments

Comments
 (0)