# HG changeset patch # User Arseniy Alekseyev # Date 2024-12-13 15:43:50 # Node ID 92c6c8ab6f94b3d9e9b4d095737f5e57e805e4dc # Parent b52f2b365eff9dff60f1ee6e9826cd53e16f13ef rhg: simplify the subcommands macro Reduce the scope of the macro to only generate individual `SubCommand` values. This way, it will be easy to tweak the behavior of `add_subcommand_args` and `subcommand_run_fn` without having to understand the details of the macro. It also lets us easy add commands that don't fit the idiom, for example the "admin::" commands or "script::" commands. diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs --- a/rust/rhg/src/main.rs +++ b/rust/rhg/src/main.rs @@ -536,39 +536,51 @@ mod commands { pub mod status; } -macro_rules! subcommands { - ($( $command: ident )+) => { - - fn add_subcommand_args(app: clap::Command) -> clap::Command { - app - $( - .subcommand(commands::$command::args()) - )+ - } +pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>; - pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>; +struct SubCommand { + run: RunFn, + args: clap::Command, + name: String, +} - fn subcommand_run_fn(name: &str) -> Option { - match name { - $( - stringify!($command) => Some(commands::$command::run), - )+ - _ => None, - } +macro_rules! subcommand { + ($command: ident) => { + SubCommand { + args: commands::$command::args(), + run: commands::$command::run, + name: stringify!($command).to_string(), } }; } +fn subcommands() -> Vec { + vec![ + subcommand!(cat), + subcommand!(debugdata), + subcommand!(debugrequirements), + subcommand!(debugignorerhg), + subcommand!(debugrhgsparse), + subcommand!(files), + subcommand!(root), + subcommand!(config), + subcommand!(status), + ] +} -subcommands! { - cat - debugdata - debugrequirements - debugignorerhg - debugrhgsparse - files - root - config - status +fn add_subcommand_args(mut app: clap::Command) -> clap::Command { + for s in subcommands() { + app = app.subcommand(s.args) + } + app +} + +fn subcommand_run_fn(name: &str) -> Option { + for s in subcommands() { + if s.name == name { + return Some(s.run); + } + } + None } pub struct CliInvocation<'a> {