From 1201abcffadab69d5a16844e968f8d50a53bdb35 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Sat, 30 Nov 2019 12:57:02 +0100 Subject: [PATCH] src/cli/command.rs: implement help --- src/bin/completion.rs | 11 +---- src/cli/command.rs | 100 ++++++++++++++++++++++++++++++++++-------- src/cli/completion.rs | 11 ++--- 3 files changed, 89 insertions(+), 33 deletions(-) diff --git a/src/bin/completion.rs b/src/bin/completion.rs index 754c674e..62fb0e5e 100644 --- a/src/bin/completion.rs +++ b/src/bin/completion.rs @@ -37,7 +37,6 @@ fn command_map() -> CliCommandMap { cmd_def } - fn main() -> Result<(), Error> { let def = CommandLineInterface::Nested(command_map()); @@ -58,14 +57,8 @@ fn main() -> Result<(), Error> { let args = shellword_split(&line)?; let def = helper.cmd_def(); - let _ = match def { - CommandLineInterface::Simple(ref cli_cmd) => { - handle_simple_command(def, "", &cli_cmd, args) - } - CommandLineInterface::Nested(ref map) => { - handle_nested_command(def, "", &map, args) - } - }; + + handle_command(def, "", args); } Ok(()) diff --git a/src/cli/command.rs b/src/cli/command.rs index ba4704be..cea760cc 100644 --- a/src/cli/command.rs +++ b/src/cli/command.rs @@ -1,7 +1,10 @@ use failure::*; use serde_json::Value; use std::collections::HashMap; +use std::sync::Arc; +use std::cell::RefCell; +use proxmox::api::*; use proxmox::api::format::*; use proxmox::api::schema::*; use proxmox::api::{ApiHandler, ApiMethod}; @@ -321,16 +324,88 @@ pub fn print_bash_completion(def: &CommandLineInterface) { } } -const VERBOSE_HELP_SCHEMA: Schema = BooleanSchema::new("Verbose help.").schema(); -const COMMAND_HELP: ObjectSchema = ObjectSchema::new( - "Get help about specified command.", - &[ ("verbose", true, &VERBOSE_HELP_SCHEMA) ] +const API_METHOD_COMMAND_HELP: ApiMethod = ApiMethod::new( + &ApiHandler::Sync(&help_command), + &ObjectSchema::new( + "Get help about specified command.", + &[ + ( "command", + true, + &StringSchema::new("Command name.").schema() + ), + ( "verbose", + true, + &BooleanSchema::new("Verbose help.").schema() + ), + ], + ) ); -const API_METHOD_COMMAND_HELP: ApiMethod = ApiMethod::new_dummy(&COMMAND_HELP); +std::thread_local! { + static HELP_CONTEXT: RefCell>> = RefCell::new(None); +} + +fn help_command( + param: Value, + _info: &ApiMethod, + _rpcenv: &mut dyn RpcEnvironment, +) -> Result { + + + let command = param["command"].as_str(); + let verbose = param["verbose"].as_bool(); + + HELP_CONTEXT.with(|ctx| { + match &*ctx.borrow() { + Some(def) => { + let mut args = Vec::new(); + // TODO: Handle multilevel sub commands + if let Some(command) = command { + args.push(command.to_string()); + } + + print_help(def, String::from(""), &args, verbose); + } + None => { + eprintln!("Sorry, help context not set - internal error."); + } + } + }); + + Ok(Value::Null) +} + +pub fn set_help_context(def: Option>) { + HELP_CONTEXT.with(|ctx| { *ctx.borrow_mut() = def; }); +} pub fn help_command_def() -> CliCommand { CliCommand::new(&API_METHOD_COMMAND_HELP) + .arg_param(&["command"]) +} + +pub fn handle_command( + def: Arc, + prefix: &str, + args: Vec, +) { + + set_help_context(Some(def.clone())); + + match &*def { + CommandLineInterface::Simple(ref cli_cmd) => { + if let Err(_) = handle_simple_command(&def, &prefix, &cli_cmd, args) { + std::process::exit(-1); + } + } + CommandLineInterface::Nested(ref map) => { + if let Err(_) = handle_nested_command(&def, &prefix, &map, args) { + std::process::exit(-1); + } + } + }; + + set_help_context(None); } pub fn run_cli_command(def: CommandLineInterface) { @@ -341,8 +416,6 @@ pub fn run_cli_command(def: CommandLineInterface) { CommandLineInterface::Nested(map.insert("help", help_command_def().into())), }; - let top_def = &def; // we pass this to the help function ... - let mut args = std::env::args(); let prefix = args.next().unwrap(); @@ -370,16 +443,5 @@ pub fn run_cli_command(def: CommandLineInterface) { } } - match def { - CommandLineInterface::Simple(ref cli_cmd) => { - if let Err(_) = handle_simple_command(top_def, &prefix, &cli_cmd, args) { - std::process::exit(-1); - } - } - CommandLineInterface::Nested(ref map) => { - if let Err(_) = handle_nested_command(top_def, &prefix, &map, args) { - std::process::exit(-1); - } - } - }; + handle_command(Arc::new(def), &prefix, args); } diff --git a/src/cli/completion.rs b/src/cli/completion.rs index ede5547f..d362a086 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -1,4 +1,5 @@ use failure::*; +use std::sync::Arc; use rustyline::completion::*; @@ -196,17 +197,17 @@ pub fn get_completions( } pub struct CliHelper { - cmd_def: CommandLineInterface, + cmd_def: Arc, } impl CliHelper { pub fn new(cmd_def: CommandLineInterface) -> Self { - Self { cmd_def } + Self { cmd_def: Arc::new(cmd_def) } } - pub fn cmd_def(&self) -> &CommandLineInterface { - &self.cmd_def + pub fn cmd_def(&self) -> Arc { + self.cmd_def.clone() } } @@ -222,7 +223,7 @@ impl rustyline::completion::Completer for CliHelper { let line = &line[..pos]; - let (start, completions) = super::get_completions(&self.cmd_def, line, false); + let (start, completions) = super::get_completions(&*self.cmd_def, line, false); return Ok((start, completions)); }