src/cli/command.rs: implement help
This commit is contained in:
parent
8423c1fe64
commit
1201abcffa
|
@ -37,7 +37,6 @@ fn command_map() -> CliCommandMap {
|
||||||
cmd_def
|
cmd_def
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
|
|
||||||
let def = CommandLineInterface::Nested(command_map());
|
let def = CommandLineInterface::Nested(command_map());
|
||||||
|
@ -58,14 +57,8 @@ fn main() -> Result<(), Error> {
|
||||||
let args = shellword_split(&line)?;
|
let args = shellword_split(&line)?;
|
||||||
|
|
||||||
let def = helper.cmd_def();
|
let def = helper.cmd_def();
|
||||||
let _ = match def {
|
|
||||||
CommandLineInterface::Simple(ref cli_cmd) => {
|
handle_command(def, "", args);
|
||||||
handle_simple_command(def, "", &cli_cmd, args)
|
|
||||||
}
|
|
||||||
CommandLineInterface::Nested(ref map) => {
|
|
||||||
handle_nested_command(def, "", &map, args)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use failure::*;
|
use failure::*;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use proxmox::api::*;
|
||||||
use proxmox::api::format::*;
|
use proxmox::api::format::*;
|
||||||
use proxmox::api::schema::*;
|
use proxmox::api::schema::*;
|
||||||
use proxmox::api::{ApiHandler, ApiMethod};
|
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 API_METHOD_COMMAND_HELP: ApiMethod = ApiMethod::new(
|
||||||
const COMMAND_HELP: ObjectSchema = ObjectSchema::new(
|
&ApiHandler::Sync(&help_command),
|
||||||
|
&ObjectSchema::new(
|
||||||
"Get help about specified command.",
|
"Get help about specified command.",
|
||||||
&[ ("verbose", true, &VERBOSE_HELP_SCHEMA) ]
|
&[
|
||||||
|
( "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<Option<Arc<CommandLineInterface>>> = RefCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn help_command(
|
||||||
|
param: Value,
|
||||||
|
_info: &ApiMethod,
|
||||||
|
_rpcenv: &mut dyn RpcEnvironment,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
|
|
||||||
|
|
||||||
|
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<Arc<CommandLineInterface>>) {
|
||||||
|
HELP_CONTEXT.with(|ctx| { *ctx.borrow_mut() = def; });
|
||||||
|
}
|
||||||
|
|
||||||
pub fn help_command_def() -> CliCommand {
|
pub fn help_command_def() -> CliCommand {
|
||||||
CliCommand::new(&API_METHOD_COMMAND_HELP)
|
CliCommand::new(&API_METHOD_COMMAND_HELP)
|
||||||
|
.arg_param(&["command"])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_command(
|
||||||
|
def: Arc<CommandLineInterface>,
|
||||||
|
prefix: &str,
|
||||||
|
args: Vec<String>,
|
||||||
|
) {
|
||||||
|
|
||||||
|
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) {
|
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())),
|
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 mut args = std::env::args();
|
||||||
|
|
||||||
let prefix = args.next().unwrap();
|
let prefix = args.next().unwrap();
|
||||||
|
@ -370,16 +443,5 @@ pub fn run_cli_command(def: CommandLineInterface) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match def {
|
handle_command(Arc::new(def), &prefix, args);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use failure::*;
|
use failure::*;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustyline::completion::*;
|
use rustyline::completion::*;
|
||||||
|
|
||||||
|
@ -196,17 +197,17 @@ pub fn get_completions(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CliHelper {
|
pub struct CliHelper {
|
||||||
cmd_def: CommandLineInterface,
|
cmd_def: Arc<CommandLineInterface>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CliHelper {
|
impl CliHelper {
|
||||||
|
|
||||||
pub fn new(cmd_def: CommandLineInterface) -> Self {
|
pub fn new(cmd_def: CommandLineInterface) -> Self {
|
||||||
Self { cmd_def }
|
Self { cmd_def: Arc::new(cmd_def) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmd_def(&self) -> &CommandLineInterface {
|
pub fn cmd_def(&self) -> Arc<CommandLineInterface> {
|
||||||
&self.cmd_def
|
self.cmd_def.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +223,7 @@ impl rustyline::completion::Completer for CliHelper {
|
||||||
|
|
||||||
let line = &line[..pos];
|
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));
|
return Ok((start, completions));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue