From cabc8b60a729ba17f5b75f7a7956c6d1ddcc8919 Mon Sep 17 00:00:00 2001 From: mat Date: Wed, 6 May 2026 18:38:23 -0545 Subject: azalea-brigadier now allows commands to return a Result --- azalea-brigadier/src/context/command_context.rs | 30 ++++---- .../src/context/command_context_builder.rs | 34 ++++----- azalea-brigadier/src/context/context_chain.rs | 81 ++++++++++++++-------- .../src/context/parsed_command_node.rs | 6 +- azalea-brigadier/src/context/suggestion_context.rs | 4 +- 5 files changed, 89 insertions(+), 66 deletions(-) (limited to 'azalea-brigadier/src/context') diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs index a9959895..0139f7e9 100644 --- a/azalea-brigadier/src/context/command_context.rs +++ b/azalea-brigadier/src/context/command_context.rs @@ -15,20 +15,20 @@ use crate::{ }; /// A built `CommandContextBuilder`. -pub struct CommandContext { +pub struct CommandContext { pub source: Arc, pub(super) input: String, pub(super) arguments: HashMap, - pub(super) command: Command, - pub(super) root_node: Arc>>, - pub(super) nodes: Vec>, + pub(super) command: Command, + pub(super) root_node: Arc>>, + pub(super) nodes: Vec>, pub(super) range: StringRange, - pub(super) child: Option>>, - pub(super) modifier: Option>>, + pub(super) child: Option>>, + pub(super) modifier: Option>>, pub(super) forks: bool, } -impl Clone for CommandContext { +impl Clone for CommandContext { fn clone(&self) -> Self { Self { source: self.source.clone(), @@ -45,7 +45,7 @@ impl Clone for CommandContext { } } -impl Debug for CommandContext { +impl Debug for CommandContext { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CommandContext") // .field("source", &self.source) @@ -62,7 +62,7 @@ impl Debug for CommandContext { } } -impl CommandContext { +impl CommandContext { pub fn copy_for(&self, source: Arc) -> Self { if Arc::ptr_eq(&source, &self.source) { // fast path @@ -83,11 +83,11 @@ impl CommandContext { } } - pub fn child(&self) -> Option<&CommandContext> { + pub fn child(&self) -> Option<&CommandContext> { self.child.as_ref().map(|c| c.as_ref()) } - pub fn last_child(&self) -> &CommandContext { + pub fn last_child(&self) -> &CommandContext { let mut result = self; while let Some(child) = result.child() { result = child; @@ -95,7 +95,7 @@ impl CommandContext { result } - pub fn command(&self) -> &Command { + pub fn command(&self) -> &Command { &self.command } @@ -104,7 +104,7 @@ impl CommandContext { argument.map(|a| a.result.as_ref()) } - pub fn redirect_modifier(&self) -> Option<&RedirectModifier> { + pub fn redirect_modifier(&self) -> Option<&RedirectModifier> { self.modifier.as_ref().map(|m| m.as_ref()) } @@ -116,11 +116,11 @@ impl CommandContext { &self.input } - pub fn root_node(&self) -> &Arc>> { + pub fn root_node(&self) -> &Arc>> { &self.root_node } - pub fn nodes(&self) -> &[ParsedCommandNode] { + pub fn nodes(&self) -> &[ParsedCommandNode] { &self.nodes } diff --git a/azalea-brigadier/src/context/command_context_builder.rs b/azalea-brigadier/src/context/command_context_builder.rs index a3819246..e3b09fc1 100644 --- a/azalea-brigadier/src/context/command_context_builder.rs +++ b/azalea-brigadier/src/context/command_context_builder.rs @@ -17,20 +17,20 @@ use crate::{ tree::{Command, CommandNode}, }; -pub struct CommandContextBuilder<'a, S> { +pub struct CommandContextBuilder<'a, S, R> { pub arguments: HashMap, - pub root: Arc>>, - pub nodes: Vec>, - pub dispatcher: &'a CommandDispatcher, + pub root: Arc>>, + pub nodes: Vec>, + pub dispatcher: &'a CommandDispatcher, pub source: Arc, - pub command: Command, - pub child: Option>>, + pub command: Command, + pub child: Option>>, pub range: StringRange, - pub modifier: Option>>, + pub modifier: Option>>, pub forks: bool, } -impl Clone for CommandContextBuilder<'_, S> { +impl Clone for CommandContextBuilder<'_, S, R> { fn clone(&self) -> Self { Self { arguments: self.arguments.clone(), @@ -47,11 +47,11 @@ impl Clone for CommandContextBuilder<'_, S> { } } -impl<'a, S> CommandContextBuilder<'a, S> { +impl<'a, S, R> CommandContextBuilder<'a, S, R> { pub fn new( - dispatcher: &'a CommandDispatcher, + dispatcher: &'a CommandDispatcher, source: Arc, - root_node: Arc>>, + root_node: Arc>>, start: usize, ) -> Self { Self { @@ -68,11 +68,11 @@ impl<'a, S> CommandContextBuilder<'a, S> { } } - pub fn with_command(&mut self, command: &Command) -> &Self { + pub fn with_command(&mut self, command: &Command) -> &Self { self.command.clone_from(command); self } - pub fn with_child(&mut self, child: Rc>) -> &Self { + pub fn with_child(&mut self, child: Rc>) -> &Self { self.child = Some(child); self } @@ -80,7 +80,7 @@ impl<'a, S> CommandContextBuilder<'a, S> { self.arguments.insert(name.to_owned(), argument); self } - pub fn with_node(&mut self, node: Arc>>, range: StringRange) -> &Self { + pub fn with_node(&mut self, node: Arc>>, range: StringRange) -> &Self { self.nodes.push(ParsedCommandNode { node: node.clone(), range, @@ -91,7 +91,7 @@ impl<'a, S> CommandContextBuilder<'a, S> { self } - pub fn build(&self, input: &str) -> CommandContext { + pub fn build(&self, input: &str) -> CommandContext { CommandContext { arguments: self.arguments.clone(), root_node: self.root.clone(), @@ -106,7 +106,7 @@ impl<'a, S> CommandContextBuilder<'a, S> { } } - pub fn find_suggestion_context(&self, cursor: usize) -> SuggestionContext { + pub fn find_suggestion_context(&self, cursor: usize) -> SuggestionContext { if self.range.start() > cursor { panic!("Can't find node before cursor"); } @@ -144,7 +144,7 @@ impl<'a, S> CommandContextBuilder<'a, S> { } } -impl Debug for CommandContextBuilder<'_, S> { +impl Debug for CommandContextBuilder<'_, S, R> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CommandContextBuilder") // .field("arguments", &self.arguments) diff --git a/azalea-brigadier/src/context/context_chain.rs b/azalea-brigadier/src/context/context_chain.rs index 8ad5b320..ab66fcf9 100644 --- a/azalea-brigadier/src/context/context_chain.rs +++ b/azalea-brigadier/src/context/context_chain.rs @@ -1,16 +1,22 @@ use std::{rc::Rc, sync::Arc}; use super::CommandContext; -use crate::{errors::CommandSyntaxError, result_consumer::ResultConsumer}; - -pub struct ContextChain { - modifiers: Vec>>, - executable: Rc>, - next_stage_cache: Option>>, +use crate::{ + errors::{CommandResultTrait, CommandSyntaxError}, + result_consumer::ResultConsumer, +}; + +pub struct ContextChain { + modifiers: Vec>>, + executable: Rc>, + next_stage_cache: Option>>, } -impl ContextChain { - pub fn new(modifiers: Vec>>, executable: Rc>) -> Self { +impl ContextChain { + pub fn new( + modifiers: Vec>>, + executable: Rc>, + ) -> Self { if executable.command.is_none() { panic!("Last command in chain must be executable"); } @@ -21,7 +27,7 @@ impl ContextChain { } } - pub fn try_flatten(root_context: Rc>) -> Option { + pub fn try_flatten(root_context: Rc>) -> Option { let mut modifiers = Vec::new(); let mut current = root_context; loop { @@ -39,9 +45,9 @@ impl ContextChain { } pub fn run_modifier( - modifier: Rc>, + modifier: Rc>, source: Arc, - result_consumer: &dyn ResultConsumer, + result_consumer: &dyn ResultConsumer, forked_mode: bool, ) -> Result>, CommandSyntaxError> { let source_modifier = modifier.redirect_modifier(); @@ -64,33 +70,43 @@ impl ContextChain { pub fn run_executable( &self, - executable: Rc>, + executable: Rc>, source: Arc, - result_consumer: &dyn ResultConsumer, + result_consumer: &dyn ResultConsumer, forked_mode: bool, - ) -> Result { + ) -> Result { let context_to_use = Rc::new(executable.copy_for(source)); let Some(command) = &executable.command else { unimplemented!(); }; - let err = match (command)(&context_to_use) { - Ok(result) => { - result_consumer.on_command_complete(context_to_use, true, result); - return if forked_mode { Ok(1) } else { Ok(result) }; + let res = (command)(&context_to_use); + let err = match res { + Ok(res) => { + let Some(res) = res.as_i32() else { + // these are treated as exceptions, so they can bubble up without doing anything + // else + return Ok(res); + }; + result_consumer.on_command_complete(context_to_use, true, res); + return if forked_mode { + Ok(R::new(1)) + } else { + Ok(R::new(res)) + }; } Err(err) => err, }; result_consumer.on_command_complete(context_to_use, false, 0); - if forked_mode { Ok(0) } else { Err(err) } + if forked_mode { Ok(R::new(0)) } else { Err(err) } } pub fn execute_all( &self, source: Arc, - result_consumer: &dyn ResultConsumer, - ) -> Result { + result_consumer: &dyn ResultConsumer, + ) -> Result { if self.modifiers.is_empty() { return self.run_executable(self.executable.clone(), source, result_consumer, false); } @@ -103,30 +119,37 @@ impl ContextChain { let mut next_sources = Vec::new(); for source_to_run in current_sources { - next_sources.extend(Self::run_modifier( + match Self::run_modifier( modifier.clone(), source_to_run.clone(), result_consumer, forked_mode, - )?); + ) { + Ok(res) => next_sources.extend(res), + Err(err) => return Err(err), + } } if next_sources.is_empty() { - return Ok(0); + return Ok(R::new(0)); } current_sources = next_sources; } - let mut result = 0; + let mut summed = 0; for execution_source in current_sources { - result += self.run_executable( + let res = self.run_executable( self.executable.clone(), execution_source, result_consumer, forked_mode, )?; + match res.as_i32() { + Some(res) => summed += res, + None => return Ok(res), + } } - Ok(result) + Ok(R::new(summed)) } pub fn stage(&self) -> Stage { @@ -137,14 +160,14 @@ impl ContextChain { } } - pub fn top_context(&self) -> Rc> { + pub fn top_context(&self) -> Rc> { self.modifiers .first() .cloned() .unwrap_or_else(|| self.executable.clone()) } - pub fn next_stage(&mut self) -> Option>> { + pub fn next_stage(&mut self) -> Option>> { let modifier_count = self.modifiers.len(); if modifier_count == 0 { return None; diff --git a/azalea-brigadier/src/context/parsed_command_node.rs b/azalea-brigadier/src/context/parsed_command_node.rs index 62da13d8..8dbadb49 100644 --- a/azalea-brigadier/src/context/parsed_command_node.rs +++ b/azalea-brigadier/src/context/parsed_command_node.rs @@ -6,12 +6,12 @@ use super::string_range::StringRange; use crate::tree::CommandNode; #[derive(Debug)] -pub struct ParsedCommandNode { - pub node: Arc>>, +pub struct ParsedCommandNode { + pub node: Arc>>, pub range: StringRange, } -impl Clone for ParsedCommandNode { +impl Clone for ParsedCommandNode { fn clone(&self) -> Self { Self { node: self.node.clone(), diff --git a/azalea-brigadier/src/context/suggestion_context.rs b/azalea-brigadier/src/context/suggestion_context.rs index 58a73fdb..ed3dbfa2 100644 --- a/azalea-brigadier/src/context/suggestion_context.rs +++ b/azalea-brigadier/src/context/suggestion_context.rs @@ -5,7 +5,7 @@ use parking_lot::RwLock; use crate::tree::CommandNode; #[derive(Debug)] -pub struct SuggestionContext { - pub parent: Arc>>, +pub struct SuggestionContext { + pub parent: Arc>>, pub start_pos: usize, } -- cgit v1.2.3