Skip to content

Conversation

cknitt
Copy link
Member

@cknitt cknitt commented Jul 25, 2025

Rewatch’s CLI now keeps the top-level help focused: it no longer floods rescript --help with all build options. Instead, users learn via the after-help note that build is the default subcommand and can dig deeper with rescript help build:

ReScript - Fast, Simple, Fully Typed JavaScript from the Future

Usage: rescript [OPTIONS] <COMMAND>

Commands:
  build          Build the project (default command)
  watch          Build, then start a watcher
  clean          Clean the build artifacts
  format         Formats ReScript files
  compiler-args  This prints the compiler arguments. It expects the path to a rescript file (.res or .resi)
  legacy         Use the legacy build system
  help           Print this message or the help of the given subcommand(s)

Options:
  -v, --verbose...  Increase logging verbosity
  -q, --quiet...    Decrease logging verbosity
  -h, --help        Print help
  -V, --version     Print version

Note: If no command is provided, the build command is run by default. See `rescript help build` for more information.

Unfortunately, clap does not support default subcommands out of the box, so this gets a bit tricky. We "double-parse" the arguments as follows:

  1. First pass – run Cli::try_parse_from(&args) exactly as clap would. If it succeeds, we’re done.
  2. Fallback path – if clap rejects the invocation and the error indicates the user simply omitted a subcommand (or provided a positional that should map to build), we clone the argument list, insert the implicit "build" at the right spot (after any global flags), and call try_parse_from again.
    • If this second parse succeeds, we treat the command as build and keep going.
    • If it fails too, we surface clap’s error unchanged so the user still sees the normal help/version output or any genuine parse problem.

We also add targeted unit tests that exercise defaulting, folder shortcuts, global-flag ordering, and help/version passthrough to guard the new behavior.

@cknitt cknitt marked this pull request as ready for review July 25, 2025 09:31
@cknitt cknitt force-pushed the rewatch-cli-help branch from f39b58c to f92128b Compare July 25, 2025 11:12
Copy link

pkg-pr-new bot commented Jul 25, 2025

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript-lang/rescript@7715

@rescript/darwin-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-arm64@7715

@rescript/darwin-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-x64@7715

@rescript/linux-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-arm64@7715

@rescript/linux-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-x64@7715

@rescript/runtime

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/runtime@7715

@rescript/win32-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/win32-x64@7715

commit: 603172f

@cknitt cknitt force-pushed the rewatch-cli-help branch from f3bc86c to dbe5153 Compare July 25, 2025 11:41
@cknitt cknitt requested review from Bushuo and zth July 25, 2025 12:07
@cknitt cknitt marked this pull request as draft July 28, 2025 14:47
@cknitt
Copy link
Member Author

cknitt commented Jul 28, 2025

This is not 100% correct yet as long as we have the [FOLDER] arg - rescript someFolder as a shortcut for rescript build someFolder will not work. Will revisit this later.

@cknitt
Copy link
Member Author

cknitt commented Sep 26, 2025

@codex review

@cknitt cknitt marked this pull request as ready for review September 26, 2025 16:43
Copy link

@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.

ℹ️ 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 👍.

Comment on lines 136 to 141
fn should_default_to_build(err: &clap::Error, args: &[String]) -> bool {
match err.kind() {
ErrorKind::MissingSubcommand | ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand => true,
ErrorKind::UnknownArgument | ErrorKind::InvalidSubcommand => {
args.iter().skip(1).any(|arg| !is_global_flag(arg))
}

Choose a reason for hiding this comment

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

[P1] Avoid defaulting to build when a subcommand was supplied

The fallback parsing in should_default_to_build treats any UnknownArgument or InvalidSubcommand as an omitted subcommand as long as a non‑global token exists. When a user explicitly runs another subcommand but mistypes an option that only build understands, the second parse injects build and succeeds. For example, rescript watch --no-timing (an invalid option for watch) is reinterpreted as rescript build watch --no-timing, so the tool performs a one‑off build of the watch folder and exits instead of starting the watcher. That silent command switch regresses error reporting and will surprise users trying to run watch/clean/format. The fallback should only fire when no subcommand token is present, not when an explicit subcommand failed to parse.

Useful? React with 👍 / 👎.

@cknitt
Copy link
Member Author

cknitt commented Sep 26, 2025

@codex review

Copy link

@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.

ℹ️ 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 👍.

@cknitt
Copy link
Member Author

cknitt commented Sep 26, 2025

@codex review

Copy link

@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.

ℹ️ 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 👍.

Comment on lines 122 to 125
if should_default_to_build(&err, &raw_args) {
let mut fallback_args = raw_args.clone();
let insert_at = index_after_global_flags(&fallback_args);
fallback_args.insert(insert_at, OsString::from("build"));

Choose a reason for hiding this comment

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

[P1] Default build fallback rejects global flags after folder paths

When the user omits an explicit subcommand, parse_cli inserts the implicit build token after only the leading global flags. Global flags that appear after the folder argument (e.g. rescript my-project -v or rescript ./ --quiet) are left trailing the newly inserted build token, so clap parses them as arguments to the build subcommand and reports UnknownArgument. The pre‑existing CLI accepted these invocations because there was no subcommand and global flags could be positioned after the folder. This regression will break scripts that pass -v/--quiet after the path. Consider collecting global flags regardless of position or reordering them ahead of the injected build command before reparsing.

Useful? React with 👍 / 👎.

@cknitt
Copy link
Member Author

cknitt commented Sep 27, 2025

@codex review

Copy link

Codex Review: Didn't find any major issues. What shall we delve into next?

ℹ️ 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 👍.

@cknitt cknitt requested a review from nojaf September 27, 2025 07:01
@cknitt cknitt added the build label Sep 27, 2025
Copy link
Member

@nojaf nojaf left a comment

Choose a reason for hiding this comment

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

I haven't used Clap much, so I'm not the best person to review this.

As we do these days, I chatted with an LLM about it. Overall, this adds complexity, and all the juggling with Clap makes me wonder if we should keep using it. If Clap does not support default subcommands, it might not be the right fit.

If we do intend to keep it, I'd like to see more architectural notes. This is a trade-off and we should be upfront about that. Future Rustacean contributors might frown on this, so we should acknowledge the potential heresy.

@cknitt
Copy link
Member Author

cknitt commented Sep 29, 2025

I haven't used Clap much, so I'm not the best person to review this.

As we do these days, I chatted with an LLM about it. Overall, this adds complexity, and all the juggling with Clap makes me wonder if we should keep using it. If Clap does not support default subcommands, it might not be the right fit.

From what I can see, clap seems to be the most commonly used and feature rich command-line argument parser in the Rust world. Not to keen on swapping it out for something else, especially at this point of the release cycle.

If we do intend to keep it, I'd like to see more architectural notes. This is a trade-off and we should be upfront about that. Future Rustacean contributors might frown on this, so we should acknowledge the potential heresy.

Right, I'll add comments for that.

}
}

fn parse_cli(raw_args: Vec<OsString>) -> Result<cli::Cli, clap::Error> {
Copy link
Member

Choose a reason for hiding this comment

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

Makes me wonder if we can check if the first argument is any of the verbs, if not prepend the vector with build.
That way we avoid the double parse in the error case.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's what I had in the beginning, and it had other issues.
See the previous codex reviews, it took quite a few attempts until everything worked correctly.

Copy link
Member

@nojaf nojaf left a comment

Choose a reason for hiding this comment

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

While I still think this is not ideal, the pragmatic thing is to move on now!

@cknitt cknitt merged commit a1b3b3c into master Sep 29, 2025
25 checks passed
@cknitt cknitt deleted the rewatch-cli-help branch September 29, 2025 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants