aboutsummaryrefslogtreecommitdiff
path: root/src/cli
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli')
-rw-r--r--src/cli/cmd/edit.rs41
-rw-r--r--src/cli/cmd/mod.rs59
-rw-r--r--src/cli/cmd/read.rs44
-rw-r--r--src/cli/cmd/write.rs42
-rw-r--r--src/cli/mod.rs128
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,
- );
- }
-}