pub struct Registry { /* private fields */ }Expand description
Owns the registered command tree and provides query/search operations.
Create a Registry with Registry::new, passing the fully-built list of
top-level commands. The registry takes ownership of the command list and
makes it available through a variety of lookup and search methods.
§Examples
let registry = Registry::new(vec![
Command::builder("deploy").summary("Deploy the app").build().unwrap(),
]);
let cmd = registry.get_command("deploy").unwrap();
assert_eq!(cmd.summary, "Deploy the app");Implementations§
Source§impl Registry
impl Registry
Sourcepub fn new(commands: Vec<Command>) -> Self
pub fn new(commands: Vec<Command>) -> Self
Create a new Registry owning the given command list.
§Arguments
commands— The top-level command list. Subcommands are nested inside the respectiveCommand::subcommandsfields.
§Examples
let registry = Registry::new(vec![
Command::builder("run").build().unwrap(),
]);
assert_eq!(registry.list_commands().len(), 1);Sourcepub fn list_commands(&self) -> Vec<&Command>
pub fn list_commands(&self) -> Vec<&Command>
Return references to all top-level commands.
§Examples
let registry = Registry::new(vec![
Command::builder("a").build().unwrap(),
Command::builder("b").build().unwrap(),
]);
assert_eq!(registry.list_commands().len(), 2);Sourcepub fn get_command(&self, canonical: &str) -> Option<&Command>
pub fn get_command(&self, canonical: &str) -> Option<&Command>
Look up a top-level command by its exact canonical name.
Returns None if no command with that canonical name exists. Does not
match aliases or spellings — use crate::Resolver for fuzzy/prefix
matching.
§Arguments
canonical— The exact canonical name to look up.
§Examples
let registry = Registry::new(vec![
Command::builder("deploy").alias("d").build().unwrap(),
]);
assert!(registry.get_command("deploy").is_some());
assert!(registry.get_command("d").is_none()); // alias, not canonicalSourcepub fn get_subcommand(&self, path: &[&str]) -> Option<&Command>
pub fn get_subcommand(&self, path: &[&str]) -> Option<&Command>
Walk a path of canonical names into the subcommand tree.
path = &["remote", "add"] returns the add subcommand of remote.
Each path segment must be an exact canonical name at that level of
the tree.
Returns None if any segment fails to match or if path is empty.
§Arguments
path— Ordered slice of canonical command names from top-level down.
§Examples
let registry = Registry::new(vec![
Command::builder("remote")
.subcommand(Command::builder("add").build().unwrap())
.build()
.unwrap(),
]);
let sub = registry.get_subcommand(&["remote", "add"]).unwrap();
assert_eq!(sub.canonical, "add");
assert!(registry.get_subcommand(&[]).is_none());
assert!(registry.get_subcommand(&["remote", "nope"]).is_none());Sourcepub fn get_examples(&self, canonical: &str) -> Option<&[Example]>
pub fn get_examples(&self, canonical: &str) -> Option<&[Example]>
Return the examples slice for a top-level command, or None if the
command does not exist.
An empty examples list returns Some(&[]).
§Arguments
canonical— The exact canonical name of the command.
§Examples
let registry = Registry::new(vec![
Command::builder("run")
.example(Example::new("basic run", "myapp run"))
.build()
.unwrap(),
]);
assert_eq!(registry.get_examples("run").unwrap().len(), 1);
assert!(registry.get_examples("missing").is_none());Sourcepub fn search(&self, query: &str) -> Vec<&Command>
pub fn search(&self, query: &str) -> Vec<&Command>
Substring search across canonical name, summary, and description.
The search is case-insensitive. Returns all top-level commands for which the query appears in at least one of the three text fields.
§Arguments
query— The substring to search for (case-insensitive).
§Examples
let registry = Registry::new(vec![
Command::builder("list").summary("List all records").build().unwrap(),
Command::builder("get").summary("Get a single record").build().unwrap(),
]);
let results = registry.search("record");
assert_eq!(results.len(), 2);
assert!(registry.search("zzz").is_empty());Sourcepub fn fuzzy_search(&self, query: &str) -> Vec<(&Command, i64)>
pub fn fuzzy_search(&self, query: &str) -> Vec<(&Command, i64)>
Fuzzy search across canonical name, summary, and description.
Uses the skim fuzzy-matching algorithm (requires the fuzzy feature).
Returns matches sorted descending by score (best match first).
Commands that produce no fuzzy match are excluded.
§Arguments
query— The fuzzy query string.
§Examples
let registry = Registry::new(vec![
Command::builder("deploy").summary("Deploy a service").build().unwrap(),
Command::builder("delete").summary("Delete a resource").build().unwrap(),
Command::builder("describe").summary("Describe a resource").build().unwrap(),
]);
// Fuzzy-matches all commands starting with 'de'
let results = registry.fuzzy_search("dep");
assert!(!results.is_empty());
// Results are sorted by match score descending
assert_eq!(results[0].0.canonical, "deploy");
// Scores are positive integers — higher is a better match
assert!(results[0].1 > 0);Sourcepub fn match_intent(&self, phrase: &str) -> Vec<(&Command, u32)>
pub fn match_intent(&self, phrase: &str) -> Vec<(&Command, u32)>
Match commands by natural-language intent phrase.
Scores each command by how many words from phrase appear in its
combined text (canonical name, aliases, semantic aliases, summary,
description). Returns matches sorted by score descending.
§Examples
let registry = Registry::new(vec![
Command::builder("deploy")
.summary("Deploy a service to an environment")
.semantic_alias("release to production")
.semantic_alias("push to environment")
.build().unwrap(),
Command::builder("status")
.summary("Check service status")
.build().unwrap(),
]);
let results = registry.match_intent("deploy to production");
assert!(!results.is_empty());
assert_eq!(results[0].0.canonical, "deploy");Sourcepub fn to_json(&self) -> Result<String, QueryError>
pub fn to_json(&self) -> Result<String, QueryError>
Serialize the entire command tree to a pretty-printed JSON string.
Handler closures are excluded from the output (they are skipped by the
serde configuration on Command).
§Errors
Returns QueryError::Serialization if serde_json fails (in
practice this should not happen for well-formed command trees).
§Examples
let registry = Registry::new(vec![
Command::builder("deploy").summary("Deploy").build().unwrap(),
]);
let json = registry.to_json().unwrap();
assert!(json.contains("deploy"));Sourcepub fn to_json_with_fields(&self, fields: &[&str]) -> Result<String, QueryError>
pub fn to_json_with_fields(&self, fields: &[&str]) -> Result<String, QueryError>
Serialize the entire command tree to a pretty-printed JSON string, filtering each command object to only include the requested top-level fields.
Each command object (including nested subcommands at any depth) is
filtered so that only keys listed in fields are retained. The
subcommands key is always walked recursively even if it is not in
fields; its entries are filtered before being emitted.
If fields is empty the method falls back to the same output as
Registry::to_json.
Field names that do not exist in the serialized command are silently ignored (no error is returned for missing fields).
Valid field names correspond to the top-level keys of the serialized
Command object: canonical, aliases, spellings,
semantic_aliases, summary, description, arguments, flags,
examples, best_practices, anti_patterns, subcommands, meta,
mutating, etc.
§Errors
Returns QueryError::Serialization if serde_json fails.
§Examples
let registry = Registry::new(vec![
Command::builder("deploy")
.summary("Deploy the app")
.build()
.unwrap(),
]);
let json = registry.to_json_with_fields(&["canonical", "summary"]).unwrap();
let v: serde_json::Value = serde_json::from_str(&json).unwrap();
let obj = &v[0];
assert_eq!(obj["canonical"], "deploy");
assert_eq!(obj["summary"], "Deploy the app");
// fields not requested are absent
assert!(obj.get("examples").is_none());Sourcepub fn to_ndjson(&self) -> Result<String, QueryError>
pub fn to_ndjson(&self) -> Result<String, QueryError>
Serialize the command tree as NDJSON (one compact JSON object per line).
Commands are emitted depth-first using Registry::iter_all_recursive.
Each line is a single, self-contained JSON object representing one
command (handler closures excluded). Subcommands appear as their own
lines rather than being nested inside their parent, which lets agents
process the registry incrementally without buffering the entire tree.
An empty registry returns an empty string (no trailing newline). A non-empty registry ends with a trailing newline.
§Errors
Returns QueryError::Serialization if serialization fails.
§Examples
let registry = Registry::new(vec![
Command::builder("remote")
.subcommand(Command::builder("add").build().unwrap())
.build()
.unwrap(),
]);
let ndjson = registry.to_ndjson().unwrap();
let lines: Vec<&str> = ndjson.trim_end_matches('\n').split('\n').collect();
assert_eq!(lines.len(), 2); // "remote" + "remote add"
// Every line must be valid JSON.
for line in &lines {
assert!(serde_json::from_str::<serde_json::Value>(line).is_ok());
}Sourcepub fn to_ndjson_with_fields(
&self,
fields: &[&str],
) -> Result<String, QueryError>
pub fn to_ndjson_with_fields( &self, fields: &[&str], ) -> Result<String, QueryError>
Serialize the command tree as NDJSON, filtering each object to the given field names.
Behaves identically to Registry::to_ndjson except that each JSON
object is filtered to include only the keys listed in fields. When
fields is empty, all fields are included (equivalent to
Registry::to_ndjson).
§Arguments
fields— Field names to keep in each output object. Pass&[]to include all fields.
§Errors
Returns QueryError::Serialization if serialization fails.
§Examples
let registry = Registry::new(vec![
Command::builder("deploy").summary("Deploy the app").build().unwrap(),
]);
let ndjson = registry.to_ndjson_with_fields(&["canonical", "summary"]).unwrap();
let val: serde_json::Value = serde_json::from_str(ndjson.trim_end_matches('\n')).unwrap();
assert!(val.get("canonical").is_some());
assert!(val.get("summary").is_some());
assert!(val.get("description").is_none());Sourcepub fn iter_all_recursive(&self) -> Vec<CommandEntry<'_>>
pub fn iter_all_recursive(&self) -> Vec<CommandEntry<'_>>
Iterate over every command in the tree depth-first, including all nested subcommands at any depth.
Each entry carries the CommandEntry::path (canonical names from the
registry root to the command) and a reference to the Command.
Commands are yielded in depth-first order: a parent command appears immediately before all of its descendants. Within each level, commands appear in registration order.
§Examples
let registry = Registry::new(vec![
Command::builder("remote")
.subcommand(Command::builder("add").build().unwrap())
.subcommand(Command::builder("remove").build().unwrap())
.build()
.unwrap(),
Command::builder("status").build().unwrap(),
]);
let all: Vec<_> = registry.iter_all_recursive();
let names: Vec<String> = all.iter().map(|e| e.path_str()).collect();
assert_eq!(names, ["remote", "remote.add", "remote.remove", "status"]);