From 40b2fdc45f9c6c727d62aa2eba19a5599268b2b1 Mon Sep 17 00:00:00 2001 From: user622628252416 Date: Mon, 19 Aug 2024 18:33:06 +0200 Subject: [PATCH] add command usage hint after syntax error --- pumpkin/src/commands/dispatcher.rs | 6 +++-- pumpkin/src/commands/mod.rs | 3 +++ pumpkin/src/commands/tree.rs | 43 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/pumpkin/src/commands/dispatcher.rs b/pumpkin/src/commands/dispatcher.rs index fe4520c53..d65483352 100644 --- a/pumpkin/src/commands/dispatcher.rs +++ b/pumpkin/src/commands/dispatcher.rs @@ -19,7 +19,7 @@ pub(crate) struct CommandDispatcher<'a> { } impl <'a> CommandDispatcher<'a> { - pub(crate) fn dispatch(&'a self, src: &mut CommandSender, cmd: &str) -> Result<(), &str> { + pub(crate) fn dispatch(&'a self, src: &mut CommandSender, cmd: &str) -> Result<(), String> { let mut parts = cmd.split_ascii_whitespace(); let key = parts.next().ok_or("Empty Command")?; @@ -31,9 +31,11 @@ impl <'a> CommandDispatcher<'a> { match Self::try_path(src, path, tree, raw_args.clone()) { Err(InvalidConsumptionError(s)) => { println!("Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed"); + return Err("Internal Error (See logs for details)".into()) }, Err(InvalidRequirementError) => { println!("Error while parsing command \"{cmd}\": a requirement that was expected was not met."); + return Err("Internal Error (See logs for details)".into()) }, Ok(fitting_path) => { if fitting_path { return Ok(()) } @@ -41,7 +43,7 @@ impl <'a> CommandDispatcher<'a> { } } - Err("Invalid Syntax: ") + Err(format!("Invalid Syntax. Usage:{}", tree.paths_formatted(key))) } fn try_path(src: &mut CommandSender, path: Vec, tree: &CommandTree, mut raw_args: RawArgs) -> Result { diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index fc36ea18f..28e042f2d 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -4,6 +4,8 @@ use pumpkin_text::TextComponent; use crate::client::Client; use crate::commands::dispatcher::CommandDispatcher; +use crate::server::Server; + mod cmd_gamemode; mod cmd_pumpkin; mod cmd_stop; @@ -11,6 +13,7 @@ mod tree; mod tree_builder; mod dispatcher; mod arg_player; +mod cmd_teleport; pub enum CommandSender<'a> { Rcon(&'a mut Vec), diff --git a/pumpkin/src/commands/tree.rs b/pumpkin/src/commands/tree.rs index 70ac6e5bb..46b45dbba 100644 --- a/pumpkin/src/commands/tree.rs +++ b/pumpkin/src/commands/tree.rs @@ -50,6 +50,49 @@ impl <'a> CommandTree<'a> { todo, } } + + pub(crate) fn paths_formatted(&'a self, name: &str) -> String { + let paths: Vec> = self.iter_paths() + .map(|path| path.iter().map(|&i| &self.nodes[i].node_type).collect()) + .collect(); + + let len = paths.iter() + .map(|path| path.iter() + .map(|node| match node { + NodeType::ExecuteLeaf { .. } => 0, + NodeType::Literal { string } => string.len() + 1, + NodeType::Argument { name, .. } => name.len() + 3, + NodeType::Require { .. } => 0, + }) + .sum::() + name.len() + 2 + ) + .sum::(); + + let mut s = String::with_capacity(len); + + for path in paths { + s.push('\n'); + s.push('/'); + s.push_str(name); + for node in path { + match node { + NodeType::Literal { string } => { + s.push(' '); + s.push_str(string); + } + NodeType::Argument { name, .. } => { + s.push(' '); + s.push('<'); + s.push_str(name); + s.push('>'); + } + _ => {} + } + } + } + + s + } } struct TraverseAllPathsIter<'a> {