Summary
In the Warp client, git add <tab> returns broken suggestions for any working-tree file whose name contains a space. The completion popup shows the filename truncated at the first space (often with a stray leading " from git's C-style quoting), and selecting the suggestion inserts the truncated string into the buffer. The user cannot stage files with spaces in their names via tab completion.
Reproduction
mkdir /tmp/repro && cd /tmp/repro
git init -q
touch "new file test.csv"
In Warp, type git add in /tmp/repro and press Tab.
Actual behavior
The popup shows a single suggestion that displays as "new (leading double-quote, content up to the first space, trailing space). Pressing Enter inserts that broken string into the buffer.
Expected behavior
The popup shows new file test.csv as a suggestion. Pressing Enter inserts a properly escaped form (new\ file\ test.csv for POSIX shells, or any equivalent that the shell will parse as the single token new file test.csv).
Environment
- Warp version: v0.2026.05.13.09.15.stable_01
- OS: Linux Mint 22.2 x86_64
- Shell: zsh
Root cause
command-signatures/src/generators/git.rs:437-453 (in warpdotdev/command-signatures, pinned in warp's Cargo.toml at rev 00a032b8):
fn post_process_tracked_files(output: &str) -> GeneratorResults {
let output = filter_messages(output);
if output.starts_with("fatal:") {
return GeneratorResults::default();
}
output
.lines()
// The first non-whitespace string is just a character indicating the type of indexed file.
.filter_map(|file| file.split_whitespace().nth(1)) // <-- bug
.map(|file| {
Suggestion::with_description(file, "Changed file")
.with_priority(Priority::Global(Importance::More(Order(100))))
.with_icon(IconType::File)
})
.collect_unordered_results()
}
This post-processor consumes the output of git --no-optional-locks status --short (registered as the files_for_staging generator at line 770-775 and referenced from command-signatures/json/git.json for the git add argument).
git status --short formats lines as XY <pathname>. By default (core.quotepath=true) git C-style-quotes pathnames with special characters, so an untracked file new file test.csv produces ?? "new file test.csv". file.split_whitespace().nth(1) returns only the second whitespace-delimited token ("new), discarding the rest of the path. That truncated string flows through unchanged as both the suggestion's display value and its insertion replacement.
The existing test test_post_process_tracked_files (same file, line 968) only covers paths without spaces, which is why the regression slipped through.
Suggested fix
Switch the command to -z mode and rewrite the parser to handle the binary-safe NUL-separated format:
- Change the command to
git --no-optional-locks status --short -z. NUL terminators replace newlines and disable C-style quoting entirely.
- In the post-processor, split the output on
'\0', take everything from byte 3 of each record (skipping the fixed-width XY prefix), and skip the source-path record that follows any rename or copy entry (status starting with R or C).
NUL bytes survive the warp runtime end-to-end:
- Local subprocess executor: raw
Vec<u8> from child.output().await.
- In-band executor: hex-encoded by the bootstrap shell wrapper (
od -An -v -tx1) and hex::decoded on the warp side, so each 0x00 byte round-trips cleanly.
- TMUX executor: same
event.output: Vec<u8> pipeline as in-band.
Notes
- The fix lives in
warpdotdev/command-signatures, not warpdotdev/warp. After the command-signatures PR merges, warp's Cargo.toml pin needs to be bumped in a follow-up PR.
- A latent gap exists at
crates/warp_completer/src/completer/engine/argument/v2.rs:685-751 (warp side): script-output suggestions go through From<signatures::Suggestion> for Suggestion with no shell-escaping of the replacement. Once the generator is fixed, plain filenames with spaces will still need escaping at insertion time. That's a separate fix in warp and probably warrants its own issue.
Summary
In the Warp client,
git add <tab>returns broken suggestions for any working-tree file whose name contains a space. The completion popup shows the filename truncated at the first space (often with a stray leading"from git's C-style quoting), and selecting the suggestion inserts the truncated string into the buffer. The user cannot stage files with spaces in their names via tab completion.Reproduction
In Warp, type
git addin/tmp/reproand press Tab.Actual behavior
The popup shows a single suggestion that displays as
"new(leading double-quote, content up to the first space, trailing space). Pressing Enter inserts that broken string into the buffer.Expected behavior
The popup shows
new file test.csvas a suggestion. Pressing Enter inserts a properly escaped form (new\ file\ test.csvfor POSIX shells, or any equivalent that the shell will parse as the single tokennew file test.csv).Environment
Root cause
command-signatures/src/generators/git.rs:437-453(inwarpdotdev/command-signatures, pinned in warp'sCargo.tomlat rev00a032b8):This post-processor consumes the output of
git --no-optional-locks status --short(registered as thefiles_for_staginggenerator at line 770-775 and referenced fromcommand-signatures/json/git.jsonfor thegit addargument).git status --shortformats lines asXY <pathname>. By default (core.quotepath=true) git C-style-quotes pathnames with special characters, so an untracked filenew file test.csvproduces?? "new file test.csv".file.split_whitespace().nth(1)returns only the second whitespace-delimited token ("new), discarding the rest of the path. That truncated string flows through unchanged as both the suggestion's display value and its insertion replacement.The existing test
test_post_process_tracked_files(same file, line 968) only covers paths without spaces, which is why the regression slipped through.Suggested fix
Switch the command to
-zmode and rewrite the parser to handle the binary-safe NUL-separated format:git --no-optional-locks status --short -z. NUL terminators replace newlines and disable C-style quoting entirely.'\0', take everything from byte 3 of each record (skipping the fixed-widthXYprefix), and skip the source-path record that follows any rename or copy entry (status starting withRorC).NUL bytes survive the warp runtime end-to-end:
Vec<u8>fromchild.output().await.od -An -v -tx1) andhex::decoded on the warp side, so each0x00byte round-trips cleanly.event.output: Vec<u8>pipeline as in-band.Notes
warpdotdev/command-signatures, notwarpdotdev/warp. After the command-signatures PR merges, warp'sCargo.tomlpin needs to be bumped in a follow-up PR.crates/warp_completer/src/completer/engine/argument/v2.rs:685-751(warp side): script-output suggestions go throughFrom<signatures::Suggestion> for Suggestionwith no shell-escaping of the replacement. Once the generator is fixed, plain filenames with spaces will still need escaping at insertion time. That's a separate fix in warp and probably warrants its own issue.