MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / render

Function render

atomic-cli/src/agent_error.rs:579–715  ·  view source on GitHub ↗

Render a clap parse failure as `key: value` lines. A pure function returning a `String`, so the whole failure surface is unit-testable without spawning a process.

(err: &clap::Error, root: &clap::Command, argv: &[OsString])

Source from the content-addressed store, hash-verified

577/// A pure function returning a `String`, so the whole failure surface is
578/// unit-testable without spawning a process.
579pub fn render(err: &clap::Error, root: &clap::Command, argv: &[OsString]) -> String {
580 // Scope first, everything else from it. clap's usage line is authoritative
581 // about WHICH command the error is about; argv is only a fallback for the
582 // kinds that attach no usage context. Deriving `cmd`/`verb`/`help` from a
583 // different source than `usage` is what lets them contradict.
584 let ctx_usage = ctx_str(err, ContextKind::Usage)
585 .map(|u| {
586 u.trim_start_matches("Usage:")
587 .trim_start_matches("usage:")
588 .trim()
589 .to_string()
590 })
591 .filter(|u| !u.is_empty());
592
593 let (key, display) = match ctx_usage.as_deref().and_then(|u| path_from_usage(root, u)) {
594 Some(k) => {
595 let d = display_path(root, &k);
596 (k, d)
597 }
598 None => resolve_invoked(root, argv),
599 };
600
601 let mut kv: Vec<(&str, String)> = vec![
602 ("error", kind_slug(err.kind()).to_string()),
603 ("cmd", display.clone()),
604 ];
605
606 // Keep the rejected value and the argument it belonged to separate. The
607 // old renderer selected only one context entry, which turned
608 // `--count nope` into a bare `got: nope` and dropped both `--count` and the
609 // parser's "invalid digit" cause.
610 match err.kind() {
611 ErrorKind::InvalidSubcommand => {
612 if let Some(value) = ctx_str(err, ContextKind::InvalidSubcommand) {
613 kv.push(("got", value));
614 }
615 }
616 ErrorKind::UnknownArgument => {
617 if let Some(arg) = ctx_str(err, ContextKind::InvalidArg) {
618 kv.push(("got", arg));
619 }
620 }
621 ErrorKind::MissingRequiredArgument => {
622 let missing = ctx_list(err, ContextKind::InvalidArg);
623 for required in missing {
624 kv.push(("required", required));
625 }
626 }
627 ErrorKind::MissingSubcommand => {}
628 ErrorKind::InvalidUtf8 => {
629 if let Some(value) = rejected_non_utf8_arg(root, argv).and_then(encode_invalid_units) {
630 kv.push(("got-raw", value));
631 }
632 }
633 _ => {
634 let invalid_arg = ctx_str(err, ContextKind::InvalidArg);
635 if let Some(arg) = invalid_arg.clone() {
636 kv.push(("arg", arg));

Calls 15

ctx_strFunction · 0.85
path_from_usageFunction · 0.85
resolve_invokedFunction · 0.85
ctx_listFunction · 0.85
rejected_non_utf8_argFunction · 0.85
has_explicit_empty_valueFunction · 0.85
reasonFunction · 0.85
walk_toFunction · 0.85
verbsFunction · 0.85
emitFunction · 0.85
extendMethod · 0.80
display_pathFunction · 0.70