Fix zsh tab-completion dropping basename for nested file paths (#10358)#10535
Fix zsh tab-completion dropping basename for nested file paths (#10358)#10535maxmilian wants to merge 4 commits intowarpdotdev:masterfrom
Conversation
The bundled compadd override emitted only the basename via OSC, dropping
zsh's $IPREFIX (the path prefix accumulated by recursive completion such
as _path_files) and the parsed-but-unused -p hidden prefix. When the
user typed `git add some/nested/folder1/<TAB>` the OSC payload contained
only `file1.txt`, which the Rust filter then dropped because it did not
prefix-match the slashy query token, leaving completion silently stuck.
Prepending $IPREFIX and ${hpre[2]} restores the full insertion text so
the candidate matches the query and is offered to the user. Both
expand to empty when not set, leaving plain command/option completion
unaffected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR updates the zsh compadd override so file completion OSC payloads include path prefixes, and adds a contract-level Rust regression test for filtering full-path replacements.
Concerns
- The new hidden-prefix handling does not actually include
compadd -pvalues becausehpreis declared as an associative array, sohpre[2]looks up key2rather than the parsed-pvalue.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| # it does not prefix-match the slashy query token. See issue #10358. | ||
| # When neither IPREFIX nor -p is set both expand to empty strings, so | ||
| # plain command/option completion is unaffected. | ||
| local match="$IPREFIX${hpre[2]}$__hits[$i]$dsuf" |
There was a problem hiding this comment.
hpre is declared as an associative array, so ${hpre[2]} looks up key 2 and stays empty for compadd -p; use the -p entry (for example ${hpre[-p]}) or the single parsed value so hidden-prefix completions are not still emitted without their prefix.
There was a problem hiding this comment.
Verified locally — hpre is not associative. The compadd override calls zparseopts -E -a extra_args - … p:=hpre … (line 1233), and zparseopts only produces an associative array when given -A. Without it, p:=hpre produces an indexed array where [1] is the flag and [2] is its value:
$ zsh -c '
> set -- -p some/nested/folder1/ extra
> zparseopts -E -a extra_args - p:=hpre
> typeset -p hpre
> echo "[1]=<${hpre[1]}> [2]=<${hpre[2]}> [-p]=<${hpre[-p]:-EMPTY}>"
> '
typeset -a hpre=( -p some/nested/folder1/ )
[1]=<-p> [2]=<some/nested/folder1/> [-p]=<EMPTY>
So ${hpre[2]} correctly returns the value when -p is present and an empty string otherwise; the suggested ${hpre[-p]} would always expand to empty here.
If hpre were ever switched to an associative array (-A), this fix would need to update accordingly, but that's a hypothetical change beyond this PR's scope.
|
/oz-review |
|
I'm re-reviewing this pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR updates the zsh compadd override to include $IPREFIX and compadd's hidden prefix in emitted completion candidates, plus adds a warp_completer filter-contract regression test for nested path completions.
Concerns
- The new full-path match is assembled after
dsufis computed from the bare basename, so nested directory candidates can be retained but still lose their trailing/. - Manual end-to-end evidence is missing for a user-visible tab-completion behavior change; please include a screen recording or manual test details showing nested zsh path completion working, or justify why manual testing is not possible.
Verdict
Found: 0 critical, 2 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| # it does not prefix-match the slashy query token. See issue #10358. | ||
| # When neither IPREFIX nor -p is set both expand to empty strings, so | ||
| # plain command/option completion is unaffected. | ||
| local match="$IPREFIX${hpre[2]}$__hits[$i]$dsuf" |
There was a problem hiding this comment.
dsuf is still based on the unprefixed basename, so nested directories under $IPREFIX can be emitted without the trailing /; compute the prefixed path before the -d check so directory completions remain chainable.
Addresses Oz review on warpdotdev#10535: dsuf was computed from the bare basename ($__hits[$i]), so when zsh's _path_files walks a nested path and our override runs from a CWD where the bare basename does not exist, the trailing `/` was dropped from directory candidates and the user could not chain another tab. Compute the prefixed path ($IPREFIX${hpre[2]}$basename) once and use it for both the existence test and the emitted match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed both concerns from the second review (commit ee81fdc): Concern 1 — Fix: compute the prefixed path once, use it for both the Concern 2 — manual end-to-end evidence. Acknowledged. The change is in /oz-review |
|
I'm re-reviewing this pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR updates the zsh compadd override to include the consumed path prefix in emitted completion replacements and adds a Rust filter-contract regression test for nested file path completions.
Concerns
- Manual testing evidence is missing for a user-visible shell completion behavior change. Manual testing is required for changes that can be manually tested; please include screenshots or a screen recording that show nested zsh path completion working end to end, or justify why manual testing is not possible.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
|
Manual end-to-end recording (per Oz's third review concern). Repro from issue #10358 — typing /oz-review PR10535.mp4 |
|
I'm re-reviewing this pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
Reviewed the zsh compadd override change and the Rust regression test for nested path completion. The PR addresses the right shell-side path reconstruction point, and no security-specific findings were identified.
Concerns
- The new hidden-prefix lookup uses a numeric subscript on an associative array, so
compadd -pprefixes are still dropped instead of being prepended. - The regression test does not mirror the current
ShellCompletioningestion path, where the OSC payload becomes both display and replacement with nofile_type.
Verdict
Found: 0 critical, 1 important, 1 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| # then drops because it does not prefix-match the slashy query token. | ||
| # See issue #10358. Both expand to empty when not set, so plain | ||
| # command/option completion is unaffected. | ||
| full="$IPREFIX${hpre[2]}$__hits[$i]" |
There was a problem hiding this comment.
hpre is declared as an associative array, so zparseopts ... p:=hpre stores the -p argument as the value for key -p; ${hpre[2]} stays empty and hidden prefixes are still dropped.
| full="$IPREFIX${hpre[2]}$__hits[$i]" | |
| full="$IPREFIX$hpre$__hits[$i]" |
| override_icon: None, | ||
| priority: super::Priority::default(), | ||
| is_hidden: false, | ||
| file_type: Some(EngineFileType::File), |
There was a problem hiding this comment.
💡 [SUGGESTION] This constructs a file-engine suggestion with basename display/full-path replacement, but shell completions currently enter through ShellCompletion::new / Suggestion::with_same_display_and_replacement, leaving file_type unset and display equal to replacement; add a case that mirrors that ingestion path so the test covers the actual OSC contract.
`hpre` is declared with `typeset -A` (associative array), so
`zparseopts ... p:=hpre` stores the -p argument under the literal `-p`
key. The previous `${hpre[2]}` expansion always evaluated to empty,
meaning the hidden-prefix portion of the fix never took effect — the
nested-path repro happened to work only because it routes through
`$IPREFIX`. Any completion path relying on `compadd -p` would still
have dropped the hidden prefix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… test Use Suggestion::with_same_display_and_replacement so display == replacement and file_type is None — matching how the OSC 9280;C payload is actually ingested. Previous form constructed a Suggestion literal with distinct display/replacement and file_type=Some(File), which did not reflect the runtime path the fix lives on. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed both points from the latest review (commits Concern 1 — - full="$IPREFIX${hpre[2]}$__hits[$i]"
+ full="$IPREFIX${hpre[-p]}$__hits[$i]"Comment block updated to spell out the associative-array reason so this doesn't regress. Concern 2 (suggestion) — regression test didn't mirror PR description updated to match. /oz-review |
Description
Fixes #10358. On macOS zsh, completing nested file paths silently fails: typing
git add some/nested/folder1/<TAB>does not insertfile1.txteven when it's the only file.app/assets/bundled/bootstrap/zsh_body.shoverridescompaddto capture completion candidates and emit them via OSC9280;C. zsh's_path_fileswalks nested directories, accumulates the consumed prefix into$IPREFIX, and ends up callingcompadd file1.txt(basename only). The override emitted only the basename, so the OSC payload wasfile1.txtwhile the user-typed token wassome/nested/folder1/. The Rust suggestion filter could not prefix-match the basename against the slashy query and silently dropped the candidate.The override already parsed compadd's
-phidden-prefix flag intohpre(line 1233) but never used it.Fix: prepend
$IPREFIXand${hpre[-p]}to the emitted match. Both expand to empty when not set, so plain command/option completion is unaffected.Note on the
[-p]key:hpreis declared withtypeset -A(associative array), sozparseopts ... p:=hprestores the-pargument under the literal-pkey — not the numeric index2(that form only applies to plain arrays). An earlier revision of this PR used${hpre[2]}, which silently expanded to empty; the nested-path repro happened to work only because it routes through$IPREFIX. Any completion path relying oncompadd -pwould still have dropped the hidden prefix.Known trade-off
The OSC
C;payload is currently mapped to bothdisplayandreplacement(Suggestion::with_same_display_and_replacement), so the dropdown will now show the full path (e.g.some/nested/folder1/file1.txt) instead of just the basename. Functionality is restored; cleaner UX (basename in dropdown, full path on accept) would require sending display and replacement separately and is left as a follow-up.Linked Issue
Fixes #10358 (label:
ready-to-implement).ready-to-specorready-to-implement.Testing
Added a regression test in
crates/warp_completer/src/completer/suggest/test.rs(test_filter_by_query_retains_file_with_full_path_replacement_after_iprefix_fix). It exercisesfilter_by_querywith both the post-fix OSC payload (full path → retained) and the pre-fix payload (bare basename → dropped), pinning the filter contract that the shell-side fix relies on. Doc comment is explicit that this is a contract-level regression test, not E2E (theShellCompletioningestion path lives in theappcrate).The 11 pre-existing
FeatureFlag::CloudEnvironmentspanics incrates/warp_features/src/lib.rs:988reproduce onmasterand are unrelated to this change../script/runAgent Mode
CHANGELOG-BUG-FIX: Fix zsh tab-completion failing to insert filenames inside nested directory paths