diff options
Diffstat (limited to 'src/cli')
| -rw-r--r-- | src/cli/cmd/edit.rs | 41 | ||||
| -rw-r--r-- | src/cli/cmd/mod.rs | 59 | ||||
| -rw-r--r-- | src/cli/cmd/read.rs | 44 | ||||
| -rw-r--r-- | src/cli/cmd/write.rs | 42 | ||||
| -rw-r--r-- | src/cli/mod.rs | 128 |
5 files changed, 0 insertions, 314 deletions
diff --git a/src/cli/cmd/edit.rs b/src/cli/cmd/edit.rs deleted file mode 100644 index b164332..0000000 --- a/src/cli/cmd/edit.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Replace the contents of the currently edited map with contents from a file. - -use super::Command; -use super::{CmdParseError, FromArgs}; -use crate::map::MapData; -use crate::Editor; -use std::path::PathBuf; - -/// Command to load a file from the disk and replace the current editor contents with it's info. -pub struct Edit { - file: PathBuf, -} - -impl FromArgs for Edit { - fn from_args(args: &[&str]) -> Result<Self, CmdParseError> { - if args.len() != 1 { - return Err(CmdParseError::WrongNumberOfArgs(args.len(), 1..=1)); - } - - Ok(Self { - file: PathBuf::from(args[0]), - }) - } -} - -impl Command for Edit { - fn process(&self, editor: &mut Editor) -> Result<String, String> { - let data = match MapData::load_from_file(&self.file) { - Ok(data) => data, - Err(err) => { - return Err(format!( - "Unable to read file: {:?}, reason: {:?}", - &self.file, err - )) - } - }; - - editor.map_mut().set_data(data); - Ok(format!("Map data from {:?} loaded.", &self.file)) - } -} diff --git a/src/cli/cmd/mod.rs b/src/cli/cmd/mod.rs deleted file mode 100644 index e00b895..0000000 --- a/src/cli/cmd/mod.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! The commands that can be performed in the CLI - -pub mod edit; -pub mod read; -pub mod write; - -pub use edit::*; -pub use read::*; -pub use write::*; - -use crate::Editor; -use std::ops::RangeInclusive; - -/// Errors that can occur when parsing a command. This is for syntax checking, the -/// semantics are checked when trying to execute the command. -#[allow(missing_docs)] -#[derive(thiserror::Error, Debug)] -pub enum CmdParseError { - #[error("no command specified")] - StringEmpty, - #[error("the command {0} is unknown")] - NoSuchCmd(String), - #[error("wrong number of arguments. Expected in range {1:?}, but received {0}")] - WrongNumberOfArgs(usize, RangeInclusive<usize>), - #[error("{0} cannot be converted into a {1}, which is required")] - InvalidArgType(String, &'static str), -} - -/// Attempts to parse a command from the given string. If it is unsuccessful, it returns a -/// [CmdParseError]. -pub fn parse_command(string: &str) -> Result<Box<dyn Command>, CmdParseError> { - if string.is_empty() { - return Err(CmdParseError::StringEmpty); - } - - let parts: Vec<&str> = string.split_whitespace().collect(); - match parts[0] { - "w" => Ok(Box::new(Write::from_args(&parts[1..])?)), - "e" => Ok(Box::new(Edit::from_args(&parts[1..])?)), - "r" => Ok(Box::new(Read::from_args(&parts[1..])?)), - other => Err(CmdParseError::NoSuchCmd(other.to_owned())), - } -} - -/// Indicates that this entity (command) can be created from arguments. Make sure to check what is -/// expected, to pass the arguments to the correct command. -pub trait FromArgs: Sized { - /// Creates a new instance from the arguments provided. If for whatever reason the syntax of the - /// given arguments is correct an [ArgParseError] is returned. - fn from_args(args: &[&str]) -> Result<Self, CmdParseError>; -} - -/// A common trait for all commands. -pub trait Command { - /// Process this command on the provided context. Returns either a string with the output of the - /// command when everything went right with it, or an error string explaining what went wrong, - /// which can be displayed to the user. - fn process(&self, editor: &mut Editor) -> Result<String, String>; -} diff --git a/src/cli/cmd/read.rs b/src/cli/cmd/read.rs deleted file mode 100644 index 45cdf99..0000000 --- a/src/cli/cmd/read.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Read the contents of a file and add it to the currently edited map. - -use super::Command; -use super::{CmdParseError, FromArgs}; -use crate::map::MapData; -use crate::Editor; -use std::path::PathBuf; - -/// Command to read a file from the system -pub struct Read { - file: PathBuf, -} - -impl FromArgs for Read { - fn from_args(args: &[&str]) -> Result<Self, CmdParseError> { - if args.len() != 1 { - return Err(CmdParseError::WrongNumberOfArgs(args.len(), 1..=1)); - } - - Ok(Self { - file: PathBuf::from(args[0]), - }) - } -} - -impl Command for Read { - fn process(&self, editor: &mut Editor) -> Result<String, String> { - let data = match MapData::load_from_file(&self.file) { - Ok(data) => data, - Err(err) => { - return Err(format!( - "Unable to read file: {:?}, reason: {:?}", - &self.file, err - )) - } - }; - - editor.map_mut().add_data(data); - Ok(format!( - "Map data from {:?} read and added to the current buffer.", - &self.file - )) - } -} diff --git a/src/cli/cmd/write.rs b/src/cli/cmd/write.rs deleted file mode 100644 index 399045c..0000000 --- a/src/cli/cmd/write.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! Save the contents of the map to disk - -use super::Command; -use super::{CmdParseError, FromArgs}; -use crate::map::MapData; -use crate::Editor; -use std::path::PathBuf; - -/// The save command can take any destination in the filesystem the user can write to. Processing -/// will then save the map contents to that destination, overwriting anything that may be there. -pub struct Write { - destination: PathBuf, -} - -impl FromArgs for Write { - fn from_args(args: &[&str]) -> Result<Self, CmdParseError> { - if args.len() != 1 { - return Err(CmdParseError::WrongNumberOfArgs(args.len(), 1..=1)); - } - - Ok(Self { - destination: PathBuf::from(args[0]), - }) - } -} - -impl Command for Write { - fn process(&self, editor: &mut Editor) -> Result<String, String> { - let data = MapData::extract_data(editor.map()); - - match data.write_to_file(&self.destination) { - Ok(_) => Ok(format!( - "Successfully wrote contents to `{:?}`", - &self.destination - )), - Err(e) => Err(format!( - "Unable to write to `{:?}`. Error: {:?}", - &self.destination, e - )), - } - } -} diff --git a/src/cli/mod.rs b/src/cli/mod.rs deleted file mode 100644 index 370a30b..0000000 --- a/src/cli/mod.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! In-window Command line interface. Used for operations that are just easier than with GUI. -//! -//! Sometimes it is nice to have a GUI, for instance when a selection has to be made, things have to -//! be moved etc., however for operations like saving/loading and exporting, no such thing has to be -//! done and the GUI is really just slowing you down (at least in my opinion). For these operations, -//! it is much better to simply have a command do that specific thing. It is also much easier to -//! implement a new command, so features can be tested more quickly. For some things, there should -//! still be a GUI option. With the example of saving/loading, it is much easier to find some hidden -//! folder in a GUI, so that is definitely a consideration for the future. - -pub mod cmd; -pub use self::cmd::*; - -use crate::colours::DEFAULT_COLOURS; -use crate::input::{Button, Input}; -use crate::math::Vec2; -use crate::Editor; -use raylib::drawing::{RaylibDraw, RaylibDrawHandle}; -use std::sync::mpsc::Receiver; - -/// The command line interface. Should be created only once per program instance. -pub struct CLI { - text: String, - char_pipe: Option<Receiver<char>>, -} - -impl CLI { - /// Create a CLI for this instance - pub fn new(input: &mut Input) -> Self { - input.add_global(Button::Text(':').into()); - - Self { - text: String::new(), - char_pipe: None, - } - } - - /// Activates the CLI, which will now capture keyboard input and execute commands accordingly. - pub fn try_activate(&mut self, input: &mut Input) { - if !self.active() { - self.char_pipe = input.try_capture_keyboard(); - - if self.char_pipe.is_some() { - self.text = ":".to_owned(); - } - } - } - - /// Deactivate the command line. - pub fn deactivate(&mut self) { - // Hang up, the input handler will get the message. - self.char_pipe = None; - } - - /// Checks if the CLI is currently active. This means input to other things should be ignored. - pub fn active(&self) -> bool { - self.char_pipe.is_some() - } - - fn perform_command(&mut self, editor: &mut Editor) { - match cmd::parse_command(&self.text[1..]) { - Ok(cmd) => match cmd.process(editor) { - Ok(res) => self.text = format!("SUCCESS: {}", res), - Err(err) => self.text = format!("ERROR: {}", err), - }, - Err(err) => self.text = format!("SYNTAX ERROR: {}", err), - } - } - - /// Handle input for the command line and perform any commands the user may want to run. - pub fn update(&mut self, editor: &mut Editor, input: &mut Input) { - /* Check if the CLI is currently active. If not and it should not be activated according to - * keyboard input, there is nothing to do. - */ - if !self.active() { - if input.poll_global(&Button::Text(':').into()) { - self.try_activate(input); - if !self.active() { - return; - } - } else { - return; - } - } - - let rx = self - .char_pipe - .as_mut() - .expect("No character pipe eventhough CLI should be active"); - - if let Ok(c) = rx.try_recv() { - match c { - '\x1B' => self.text.clear(), // Escape - '\x7f' => { - self.text.pop(); - } // Backspace - '\n' => { - self.perform_command(editor); - self.deactivate(); - } - c => self.text.push(c), - } - } - - // When the text is empty, there is also no command marker, so set as inactive and leave. - if self.text.is_empty() { - self.deactivate() - } - } - - /// Draw the command line at the bottom of the window. - pub fn draw(&self, rld: &mut RaylibDrawHandle) { - let pos = Vec2::new(150., rld.get_screen_height() as f32 - 25.); - - rld.draw_rectangle_v( - pos, - Vec2::new(rld.get_screen_width() as f32 - pos.x, 25.), - DEFAULT_COLOURS.cli_background, - ); - rld.draw_text( - &self.text, - 155, - rld.get_screen_height() - 22, - 20, - DEFAULT_COLOURS.cli_foreground, - ); - } -} |
