feat(cli): render all doc-related fields in --help output#554
Conversation
…tput These doc-related fields were only used in manpage and markdown docs but not in script --help/-h output. Now the CLI help templates render them. Closes #549 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly improves the user experience of the command-line interface by integrating more comprehensive and structured help documentation. It allows developers to provide richer contextual information and practical usage examples directly within the CLI's help output, making the tools easier to understand and use without external documentation. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request enhances the CLI help output by including before_help, after_help, and examples sections. The changes correctly handle short and long help variants, with appropriate fallbacks. The new unit tests provide good coverage for the added functionality. My review focuses on improving the maintainability of the Tera templates by reducing code duplication. I've suggested refactoring the conditional logic for rendering these new sections to make the templates more concise and easier to maintain.
| {%- if cmd.before_help_long %}{{ cmd.before_help_long }} | ||
|
|
||
| {% elif cmd.before_help %}{{ cmd.before_help }} | ||
|
|
||
| {% elif spec.before_help_long %}{{ spec.before_help_long }} | ||
|
|
||
| {% elif spec.before_help %}{{ spec.before_help }} | ||
|
|
||
| {% endif -%} |
There was a problem hiding this comment.
The logic for selecting and rendering before_help text can be simplified to improve readability and reduce repetition. By using Tera's default filter, you can create a chain of fallbacks and then render the result in a single block. This makes the template more concise.
{%- set text = cmd.before_help_long | default(value=cmd.before_help) | default(value=spec.before_help_long) | default(value=spec.before_help) -%}
{%- if text %}{{ text }}
{% endif -%}
| {%- if cmd.examples %} | ||
|
|
||
| Examples: | ||
| {%- for example in cmd.examples %} | ||
| {%- if example.header %} | ||
| {{ example.header }}: | ||
| {%- endif %} | ||
| {%- if example.help %} | ||
| {{ example.help }} | ||
| {%- endif %} | ||
| $ {{ example.code }} | ||
| {%- endfor %} | ||
| {%- elif spec.examples %} | ||
|
|
||
| Examples: | ||
| {%- for example in spec.examples %} | ||
| {%- if example.header %} | ||
| {{ example.header }}: | ||
| {%- endif %} | ||
| {%- if example.help %} | ||
| {{ example.help }} | ||
| {%- endif %} | ||
| $ {{ example.code }} | ||
| {%- endfor %} | ||
| {%- endif %} |
There was a problem hiding this comment.
The logic for rendering examples for cmd and spec is duplicated. You can reduce this duplication by first determining which set of examples to use (cmd.examples or spec.examples) and then using a single loop to render them. This improves maintainability as any future changes to the example format will only need to be made in one place.
{%- set examples = cmd.examples -%}
{%- if not examples %}{%- set examples = spec.examples %}{%- endif -%}
{%- if examples %}
Examples:
{%- for example in examples %}
{%- if example.header %}
{{ example.header }}:
{%- endif %}
{%- if example.help %}
{{ example.help }}
{%- endif %}
$ {{ example.code }}
{%- endfor %}
{%- endif %}
| {%- if cmd.after_help_long %} | ||
|
|
||
| {{ cmd.after_help_long }} | ||
| {%- elif cmd.after_help %} | ||
|
|
||
| {{ cmd.after_help }} | ||
| {%- elif spec.after_help_long %} | ||
|
|
||
| {{ spec.after_help_long }} | ||
| {%- elif spec.after_help %} | ||
|
|
||
| {{ spec.after_help }} | ||
| {%- endif -%} |
There was a problem hiding this comment.
Similar to before_help, the logic for after_help can be simplified using Tera's default filter to create a fallback chain. This will make the template more concise and easier to read.
{%- set text = cmd.after_help_long | default(value=cmd.after_help) | default(value=spec.after_help_long) | default(value=spec.after_help) -%}
{%- if text %}
{{ text }}
{%- endif -%}
| {%- if cmd.before_help %}{{ cmd.before_help }} | ||
|
|
||
| {% endif %} | ||
| {% elif spec.before_help %}{{ spec.before_help }} | ||
|
|
||
| {% endif -%} |
There was a problem hiding this comment.
The logic for selecting and rendering before_help text can be simplified. Using Tera's default filter provides a more concise way to handle the fallback from cmd.before_help to spec.before_help.
{%- set text = cmd.before_help | default(value=spec.before_help) -%}
{%- if text %}{{ text }}
{% endif -%}
| {%- if cmd.examples %} | ||
|
|
||
| Examples: | ||
| {%- for example in cmd.examples %} | ||
| {%- if example.header %} | ||
| {{ example.header }}: | ||
| {%- endif %} | ||
| $ {{ example.code }} | ||
| {%- endfor %} | ||
| {%- elif spec.examples %} | ||
|
|
||
| Examples: | ||
| {%- for example in spec.examples %} | ||
| {%- if example.header %} | ||
| {{ example.header }}: | ||
| {%- endif %} | ||
| $ {{ example.code }} | ||
| {%- endfor %} | ||
| {%- endif %} |
There was a problem hiding this comment.
There is duplicated logic for rendering examples from cmd.examples and spec.examples. This can be refactored to first select the appropriate list of examples and then iterate over it, avoiding code repetition and improving maintainability.
{%- set examples = cmd.examples -%}
{%- if not examples %}{%- set examples = spec.examples %}{%- endif -%}
{%- if examples %}
Examples:
{%- for example in examples %}
{%- if example.header %}
{{ example.header }}:
{%- endif %}
$ {{ example.code }}
{%- endfor %}
{%- endif %}
| {%- if cmd.after_help %} | ||
|
|
||
| {{ cmd.after_help }} | ||
| {%- elif spec.after_help %} | ||
|
|
||
| {{ spec.after_help }} | ||
| {%- endif -%} |
There was a problem hiding this comment.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #554 +/- ##
==========================================
+ Coverage 72.40% 72.98% +0.58%
==========================================
Files 48 48
Lines 6830 6970 +140
Branches 6830 6970 +140
==========================================
+ Hits 4945 5087 +142
+ Misses 1242 1236 -6
- Partials 643 647 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- Show name + version header at the top of both short and long help - Show author and license in long help footer - Show [deprecated: reason] marker on subcommands in both templates - Add tests for all new fields Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Greptile SummaryThis PR wires Key observations:
Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[render_help called] --> B{long?}
B -- yes --> C[spec_template_long.tera]
B -- no --> D[spec_template_short.tera]
C --> E{cmd.before_help_long?}
E -- yes --> F[render cmd.before_help_long]
E -- no --> G{cmd.before_help?}
G -- yes --> H[render cmd.before_help]
G -- no --> I{spec.before_help_long?}
I -- yes --> J[render spec.before_help_long]
I -- no --> K{spec.before_help?}
K -- yes --> L[render spec.before_help]
K -- no --> M[no before_help]
D --> N{cmd.before_help?}
N -- yes --> O[render cmd.before_help]
N -- no --> P{spec.before_help?}
P -- yes --> Q[render spec.before_help]
P -- no --> R[no before_help]
C --> S[version / about / usage / subcommands / args / flags]
D --> S
C --> T{examples on cmd or spec?}
D --> T
T -- yes --> U[render Examples section]
T -- no --> V[skip]
C --> W{cmd/spec after_help_long or after_help?}
W -- yes --> X[render after_help long then short template]
D --> Y{cmd/spec after_help?}
Y -- yes --> Z[render after_help short template]
C --> AA{spec.author or spec.license?}
AA -- yes --> AB[render Author / License footer]
Reviews (1): Last reviewed commit: "feat(cli): add version, author, license,..." | Re-trigger Greptile |
| {%- if spec.author or spec.license %} | ||
| {% if spec.author %} | ||
| Author: {{ spec.author }} | ||
| {%- endif %} |
There was a problem hiding this comment.
Inconsistent whitespace trimming on inner
if
{% if spec.author %} on line 131 does not use the {%- trim prefix, unlike every other conditional in this template. This is intentional here (it preserves the blank line added by the outer {%- if spec.author or spec.license %} close), but it means the blank-line semantics differ between the only-author and only-license cases:
- only
author:\n(end of line 130) +\n(end of line 131 after{% if %}), thenAuthor: …→ two newlines = correct blank line. - only
license:\n(end of line 130), then{% if spec.author %}false (inner\nis skipped), then{%- if spec.license %}trims NODE5\n→ only\n(NODE6) remains, producing just a single newline rather than a blank line beforeLicense:.
The existing test (test_render_help_with_author_license) exercises only the both set case, so the edge case is unverified. Consider adding a {%- to the inner tag and adjusting the surrounding blank-line logic, or add tests for the single-field cases to lock in the intended output.
| {%- if spec.author or spec.license %} | |
| {% if spec.author %} | |
| Author: {{ spec.author }} | |
| {%- endif %} | |
| {%- if spec.author or spec.license %} | |
| {%- if spec.author %} | |
| Author: {{ spec.author }} | |
| {%- endif %} | |
| {%- if spec.license %} | |
| License: {{ spec.license }} | |
| {%- endif %} | |
| {%- endif -%} |
| #[test] | ||
| fn test_render_help_with_deprecated_command() { | ||
| let spec = crate::spec! { r#" | ||
| bin "testcli" | ||
| cmd "old-cmd" help="Do something" deprecated="use new-cmd instead" | ||
| cmd "new-cmd" help="Do something better" | ||
| "# } | ||
| .unwrap(); | ||
|
|
||
| assert_snapshot!(render_help(&spec, &spec.cmd, false), @r" | ||
| Usage: testcli <SUBCOMMAND> | ||
|
|
||
| Commands: | ||
| new-cmd Do something better | ||
| old-cmd [deprecated: use new-cmd instead] Do something | ||
| help Print this message or the help of the given subcommand(s) | ||
| "); | ||
| } |
There was a problem hiding this comment.
Long-help deprecated snapshot missing
test_render_help_with_deprecated_command only asserts on the short (-h) output. The long template renders deprecated differently — the help text is indented on a new line rather than being inline:
old-cmd [deprecated: use new-cmd instead]
Do something
A render_help(&spec, &spec.cmd, true) snapshot would lock in that formatting and prevent regressions.
### 🚀 Features - **(cli)** render all doc-related fields in --help output by [@jdx](https://github.com/jdx) in [#554](#554) - **(cli)** support reading spec from stdin via --file - by [@jdx](https://github.com/jdx) in [#555](#555) ### 🐛 Bug Fixes - **(zsh)** remove trailing space from completions and add directory slash by [@jdx](https://github.com/jdx) in [#556](#556) - use field assignment for non-exhaustive Spec in benchmarks by [@jdx](https://github.com/jdx) in [#552](#552) ### 📦️ Dependency Updates - update apple-actions/import-codesign-certs digest to fe74d46 by [@renovate[bot]](https://github.com/renovate[bot]) in [#550](#550) - update codecov/codecov-action digest to 1af5884 by [@renovate[bot]](https://github.com/renovate[bot]) in [#551](#551) - lock file maintenance by [@renovate[bot]](https://github.com/renovate[bot]) in [#547](#547)
⚠️ **CAUTION: this is a major update, indicating a breaking change!**⚠️ This MR contains the following updates: | Package | Update | Change | |---|---|---| | [usage](https://github.com/jdx/usage) | major | `2.18.2` → `3.2.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> ### [`v3.2.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#320---2026-03-23) [Compare Source](jdx/usage@v3.1.0...v3.2.0) ##### 🚀 Features - Support env-backed choices with `choices env=...` by [@​mustafa0x](https://github.com/mustafa0x) in [#​548](jdx/usage#548) ##### 🐛 Bug Fixes - **(zsh)** escape parentheses and brackets in completion descriptions by [@​jdx](https://github.com/jdx) in [#​559](jdx/usage#559) ##### New Contributors - [@​mustafa0x](https://github.com/mustafa0x) made their first contribution in [#​548](jdx/usage#548) ### [`v3.1.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#310---2026-03-22) [Compare Source](jdx/usage@v3.0.0...v3.1.0) ##### 🚀 Features - **(cli)** render all doc-related fields in --help output by [@​jdx](https://github.com/jdx) in [#​554](jdx/usage#554) - **(cli)** support reading spec from stdin via --file - by [@​jdx](https://github.com/jdx) in [#​555](jdx/usage#555) ##### 🐛 Bug Fixes - **(zsh)** remove trailing space from completions and add directory slash by [@​jdx](https://github.com/jdx) in [#​556](jdx/usage#556) - use field assignment for non-exhaustive Spec in benchmarks by [@​jdx](https://github.com/jdx) in [#​552](jdx/usage#552) ##### 📦️ Dependency Updates - update apple-actions/import-codesign-certs digest to [`fe74d46`](jdx/usage@fe74d46) by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​550](jdx/usage#550) - update codecov/codecov-action digest to [`1af5884`](jdx/usage@1af5884) by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​551](jdx/usage#551) - lock file maintenance by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​547](jdx/usage#547) ### [`v3.0.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#300---2026-03-13) [Compare Source](jdx/usage@v2.18.2...v3.0.0) ##### 🚀 Features - **(spec)** **breaking** add support for license, before/after help metadata by [@​jdx](https://github.com/jdx) in [#​542](jdx/usage#542) ##### 🐛 Bug Fixes - **(cobra)** escape newlines, tabs, and carriage returns in kdlQuoteAlways by [@​thecodesmith](https://github.com/thecodesmith) in [#​539](jdx/usage#539) - bump major version for breaking changes in release automation by [@​jdx](https://github.com/jdx) in [#​544](jdx/usage#544) - add custom\_major\_increment\_regex for breaking change detection by [@​jdx](https://github.com/jdx) in [#​545](jdx/usage#545) - handle all breaking change commit formats in major bump regex by [@​jdx](https://github.com/jdx) in [27e1ab1](jdx/usage@27e1ab1) - normalize breaking change commit format in preprocessor by [@​jdx](https://github.com/jdx) in [aa72b92](jdx/usage@aa72b92) ##### 📚 Documentation - add argparse-usage integration by [@​jdx](https://github.com/jdx) in [#​531](jdx/usage#531) - mark KDL code blocks as KDL and use correct inline-comment `//` by [@​muzimuzhi](https://github.com/muzimuzhi) in [#​536](jdx/usage#536) - fix include syntax to match implementation by [@​jdx](https://github.com/jdx) in [#​540](jdx/usage#540) - consolidate integration list to single source by [@​jdx](https://github.com/jdx) in [#​541](jdx/usage#541) - fix link to integrations by [@​muzimuzhi](https://github.com/muzimuzhi) in [#​543](jdx/usage#543) ##### 🛡️ Security - **(deps)** update dependency eslint to v10 by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​526](jdx/usage#526) ##### 🔍 Other Changes - Added an integration with ruby's OptionParser by [@​packrat386](https://github.com/packrat386) in [#​533](jdx/usage#533) ##### 📦️ Dependency Updates - update actions/setup-node digest to [`53b8394`](jdx/usage@53b8394) by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​525](jdx/usage#525) - update jdx/mise-action action to v3 by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​528](jdx/usage#528) - update rust crate roff to v1 by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​529](jdx/usage#529) ##### New Contributors - [@​thecodesmith](https://github.com/thecodesmith) made their first contribution in [#​539](jdx/usage#539) - [@​packrat386](https://github.com/packrat386) made their first contribution in [#​533](jdx/usage#533) </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:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDIuMTAiLCJ1cGRhdGVkSW5WZXIiOiI0My4xMDIuMTAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbIlJlbm92YXRlIEJvdCIsImF1dG9tYXRpb246Ym90LWF1dGhvcmVkIiwiZGVwZW5kZW5jeS10eXBlOjptYWpvciJdfQ==-->
Summary
before_help,after_help,before_help_long,after_help_longin CLI-h/--helpoutputname+versionheader at the top of help outputauthorandlicensein the long help (--help) footer[deprecated: reason]marker on subcommandsexampleswith headers, help text, and$-prefixed commands-h) uses base variants; long help (--help) prefers_longvariants with fallbackCloses #549
Test plan
before_help/after_helprendering (short and long)before_help_long/after_help_longfallback behaviorversionheader displayauthor/licensein long help footerdeprecatedmarker on subcommandscargo test --all --all-features)🤖 Generated with Claude Code
Note
Low Risk
Low risk: changes are limited to CLI
--help/-hrendering templates and snapshot tests, affecting formatting/output only.Overview
Help output is expanded to render
before_help/after_help(with_longvariants preferred for--help), plus anExamplessection sourced from command- or spec-level examples.The templates now also show name+version headers, annotate deprecated subcommands with
[deprecated: ...], and include author/license lines in long help. Snapshot tests were added/updated to cover the new rendering behaviors.Written by Cursor Bugbot for commit b2967cc. This will update automatically on new commits. Configure here.