Skip to main content

Module resolver

Module resolver 

Source
Expand description

String-to-command resolution with prefix and ambiguity detection.

The resolver implements a three-phase algorithm:

  1. Normalize — trim whitespace and lowercase the input.
  2. Exact match — check the input against every command’s canonical name, aliases, and spellings. Return immediately if exactly one matches.
  3. Prefix match — check which commands have at least one matchable string that starts with the normalized input. If exactly one command matches, return it. If more than one matches, return ResolveError::Ambiguous. If none match, return ResolveError::Unknown.

This algorithm allows users (and agents) to type unambiguous prefixes like dep instead of deploy while still producing clear errors when a prefix is shared by multiple commands.

When a command cannot be found, the resolver also computes up to three “did you mean?” suggestions based on Levenshtein edit distance (≤ 2) or substring containment, and attaches them to the ResolveError::Unknown variant.

§Example

let cmds = vec![
    Command::builder("list").alias("ls").build().unwrap(),
    Command::builder("log").build().unwrap(),
];

let resolver = Resolver::new(&cmds);

// Exact canonical
assert_eq!(resolver.resolve("list").unwrap().canonical, "list");
// Exact alias
assert_eq!(resolver.resolve("ls").unwrap().canonical, "list");
// Unambiguous prefix
assert_eq!(resolver.resolve("lo").unwrap().canonical, "log");
// Ambiguous prefix — "l" matches both "list" and "log"
assert!(resolver.resolve("l").is_err());
// Near-miss — "lust" is one edit away from "list"
match resolver.resolve("lust") {
    Err(ResolveError::Unknown { suggestions, .. }) => {
        assert!(suggestions.contains(&"list".to_string()));
    }
    _ => unreachable!(),
}

Structs§

Resolver
Resolves a string token to a Command in a slice, supporting aliases, spellings, and unambiguous prefix matching.

Enums§

ResolveError
Errors produced by Resolver::resolve.