Skip to content

fix(zsh): escape values without descriptions#597

Merged
jdx merged 1 commit intojdx:mainfrom
david-hamilton-glean:hjdivad/fix-zsh-usage-tasks-without-descriptions
Apr 22, 2026
Merged

fix(zsh): escape values without descriptions#597
jdx merged 1 commit intojdx:mainfrom
david-hamilton-glean:hjdivad/fix-zsh-usage-tasks-without-descriptions

Conversation

@david-hamilton-glean
Copy link
Copy Markdown
Contributor

@david-hamilton-glean david-hamilton-glean commented Apr 21, 2026

Usage v3.1.0 introduced a regression in zsh completion. Nested tasks without descriptions would fail to complete.

❯ fd . mise/tasks
mise/tasks/test/
mise/tasks/test/git.sh
mise/tasks/test/nvim.sh

# When the files lack a #MISE description=""
❯ command usage complete-word --shell zsh -f /var/folders/8s/74f40sh52hq66ghhh3c39tz80000gn/T/usage__usage_spec_mise_2026_4_18.spec -- mise run te
test:git
test:nvim

# When the files contain a #MISE description=""
❯ command usage complete-word --shell zsh -f /var/folders/8s/74f40sh52hq66ghhh3c39tz80000gn/T/usage__usage_spec_mise_2026_4_18.spec -- mise run te
test\:git:run git tests
test\:nvim:run nvim tests

Commit ae67b38 switched zsh completions to _describe, but it only escaped completion values when any descriptions were present. This meant zsh treated nested tasks as descriptions (e.g. in test:git, "git" is interpreted as the description of the item "test").

This PR fixes the issue by always escaping zsh candidates so values like test:git remain valid _describe entries even when no description is emitted.

See: https://github.com/zsh-users/zsh-completions/blob/master/zsh-completions-howto.org#writing-simple-completion-functions-using-_describe

Commit ae67b38 switched zsh completions
to `_describe` in 3.1.0, but it only escaped completion values when any
descriptions were present. Always escape zsh candidates so values like
`test:git` remain valid `_describe` entries even when no description is
emitted.

Reference: https://github.com/zsh-users/zsh-completions/blob/master/zsh-completions-howto.org#writing-simple-completion-functions-using-_describe
@david-hamilton-glean david-hamilton-glean force-pushed the hjdivad/fix-zsh-usage-tasks-without-descriptions branch from 9072f2c to 36de73e Compare April 21, 2026 23:12
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request ensures that completion words for zsh are properly escaped even when no descriptions are provided. It moves the escaping logic for the completion word outside the conditional block and adds a regression test to verify that colons are correctly escaped in this scenario. I have no feedback to provide.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9072f2c555

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cli/tests/complete_word.rs
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 21, 2026

Greptile Summary

This PR fixes a regression introduced in v3.1.0 where zsh completions would fail for nested tasks (e.g. test:git) when no descriptions were present, because zsh_escape was only applied to completion values inside the if any_descriptions block. The fix moves the zsh_escape(&c) call unconditionally before the branch, so colon-containing values are always properly escaped for _describe.

Confidence Score: 5/5

Safe to merge — the fix is minimal, correctly scoped, and covered by a new regression test.

The change is a one-line hoist of an existing escape call, no new logic is introduced, and the regression is directly tested. No P0/P1 issues found.

No files require special attention.

Important Files Changed

Filename Overview
cli/src/cli/complete_word.rs Moved zsh_escape(&c) unconditionally before the any_descriptions branch — minimal, correct fix for the regression.
cli/tests/complete_word.rs New test verifies colon-containing choices are properly escaped in zsh output when no descriptions are present.
examples/zsh-colons-without-descriptions.usage.kdl New example fixture used by the regression test; defines test:git and test:nvim choices without descriptions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[For each completion candidate c] --> B["zsh_escape(&c)  ← moved here (unconditional)"]
    B --> C{any_descriptions?}
    C -- yes --> D["zsh_escape(&description)"]
    D --> E["println!('{c}:{description}')"]
    C -- no --> F["println!('{c}')"]

    style B fill:#d4edda,stroke:#28a745
Loading

Reviews (1): Last reviewed commit: "fix(zsh): escape values without descript..." | Re-trigger Greptile

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

Codecov Report

❌ Patch coverage is 0% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 79.03%. Comparing base (79926cd) to head (36de73e).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
cli/src/cli/complete_word.rs 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #597      +/-   ##
==========================================
- Coverage   79.04%   79.03%   -0.02%     
==========================================
  Files          48       48              
  Lines        7235     7235              
  Branches     7235     7235              
==========================================
- Hits         5719     5718       -1     
+ Misses       1141     1140       -1     
- Partials      375      377       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jdx jdx merged commit a740abd into jdx:main Apr 22, 2026
9 checks passed
jdx pushed a commit that referenced this pull request Apr 22, 2026
### 🐛 Bug Fixes

- **(zsh)** escape values without descriptions by
[@david-hamilton-glean](https://github.com/david-hamilton-glean) in
[#597](#597)
- use CARGO_BIN_EXE_usage if set by
[@kybe236](https://github.com/kybe236) in
[#568](#568)

### 📚 Documentation

- add releases nav and aube lock by [@jdx](https://github.com/jdx) in
[#593](#593)
- add linux optional packages to aube lock by
[@jdx](https://github.com/jdx) in
[#594](#594)

### 📦️ Dependency Updates

- pin dtolnay/rust-toolchain action to 631a55b by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#562](#562)
- update codecov/codecov-action digest to 75cd116 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#563](#563)
- update pnpm/action-setup digest to b906aff by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#566](#566)
- update jdx/mise-action digest to 5228313 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#565](#565)
- lock file maintenance by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#569](#569)
- update dtolnay/rust-toolchain digest to 29eef33 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#571](#571)
- update swatinem/rust-cache digest to e18b497 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#572](#572)
- lock file maintenance by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#574](#574)
- lock file maintenance by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#575](#575)
- update taiki-e/upload-rust-binary-action digest to 10c1cf6 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#576](#576)
- update rust crate ctor to 0.9 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#577](#577)
- update actions/configure-pages action to v6 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#579](#579)
- update rust crate indexmap to v2.14.0 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#578](#578)
- update codecov/codecov-action action to v6 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#581](#581)
- update actions/deploy-pages action to v5 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#580](#580)
- update pnpm/action-setup action to v5 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#583](#583)
- update jdx/mise-action action to v4 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#582](#582)
- update pnpm/action-setup action to v6 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#584](#584)
- lock file maintenance by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#585](#585)
- update rust crate clap to v4.6.1 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#586](#586)
- update rust crate ctor to 0.10 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#587](#587)
- update actions/upload-pages-artifact action to v5 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#588](#588)
- update rust crate assert_cmd to v2.2.1 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#589](#589)
- update taiki-e/upload-rust-binary-action digest to f0d45ae by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#590](#590)
- update dependency eslint to v10.2.1 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#591](#591)
- update pnpm/action-setup digest to 078e9d4 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#592](#592)
- lock file maintenance by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#595](#595)

### New Contributors

- @david-hamilton-glean made their first contribution in
[#597](#597)
- @kybe236 made their first contribution in
[#568](#568)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Apr 22, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [usage](https://github.com/jdx/usage) | patch | `3.2.0` → `3.2.1` |

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>

### [`v3.2.1`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#321---2026-04-22)

[Compare Source](jdx/usage@v3.2.0...v3.2.1)

##### 🐛 Bug Fixes

- **(zsh)** escape values without descriptions by [@&#8203;david-hamilton-glean](https://github.com/david-hamilton-glean) in [#&#8203;597](jdx/usage#597)
- use CARGO\_BIN\_EXE\_usage if set by [@&#8203;kybe236](https://github.com/kybe236) in [#&#8203;568](jdx/usage#568)

##### 📚 Documentation

- add releases nav and aube lock by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;593](jdx/usage#593)
- add linux optional packages to aube lock by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;594](jdx/usage#594)

##### 📦️ Dependency Updates

- pin dtolnay/rust-toolchain action to [`631a55b`](jdx/usage@631a55b) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;562](jdx/usage#562)
- update codecov/codecov-action digest to [`75cd116`](jdx/usage@75cd116) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;563](jdx/usage#563)
- update pnpm/action-setup digest to [`b906aff`](jdx/usage@b906aff) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;566](jdx/usage#566)
- update jdx/mise-action digest to [`5228313`](jdx/usage@5228313) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;565](jdx/usage#565)
- lock file maintenance by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;569](jdx/usage#569)
- update dtolnay/rust-toolchain digest to [`29eef33`](jdx/usage@29eef33) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;571](jdx/usage#571)
- update swatinem/rust-cache digest to [`e18b497`](jdx/usage@e18b497) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;572](jdx/usage#572)
- lock file maintenance by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;574](jdx/usage#574)
- lock file maintenance by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;575](jdx/usage#575)
- update taiki-e/upload-rust-binary-action digest to [`10c1cf6`](jdx/usage@10c1cf6) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;576](jdx/usage#576)
- update rust crate ctor to 0.9 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;577](jdx/usage#577)
- update actions/configure-pages action to v6 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;579](jdx/usage#579)
- update rust crate indexmap to v2.14.0 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;578](jdx/usage#578)
- update codecov/codecov-action action to v6 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;581](jdx/usage#581)
- update actions/deploy-pages action to v5 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;580](jdx/usage#580)
- update pnpm/action-setup action to v5 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;583](jdx/usage#583)
- update jdx/mise-action action to v4 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;582](jdx/usage#582)
- update pnpm/action-setup action to v6 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;584](jdx/usage#584)
- lock file maintenance by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;585](jdx/usage#585)
- update rust crate clap to v4.6.1 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;586](jdx/usage#586)
- update rust crate ctor to 0.10 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;587](jdx/usage#587)
- update actions/upload-pages-artifact action to v5 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;588](jdx/usage#588)
- update rust crate assert\_cmd to v2.2.1 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;589](jdx/usage#589)
- update taiki-e/upload-rust-binary-action digest to [`f0d45ae`](jdx/usage@f0d45ae) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;590](jdx/usage#590)
- update dependency eslint to v10.2.1 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;591](jdx/usage#591)
- update pnpm/action-setup digest to [`078e9d4`](jdx/usage@078e9d4) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;592](jdx/usage#592)
- lock file maintenance by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;595](jdx/usage#595)

##### New Contributors

- [@&#8203;david-hamilton-glean](https://github.com/david-hamilton-glean) made their first contribution in [#&#8203;597](jdx/usage#597)
- [@&#8203;kybe236](https://github.com/kybe236) made their first contribution in [#&#8203;568](jdx/usage#568)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever MR is behind base branch, 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:eyJjcmVhdGVkSW5WZXIiOiI0My4xMzYuMiIsInVwZGF0ZWRJblZlciI6IjQzLjEzNi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6cGF0Y2giXX0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants