mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 01:35:36 +00:00
fix(cli): read an -o that follows an unknown argument
clap stops parsing at an unknown argument, so `idx config get --bogus -o json` lost the -o. Drop each unknown argument and parse again before reading the output flag (Pullfrog review on #56). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
This commit is contained in:
parent
0f2806f9f5
commit
70e923334d
2 changed files with 47 additions and 10 deletions
|
|
@ -115,16 +115,9 @@ fn argument_error(err: clap::Error) -> IdxError {
|
|||
/// `-o`/`--output` as clap reads it (clustered short flags, the last one
|
||||
/// at any subcommand level), then `IDX_OUTPUT`, then auto.
|
||||
fn requested_output_from_args() -> OutputFormat {
|
||||
use clap::CommandFactory;
|
||||
// ignore_errors keeps every argument clap could read; args_os, because an
|
||||
// argument that is not UTF-8 (itself the error being reported) must not
|
||||
// panic here.
|
||||
let flag = Cli::command()
|
||||
.ignore_errors(true)
|
||||
.try_get_matches_from(std::env::args_os())
|
||||
.ok()
|
||||
.and_then(|matches| matches.get_one::<OutputSetting>("output").copied());
|
||||
let setting = flag
|
||||
// args_os: an argument that is not UTF-8 (itself the error being
|
||||
// reported) must not panic here.
|
||||
let setting = output_flag(std::env::args_os().collect())
|
||||
.or_else(|| {
|
||||
std::env::var("IDX_OUTPUT")
|
||||
.ok()
|
||||
|
|
@ -134,6 +127,37 @@ fn requested_output_from_args() -> OutputFormat {
|
|||
setting.resolve(config::stdout_is_terminal())
|
||||
}
|
||||
|
||||
/// clap stops at an unknown argument, so an `-o` after it would be missed;
|
||||
/// drop each unknown argument and parse again. What is left is read with
|
||||
/// ignore_errors, which keeps the matches made before any other error.
|
||||
fn output_flag(mut args: Vec<std::ffi::OsString>) -> Option<OutputSetting> {
|
||||
use clap::CommandFactory;
|
||||
use clap::error::{ContextKind, ContextValue, ErrorKind};
|
||||
for _ in 0..args.len() {
|
||||
let Err(err) = Cli::command().try_get_matches_from(&args) else {
|
||||
break;
|
||||
};
|
||||
if err.kind() != ErrorKind::UnknownArgument {
|
||||
break;
|
||||
}
|
||||
let Some(ContextValue::String(bad)) = err.get(ContextKind::InvalidArg) else {
|
||||
break;
|
||||
};
|
||||
let Some(index) = args.iter().skip(1).position(|arg| {
|
||||
let arg = arg.to_string_lossy();
|
||||
arg == bad.as_str() || arg.starts_with(&format!("{bad}="))
|
||||
}) else {
|
||||
break;
|
||||
};
|
||||
args.remove(index + 1);
|
||||
}
|
||||
Cli::command()
|
||||
.ignore_errors(true)
|
||||
.try_get_matches_from(args)
|
||||
.ok()
|
||||
.and_then(|matches| matches.get_one::<OutputSetting>("output").copied())
|
||||
}
|
||||
|
||||
fn bootstrap_output_format(cli: &Cli) -> OutputFormat {
|
||||
let setting = cli
|
||||
.output
|
||||
|
|
|
|||
|
|
@ -2127,6 +2127,19 @@ fn argument_errors_follow_the_output_format_clap_resolves() {
|
|||
] {
|
||||
run_error_json(test_bin("argument-error-json").args(args), "INVALIDINPUT");
|
||||
}
|
||||
// An -o after an unknown argument still counts, over IDX_OUTPUT too.
|
||||
run_error_json(
|
||||
test_bin("argument-error-json")
|
||||
.env("IDX_OUTPUT", "table")
|
||||
.args(["config", "get", "--bogus", "-o", "json"]),
|
||||
"INVALIDINPUT",
|
||||
);
|
||||
test_bin("argument-error-table")
|
||||
.args(["config", "get", "--bogus", "-o", "table"])
|
||||
.assert()
|
||||
.failure()
|
||||
.stdout("")
|
||||
.stderr(predicate::str::starts_with("error: "));
|
||||
for args in [
|
||||
&["-o", "json", "config", "-o", "table", "get"][..],
|
||||
&["-qotable", "config", "get"][..],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue