-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
464 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[package] | ||
name = "commands" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
thiserror = { workspace = true } | ||
tracing = { workspace = true } | ||
dashmap = { workspace = true } | ||
tokio = { workspace = true } | ||
ferrumc-text = { workspace = true } | ||
ferrumc-state = { workspace = true } | ||
|
||
[dev-dependencies] # Needed for the ServerState mock... :concern: | ||
ferrumc-ecs = { workspace = true } | ||
ferrumc-world = { workspace = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use parser::ArgumentParser; | ||
|
||
pub mod parser; | ||
|
||
pub struct CommandArgument { | ||
pub name: String, | ||
pub required: bool, | ||
pub parser: Box<dyn ArgumentParser>, | ||
} | ||
|
||
impl CommandArgument { | ||
pub fn new(name: String, required: bool, parser: Box<dyn ArgumentParser>) -> Self { | ||
CommandArgument { | ||
name, | ||
required, | ||
parser, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use std::sync::{Arc, Mutex}; | ||
|
||
use crate::{ctx::CommandContext, input::CommandInput, ParserResult}; | ||
|
||
use super::{utils::error, ArgumentParser}; | ||
|
||
pub struct IntParser; | ||
|
||
impl ArgumentParser for IntParser { | ||
fn parse(&self, _ctx: Arc<&CommandContext>, input: Arc<Mutex<CommandInput>>) -> ParserResult { | ||
let token = input.lock().unwrap().read_string(); | ||
|
||
match token.parse::<u32>() { | ||
Ok(int) => Ok(Box::new(int)), | ||
Err(err) => Err(error(err)) | ||
} | ||
} | ||
|
||
fn new() -> Self | ||
where | ||
Self: Sized, | ||
{ | ||
IntParser | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use std::sync::{Arc, Mutex}; | ||
|
||
use crate::{ctx::CommandContext, input::CommandInput, ParserResult}; | ||
|
||
pub mod int; | ||
pub mod string; | ||
|
||
pub(crate) mod utils; | ||
|
||
pub trait ArgumentParser: Send + Sync { | ||
fn parse( | ||
&self, | ||
context: Arc<&CommandContext>, | ||
input: Arc<Mutex<CommandInput>>, | ||
) -> ParserResult; | ||
fn new() -> Self | ||
where | ||
Self: Sized; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use std::sync::{Arc, Mutex}; | ||
|
||
use crate::{ctx::CommandContext, input::CommandInput, ParserResult}; | ||
|
||
use super::ArgumentParser; | ||
|
||
pub struct SingleStringParser; | ||
|
||
impl ArgumentParser for SingleStringParser { | ||
fn parse(&self, _ctx: Arc<&CommandContext>, input: Arc<Mutex<CommandInput>>) -> ParserResult { | ||
Ok(Box::new(input.lock().unwrap().read_string())) | ||
} | ||
|
||
fn new() -> Self | ||
where | ||
Self: Sized, | ||
{ | ||
SingleStringParser | ||
} | ||
} | ||
|
||
pub struct GreedyStringParser; | ||
|
||
impl ArgumentParser for GreedyStringParser { | ||
fn parse(&self, _ctx: Arc<&CommandContext>, input: Arc<Mutex<CommandInput>>) -> ParserResult { | ||
let mut result = String::new(); | ||
|
||
loop { | ||
let token = input.lock().unwrap().read_string_skip_whitespace(false); | ||
|
||
if token.is_empty() { | ||
break; | ||
} | ||
|
||
if !result.is_empty() { | ||
result.push(' '); | ||
} | ||
result.push_str(&token); | ||
} | ||
|
||
Ok(Box::new(result)) | ||
} | ||
|
||
fn new() -> Self | ||
where | ||
Self: Sized, | ||
{ | ||
GreedyStringParser | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
use std::error::Error; | ||
|
||
use ferrumc_text::{NamedColor, TextComponent, TextComponentBuilder}; | ||
|
||
pub(crate) fn error(err: impl Error) -> TextComponent { | ||
TextComponentBuilder::new(err.to_string()).color(NamedColor::Red).build() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
use std::{ | ||
any::Any, | ||
sync::{Arc, Mutex}, | ||
}; | ||
|
||
use ferrumc_state::GlobalState; | ||
|
||
use crate::{input::CommandInput, Command}; | ||
|
||
pub struct CommandContext { | ||
pub input: Arc<Mutex<CommandInput>>, | ||
pub command: Arc<Command>, | ||
pub state: GlobalState, | ||
} | ||
|
||
impl CommandContext { | ||
pub fn new(input: CommandInput, command: Arc<Command>, state: GlobalState) -> Arc<Self> { | ||
Arc::new(Self { | ||
input: Arc::new(Mutex::new(input)), | ||
command, | ||
state, | ||
}) | ||
} | ||
|
||
pub fn arg<T: Any>(&self, name: &str) -> T { | ||
if let Some(arg) = self.command.args.iter().find(|a| a.name == name) { | ||
let input = self.input.clone(); | ||
let result = arg.parser.parse(Arc::new(self), input); | ||
|
||
return match result { | ||
Ok(b) => match b.downcast::<T>() { | ||
Ok(value) => *value, | ||
Err(_) => { | ||
todo!("failed downcasting command argument, change design of this fn"); | ||
} | ||
}, | ||
Err(_) => unreachable!("arg has already been validated") | ||
}; | ||
} else { | ||
todo!(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
use thiserror::Error; | ||
|
||
#[derive(Debug, Clone, Error)] | ||
pub enum CommandError { | ||
#[error("Something failed lol")] | ||
SomeError, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
use dashmap::DashMap; | ||
use std::sync::{Arc, LazyLock}; | ||
|
||
use crate::Command; | ||
|
||
static COMMANDS: LazyLock<DashMap<&'static str, Arc<Command>>> = LazyLock::new(DashMap::new); | ||
|
||
pub fn register_command(command: Arc<Command>) { | ||
COMMANDS.insert(command.name, command); | ||
} | ||
|
||
pub fn get_command_by_name(name: &'static str) -> Option<Arc<Command>> { | ||
COMMANDS.get(name).map(|cmd_ref| Arc::clone(&cmd_ref)) | ||
} | ||
|
||
pub fn find_command(input: &'static str) -> Option<Arc<Command>> { | ||
let mut command = None; | ||
let mut input = input; | ||
|
||
while !input.is_empty() { | ||
command = get_command_by_name(input); | ||
if command.is_some() { | ||
break; | ||
} | ||
|
||
if let Some(pos) = input.rfind(' ') { | ||
input = &input[..pos]; | ||
} else { | ||
input = ""; | ||
} | ||
} | ||
|
||
command | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/// Very based on Cloud, this is gonna have to be changed up a bit probably. | ||
#[derive(Clone)] | ||
pub struct CommandInput { | ||
pub input: String, | ||
pub cursor: u32, | ||
} | ||
|
||
impl CommandInput { | ||
pub fn of(string: String) -> Self { | ||
Self { | ||
input: string, | ||
cursor: 0, | ||
} | ||
} | ||
pub fn append_string(&mut self, string: String) { | ||
self.input += &*string; | ||
} | ||
pub fn move_cursor(&mut self, chars: u32) { | ||
if self.cursor + chars > self.input.len() as u32 { | ||
return; | ||
} | ||
|
||
self.cursor += chars; | ||
} | ||
pub fn remaining_length(&self) -> u32 { | ||
self.input.len() as u32 - self.cursor | ||
} | ||
pub fn peek(&self) -> Option<char> { | ||
self.input.chars().nth(self.cursor as usize) | ||
} | ||
pub fn has_remaining_input(&self) -> bool { | ||
self.cursor < self.input.len() as u32 | ||
} | ||
pub fn skip_whitespace(&mut self, max_spaces: u32, preserve_single: bool) { | ||
if preserve_single && self.remaining_length() == 1 && self.peek() == Some(' ') { | ||
return; | ||
} | ||
|
||
let mut i = 0; | ||
while i < max_spaces | ||
&& self.has_remaining_input() | ||
&& self.peek().map_or(false, |c| c.is_whitespace()) | ||
{ | ||
self.read(1); | ||
i += 1; | ||
} | ||
} | ||
pub fn remaining_input(&self) -> String { | ||
self.input[..self.cursor as usize].to_string() | ||
} | ||
pub fn peek_string_chars(&self, chars: u32) -> String { | ||
let remaining = self.remaining_input(); | ||
if chars > remaining.len() as u32 { | ||
return "".to_string(); | ||
} | ||
|
||
remaining[0..chars as usize].to_string() | ||
} | ||
pub fn read(&mut self, chars: u32) -> String { | ||
let read_string = self.peek_string_chars(chars); | ||
self.move_cursor(chars); | ||
read_string | ||
} | ||
pub fn remaining_tokens(&self) -> u32 { | ||
let count = self.remaining_input().split(' ').count() as u32; | ||
if self.remaining_input().ends_with(' ') { | ||
return count + 1; | ||
} | ||
count | ||
} | ||
pub fn read_string(&mut self) -> String { | ||
self.skip_whitespace(u32::MAX, false); | ||
let mut result = String::new(); | ||
while let Some(c) = self.peek() { | ||
if c.is_whitespace() { | ||
break; | ||
} | ||
result.push(c); | ||
self.move_cursor(1); | ||
} | ||
result | ||
} | ||
pub fn peek_string(&self) -> String { | ||
let remaining = self.remaining_input(); | ||
remaining | ||
.split_whitespace() | ||
.next() | ||
.unwrap_or("") | ||
.to_string() | ||
} | ||
pub fn read_until(&mut self, separator: char) -> String { | ||
self.skip_whitespace(u32::MAX, false); | ||
let mut result = String::new(); | ||
while let Some(c) = self.peek() { | ||
if c == separator { | ||
self.move_cursor(1); | ||
break; | ||
} | ||
result.push(c); | ||
self.move_cursor(1); | ||
} | ||
result | ||
} | ||
pub fn read_string_skip_whitespace(&mut self, preserve_single: bool) -> String { | ||
let read_string = self.read_string(); | ||
self.skip_whitespace(u32::MAX, preserve_single); | ||
read_string | ||
} | ||
} |
Oops, something went wrong.