fix: match completion prefix against unescaped names#460
Conversation
When using `complete ... descriptions=#true`, prefix matching was done against escaped strings (e.g., `test\:integration`) instead of unescaped names (`test:integration`). This caused completions to fail when user input contained an unescaped colon. Fix by moving the filter to after the map that unescapes the names. This bug caused a problem with mise: there was no shell completion if you entered `mise test:i<tab>` even if there was a `test:integration` task. `mise run test:i<tab>` was *not* affected, that is treated differently by `mise`'s `usage` spec.
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug where shell completion prefix matching failed when completion names contained colons. The issue occurred because filtering was performed on escaped strings (e.g., test\:integration) before unescaping, causing user input like test: to not match.
Changes:
- Moved the prefix filter operation to after the unescaping step in
complete_word.rs - Added a comprehensive test case with an example usage file to verify colon handling in completions
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| cli/src/cli/complete_word.rs | Repositioned the filter to match against unescaped completion names |
| cli/tests/complete_word.rs | Added test function to verify prefix matching works with escaped colons |
| examples/colon-in-completions.usage.kdl | Added example usage configuration demonstrating colon-containing completions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // Empty input should match all completions | ||
| assert_cmd("colon-in-completions.usage.kdl", &["--", "run", ""]) | ||
| .stdout("'test\\\\:unit'\\:'Run unit tests'\n'test\\\\:integration'\\:'Run integration tests'\n'build'\\:'Build the project'\n"); |
There was a problem hiding this comment.
This assertion line exceeds typical line length limits (appears to be >120 characters). Consider breaking it into multiple lines for better readability, similar to how the other assertions in this test are formatted.
| .stdout("'test\\\\:unit'\\:'Run unit tests'\n'test\\\\:integration'\\:'Run integration tests'\n'build'\\:'Build the project'\n"); | |
| .stdout(concat!( | |
| "'test\\\\:unit'\\:'Run unit tests'\n", | |
| "'test\\\\:integration'\\:'Run integration tests'\n", | |
| "'build'\\:'Build the project'\n", | |
| )); |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #460 +/- ##
=======================================
Coverage 76.73% 76.73%
=======================================
Files 47 47
Lines 6250 6250
Branches 6250 6250
=======================================
Hits 4796 4796
Misses 1102 1102
Partials 352 352 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
bugbot run |
### 🚀 Features - **(lint)** add more lint checks by [@jdx](https://github.com/jdx) in [#446](#446) - add logo to docs site by [@jdx](https://github.com/jdx) in [#442](#442) - add VT323 retro terminal font and --usage branding by [@jdx](https://github.com/jdx) in [#443](#443) - add missing builder methods by [@jdx](https://github.com/jdx) in [#444](#444) ### 🐛 Bug Fixes - use pithy LLM-generated title for GitHub releases by [@jdx](https://github.com/jdx) in [#441](#441) - replace unwrap calls with proper error handling in fig.rs by [@jdx](https://github.com/jdx) in [#454](#454) - improve error messages with more context by [@jdx](https://github.com/jdx) in [#449](#449) - skip powershell test if pwsh is not installed by [@jdx](https://github.com/jdx) in [#457](#457) - match completion prefix against unescaped names by [@ilyagr](https://github.com/ilyagr) in [#460](#460) ### 🚜 Refactor - simplify Spec::merge with local macros by [@jdx](https://github.com/jdx) in [#451](#451) ### 📚 Documentation - add CLAUDE.md for Claude Code guidance by [@jdx](https://github.com/jdx) in [#452](#452) - escape generic type parameters in macro doc comments by [@jdx](https://github.com/jdx) in [#453](#453) - add rustdoc for public API functions by [@jdx](https://github.com/jdx) in [#450](#450) - add documentation to public API structs by [@jdx](https://github.com/jdx) in [#455](#455) - add conventional commit guidance to CLAUDE.md by [@jdx](https://github.com/jdx) in [#459](#459) ### ⚡ Performance - remove unnecessary clone in set_subcommand_ancestors by [@jdx](https://github.com/jdx) in [#448](#448) ### 🧪 Testing - add test coverage for untested modules by [@jdx](https://github.com/jdx) in [#447](#447) ### 🔍 Other Changes - remove commented-out trait implementations in mount.rs by [@jdx](https://github.com/jdx) in [#445](#445) - make codecov checks informational by [@jdx](https://github.com/jdx) in [#456](#456) ### 📦️ Dependency Updates - lock file maintenance by [@renovate[bot]](https://github.com/renovate[bot]) in [#439](#439) ### New Contributors - @ilyagr made their first contribution in [#460](#460)
As previously advertised in #460. This is purely a refactor, the tests are functionally unchanged. ------------- Fish's completion output format uses tabs between name and description, and doesn't require quoting or escaping colons. This makes test assertions much more readable: Before (zsh): `"'task-a'\\:'Task from default dir'"` After (fish): `"task-a\tTask from default dir"` This is especially valuable for completions containing colons, where zsh's escaping becomes nearly unreadable: Before (zsh): `"'test\\\\:unit'\\:'Run unit tests'"` After (fish): `"test:unit\tRun unit tests"` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Refactors CLI completion tests to use fish’s output format for simpler assertions. > > - Switches `cli/tests/complete_word.rs` from zsh to `--shell fish` (via `cmd(...)` and `assert_cmd(...)`), updating specific tests accordingly > - Updates expected outputs: removes quoting/escaping, uses plain names and tab-delimited `name description` where applicable > - Adjusts predicates from quoted matches to unquoted (e.g., `contains("install")`), and updates file/special cases (colons, flags, files) to fish formatting > - No production code changes > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 3fe0751. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Ilya Grigoriev <ilyagr@users.noreply.github.com>
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [usage](https://github.com/jdx/usage) | minor | `2.13.1` → `2.15.0` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>jdx/usage (usage)</summary> ### [`v2.15.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#2150---2026-01-26) [Compare Source](jdx/usage@v2.14.0...v2.15.0) ##### 🚀 Features - **(parse)** add Parser builder for custom env var handling by [@​jdx](https://github.com/jdx) in [#​464](jdx/usage#464) ##### 🧪 Testing - **(cli)** use fish output format for cleaner assertions by [@​ilyagr](https://github.com/ilyagr) in [#​461](jdx/usage#461) ##### 🔍 Other Changes - add cargo-semver-checks to detect breaking changes by [@​jdx](https://github.com/jdx) in [#​463](jdx/usage#463) ### [`v2.14.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#2140---2026-01-26) [Compare Source](jdx/usage@v2.13.1...v2.14.0) ##### 🚀 Features - **(lint)** add more lint checks by [@​jdx](https://github.com/jdx) in [#​446](jdx/usage#446) - add logo to docs site by [@​jdx](https://github.com/jdx) in [#​442](jdx/usage#442) - add VT323 retro terminal font and --usage branding by [@​jdx](https://github.com/jdx) in [#​443](jdx/usage#443) - add missing builder methods by [@​jdx](https://github.com/jdx) in [#​444](jdx/usage#444) ##### 🐛 Bug Fixes - use pithy LLM-generated title for GitHub releases by [@​jdx](https://github.com/jdx) in [#​441](jdx/usage#441) - replace unwrap calls with proper error handling in fig.rs by [@​jdx](https://github.com/jdx) in [#​454](jdx/usage#454) - improve error messages with more context by [@​jdx](https://github.com/jdx) in [#​449](jdx/usage#449) - skip powershell test if pwsh is not installed by [@​jdx](https://github.com/jdx) in [#​457](jdx/usage#457) - match completion prefix against unescaped names by [@​ilyagr](https://github.com/ilyagr) in [#​460](jdx/usage#460) ##### 🚜 Refactor - simplify Spec::merge with local macros by [@​jdx](https://github.com/jdx) in [#​451](jdx/usage#451) ##### 📚 Documentation - add CLAUDE.md for Claude Code guidance by [@​jdx](https://github.com/jdx) in [#​452](jdx/usage#452) - escape generic type parameters in macro doc comments by [@​jdx](https://github.com/jdx) in [#​453](jdx/usage#453) - add rustdoc for public API functions by [@​jdx](https://github.com/jdx) in [#​450](jdx/usage#450) - add documentation to public API structs by [@​jdx](https://github.com/jdx) in [#​455](jdx/usage#455) - add conventional commit guidance to CLAUDE.md by [@​jdx](https://github.com/jdx) in [#​459](jdx/usage#459) ##### ⚡ Performance - remove unnecessary clone in set\_subcommand\_ancestors by [@​jdx](https://github.com/jdx) in [#​448](jdx/usage#448) ##### 🧪 Testing - add test coverage for untested modules by [@​jdx](https://github.com/jdx) in [#​447](jdx/usage#447) ##### 🔍 Other Changes - remove commented-out trait implementations in mount.rs by [@​jdx](https://github.com/jdx) in [#​445](jdx/usage#445) - make codecov checks informational by [@​jdx](https://github.com/jdx) in [#​456](jdx/usage#456) ##### 📦️ Dependency Updates - lock file maintenance by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​439](jdx/usage#439) ##### New Contributors - [@​ilyagr](https://github.com/ilyagr) made their first contribution in [#​460](jdx/usage#460) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi45MC4wIiwidXBkYXRlZEluVmVyIjoiNDIuOTIuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6Om1pbm9yIl19-->
When using
complete ... descriptions=#true, prefix matching was done against escaped strings (e.g.,test\:integration) instead of unescaped names (test:integration). This caused completions to fail when user input contained an unescaped colon.Fix by moving the filter to after the map that unescapes the names.
This bug caused a problem with mise: there was no shell completion if you entered
mise test:i<tab>even if there was atest:integrationtask.mise run test:i<tab>was not affected, that is treated differently bymise'susagespec.I feel that the test could be more readable, I might do that in a subsequent PR. I think all
complete_wordtests could use the fish syntax instead of the zsh syntax, so e.g.Let me know if you prefer I do that refactor first to make the diff here more readable (but it's not that bad)
Update: Apparently, that'd also make Copilot happer. Here's a draft: ilyagr@fish-refactor . Again, I'm happy to reorder the commits so that the cleaner syntax comes first. The biggest win from the refactor is in the test added in this PR, but others are also easier to read IMO for somebody unfamiliar with either shell's syntax.
This was mostly debugged by AI. If the fix is not correct, it could be considered a bug report (but it seems good to me).
Note
Fixes completion prefix matching when
complete ... descriptions=#trueby filtering after unescapingname:descriptionoutputs.complete_word.rs, process command output lines first (unescape and split) then filter byctoken, so prefixes match unescaped names containing colonscomplete_word_escaped_colons_in_completionsand examplecolon-in-completions.usage.kdlto validate colon-containing completionsWritten by Cursor Bugbot for commit e24490f. This will update automatically on new commits. Configure here.