feat(cli): enhance help documentation and dynamic applet dispatch

This commit is contained in:
Nils Andreas Svee committed 2026-06-22 15:13:36 +07:00
1 parent f1d442d798
commit b33f01cfe1
4 files changed
+92 -26

No files matched your search

+55 -10
View File
@@ -41,13 +41,15 @@ pub fn dispatch_from_argv(argv: Vec<OsString>) -> Result<AppletDispatch, String>
let basename = applet_basename(argv0);
if basename.starts_with("irtt-") && basename != "irtt-rs" {
return Err(format!(
"unknown applet name '{basename}'. Known applet names: irtt-rs, irtt-cli, irtt-tui, irtt-server"
"unknown applet name '{basename}'. Known applet names: {}",
known_applet_binary_names()
));
}
let Some(command) = argv.get(1).and_then(|arg| arg.to_str()) else {
return Err(format!(
"choose an applet: client, tui, or server\n\n{}",
"choose an applet: {}\n\n{}",
applet_command_names(),
dispatcher_help()
));
};
@@ -67,7 +69,8 @@ pub fn dispatch_from_argv(argv: Vec<OsString>) -> Result<AppletDispatch, String>
argv: applet_argv("irtt-server", &argv[2..]),
}),
_ => Err(format!(
"unknown applet '{command}'. Choose one of: client, tui, server\n\n{}",
"unknown applet '{command}'. Choose one of: {}\n\n{}",
applet_command_names(),
dispatcher_help()
)),
}
@@ -76,13 +79,47 @@ pub fn dispatch_from_argv(argv: Vec<OsString>) -> Result<AppletDispatch, String>
pub fn dispatcher_help() -> String {
let mut command = Command::new("irtt-rs")
.about("IRTT-compatible multi-applet dispatcher")
.subcommand(Command::new("client").about("Run the stream client applet"))
.subcommand(Command::new("tui").about("Run the terminal UI applet"))
.subcommand(Command::new("server").about("Run the server applet"))
.after_help("Applet binary names: irtt-cli, irtt-tui, irtt-server");
.subcommand(Command::new("client").about(client_applet_about()))
.subcommand(Command::new("tui").about(tui_applet_about()))
.subcommand(Command::new("server").about("Server applet is not available in this build"))
.after_help(dispatcher_after_help());
command.render_help().to_string()
}
fn client_applet_about() -> &'static str {
if cfg!(feature = "client") {
"Run the stream client applet"
} else {
"Stream client applet is not available in this build"
}
}
fn tui_applet_about() -> &'static str {
if cfg!(feature = "tui") {
"Run the terminal UI applet"
} else {
"Terminal UI applet is not available in this build"
}
}
fn known_applet_binary_names() -> &'static str {
"irtt-rs, irtt-cli, irtt-tui, irtt-server"
}
fn applet_command_names() -> &'static str {
"client, tui, or server"
}
fn dispatcher_after_help() -> &'static str {
if cfg!(feature = "tui") {
"Recognized applet binary names: irtt-cli, irtt-tui, irtt-server"
} else if cfg!(feature = "client") {
"Recognized applet binary names: irtt-cli, irtt-tui, irtt-server\nOptional applet: irtt-tui requires the tui feature"
} else {
"Recognized applet binary names: irtt-cli, irtt-tui, irtt-server\nOptional applets: irtt-cli requires the client feature; irtt-tui requires the tui feature"
}
}
fn applet_basename(argv0: &str) -> &str {
Path::new(argv0)
.file_name()
@@ -127,7 +164,11 @@ mod tests {
};
assert!(help.contains("IRTT-compatible multi-applet dispatcher"));
assert!(help.contains("client"));
assert!(help.contains("tui"));
if cfg!(feature = "tui") {
assert!(help.contains("Run the terminal UI applet"));
} else {
assert!(help.contains("Terminal UI applet is not available in this build"));
}
assert!(help.contains("server"));
}
@@ -136,7 +177,9 @@ mod tests {
let err = dispatch_from_argv(vec!["irtt-rs".into()]).unwrap_err();
assert!(err.contains("choose an applet"));
assert!(err.contains("client"));
assert!(err.contains("tui"));
if cfg!(feature = "tui") {
assert!(err.contains("tui"));
}
assert!(err.contains("server"));
}
@@ -171,7 +214,9 @@ mod tests {
let err = dispatch_from_argv(vec!["/usr/bin/irtt-typo".into()]).unwrap_err();
assert!(err.contains("unknown applet name 'irtt-typo'"));
assert!(err.contains("irtt-cli"));
assert!(err.contains("irtt-tui"));
if cfg!(feature = "tui") {
assert!(err.contains("irtt-tui"));
}
assert!(err.contains("irtt-server"));
}
}