Skip to content

feat: align native subcommands on shared output styling - #461

Merged
marc0der merged 45 commits into
masterfrom
feat/output-style-alignment
Oct 24, 2026
Merged

marc0der merged 45 commits into
masterfrom
feat/output-style-alignment

Conversation

@marc0der

@marc0der marc0der commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Summary

Aligns all native subcommands on a shared output-styling architecture so user-facing text is consistent, stream-aware, and sourced from single definitions. Also makes the help binary answer every help flag the bash core forwards to it, so that with native commands enabled all help is rendered by native code.

Output style alignment (spec 001)

  • Adds a ui module as the sole place that writes messages and applies styling — message types, data output, semantic tokens, and CliError (ADR 0003: stdout for data, stderr for everything conversational).
  • Adds a cli module holding shared clap command definitions so each command's help has one source of truth, and rebuilds the help binary on top of those definitions.
  • Migrates current, default, home, uninstall, and version to a common run shape with ui-based output.
  • Restyles clap parse errors and maps unknown bash commands to styled help.
  • Suggests the closest SDK name for unknown names.
  • Lists main-page aliases as [aliases: X].
  • Hardens helpers: returns Result from shared helpers, reports a missing home directory instead of panicking, shares current-link removal, and removes dead code.
  • Drops the colored and textwrap dependencies in favour of anstream/anstyle.
  • Updates STYLE.md and CLAUDE.md, clears pre-existing clippy lints, and expands test coverage (including insta snapshots for every help page).

Help flags through the core (spec 002)

  • help accepts -h and --help: -h always prints the short page and --help the full page, for the main page and every command in the Help Catalogue. help -h, help --help, help <cmd> -h and help <cmd> --help follow the contract the bash core relies on; when both flags are given, the last one wins.
  • Adds short pages for the bash commands, with snapshots.
  • Fixes the flush page, which described behaviour bash flush does not have.
  • Accepts l as a hidden alias of list.
  • Tests assert each row of the help contract (main page, command pages, unknown commands) and that native -h/--help match help.
  • The companion bash core change, routing help flags to the help binary, lands separately in sdkman-cli.

Docs

  • Numbers specs in the order they were written and documents in CLAUDE.md that a later spec overrides an earlier one.

Test plan

  • cargo fmt --check
  • cargo clippy --all-targets -- -D warnings
  • cargo test

🤖 Generated with Claude Code

@chloe41427 chloe41427 Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the full diff and ran a focused pass over the ui/helpers modules, the shared cli/help layer, and the five migrated binaries against master. CI is green on all three platforms (fmt / clippy -D warnings / test all pass). LGTM. 👍

No bugs found. The load-bearing invariants hold:

  • stdout/stderr contract preserved — all captured data (home path, version string, current output) stays on stdout; only conversational text moved to stderr. $(sdk home java 21) and friends still work. This was the main regression risk and it's clean.
  • No new panics — the old .expect() / .unwrap() / process::exit paths (missing HOME, missing var/version) are now proper CliError → exit 1 instead of a 101 panic. Strictly better.
  • uninstall / default semantics intact — symlink comparison, --force gating, real remove_dir_all before the success message, and version-exists validation are all preserved.
  • Tests tightened, not weakened — assertions moved from contains() to exact stdout/stderr equality plus empty-stream checks, with the filesystem assertions retained. Every help page has an insta snapshot (the old src/bin/snapshots set is fully superseded).

One thing worth a sanity check (not a blocker): cli::default() now marks <VERSION> required and the help reads Usage: sdk default <SDK> <VERSION>. The native binary always required it (required(true) on master too), so this just makes the help honest — but the version-less form (sdk default java) is a real feature of the bash default command, and master's help text documented it. If the bash wrapper ever routes to this help render, users lose that documentation. Low stakes.

Nit: sdk help --help / sdk help -h prints unknown command --help with a fuzzy suggestion rather than the help page — the help binary doesn't special-case a leading -. Harmless since the wrapper drives help, but a plausible manual keystroke.

Approving. 🦀

@marc0der

marc0der commented Oct 8, 2026

Copy link
Copy Markdown
Member Author

Turning this into a draft until we've ensured full compatibility with the sdkman-cli wrapper.

marc0der and others added 26 commits October 24, 2026 01:13
Co-Authored-By: Claude <noreply@anthropic.com>
Binaries are flat files in src/bin/ since eda931d, and the package
is not a workspace. Describe where each kind of test lives, the
release script and the docs layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- gate: fmt check, clippy with -D warnings, test
- snapshot rules for insta
- boundaries for autonomous loops

Co-Authored-By: Claude <noreply@anthropic.com>
- add pure colour_choice applying R4 env and config rules in order
- add ui::init reading etc/config and setting the global ColorChoice
- add success, info, warning, error and hint message functions
- add value and table data output plus sdk, cmd and path tokens
- add CliError with a report method

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- known_candidates returns Result<Vec<String>, CliError>, dropping Box::leak
- add require_candidate and require_version_path with catalogue error text
- give home fn main() -> ExitCode calling a run helper
- emit the path through ui::value and errors through CliError
- add optional etc/config to VirtualEnv test harness
- assert ANSI under CLICOLOR_FORCE and plain value, NO_COLOR and config off

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- route success, guards, warnings and file errors through ui/CliError
- expose helpers::os_reason for file-error reasons

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- print the success line only after the change succeeds
- route the copy fallback and file failures through ui and CliError

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- print one SDK default as an unstyled value and all as a table
- route the no-default error and empty info through ui

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- print core: aligned with native: and brand via ui
- replace version-file panics with CliError, exit 1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- add strsim jaro scoring in require_candidate with a 0.7 threshold
- hint "did you mean <sdk>?" or fall back to "sdk list"

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- add cli module with configure() styles, template and native builders
- parse current, default, home, uninstall and version via try_get_matches
- snapshot each native --help page

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- map clap parse errors to STYLE.md shapes on stderr with exit 2
- route -h/--help to stdout with exit 0 via clap's own print
- reject extra arguments and unknown options for sdk version

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- build the sdk command from the native cli definitions and resolve
  sdk help <command> and its aliases with find_subcommand
- assert sdk help <command> and <command> --help give identical stdout
- add cli builders for the bash commands and a sdk() main page
- map an unknown command to error + closest suggestion, exit 2

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- drop the colored dependency and its two unused panic-based validators
- remove textwrap, now unused since clap wraps help

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- note interim java 21.0.2-tem form and the sdk usage-line override
- list the ui and cli modules in the architecture section

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- use Result::ok in read_file_content instead of a match
- borrow sdkman_dir for env::set_var; use write_all in the test helper
- drop needless return and to_owned in the test harness
- inline format args so clippy --all-targets passes
- render the sdk main page and rewrite clap's single-alias [alias: X]
  to the catalogue's [aliases: X] form
- preserve the colour decision via anstream::stdout()

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- infer_sdkman_dir returns Result<PathBuf, CliError>
- fallback_sdkman_dir errors with cannot find your home directory, exit 1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- drops the last panic! and to_str().unwrap() in src/lib.rs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
marc0der and others added 19 commits October 24, 2026 01:13
- extract remove_current_link into helpers
- call it from default and uninstall

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- call require_candidate with an unknown name
- assert the unknown SDK message and did-you-mean hint

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- add a sdk default missing-argument test asserting exit 2
- assert the full parse-error lines and --help hints for sdk version

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
- no native help when native commands are disabled
- keep clap's two-line layout for full help pages
- pin flag position and stderr assertions in tests

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- add bin_output as the single place that sets colour env
- drop duplicate short main-page test

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@marc0der
marc0der force-pushed the feat/output-style-alignment branch from a73f656 to 33c79a5 Compare October 24, 2026 00:13
@marc0der
marc0der marked this pull request as ready for review October 24, 2026 00:15
@marc0der
marc0der merged commit ca259c4 into master Oct 24, 2026
3 checks passed
@marc0der
marc0der deleted the feat/output-style-alignment branch October 24, 2026 00:20
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.

1 participant