diff --git a/Cargo.lock b/Cargo.lock index 759b256..181511b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,7 +96,7 @@ dependencies = [ [[package]] name = "merlin" -version = "1.2.1" +version = "1.3.0" dependencies = [ "clap", "ctrlc", diff --git a/Cargo.toml b/Cargo.toml index bb670ce..16f43e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "merlin" -version = "1.2.1" +version = "1.3.0" authors = ["geremachek "] edition = "2018" diff --git a/src/commands/mod.rs b/src/commands/mod.rs index deddc77..151477f 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -29,6 +29,7 @@ pub enum Command { Burn, Shave, Molecule, + Atoms, Pen, Orbit, Decay, @@ -40,6 +41,8 @@ pub enum Command { Scribe, Adieu, Nomen, + Disenchant, + Smash, Merlin, Summon, Dub, @@ -52,91 +55,85 @@ impl FromStr for Command { fn from_str(cmd: &str) -> Result { match cmd { - "genesis" => Ok(Command::Genesis), - "spine" => Ok(Command::Spine), - "carved" => Ok(Command::Carved), - "incant" => Ok(Command::Incant), - "infuse" => Ok(Command::Infuse), - "shelve" => Ok(Command::Shelve), - "focus" => Ok(Command::Focus), - "volume" => Ok(Command::Volume), - "volumes" => Ok(Command::Volumes), - "spot" => Ok(Command::Spot), - "span" => Ok(Command::Span), - "pin" => Ok(Command::Pin), - "columns" => Ok(Command::Columns), - "traverse" => Ok(Command::Traverse), - "shift" => Ok(Command::Shift), - "appear" => Ok(Command::Appear), - "infix" => Ok(Command::Infix), - "peer" => Ok(Command::Peer), - "inscribe" => Ok(Command::Inscribe), - "trample" => Ok(Command::Trample), - "burn" => Ok(Command::Burn), - "shave" => Ok(Command::Shave), - "molecule" => Ok(Command::Molecule), - "pen" => Ok(Command::Pen), - "orbit" => Ok(Command::Orbit), - "decay" => Ok(Command::Decay), - "destroy" => Ok(Command::Destroy), - "tether" => Ok(Command::Tether), - "fray" => Ok(Command::Fray), - "mirror" => Ok(Command::Mirror), - "atom" => Ok(Command::Atom), - "scribe" => Ok(Command::Scribe), - "adieu" => Ok(Command::Adieu), - "nomen" => Ok(Command::Nomen), - "merlin" => Ok(Command::Merlin), - "summon" => Ok(Command::Summon), - "dub" => Ok(Command::Dub), - "carve" => Ok(Command::Carve), - "spellbook" => Ok(Command::Spellbook), - _ => Err(MerlinError::UnknownCommand), + "genesis" => Ok(Command::Genesis), + "spine" => Ok(Command::Spine), + "carved" => Ok(Command::Carved), + "incant" => Ok(Command::Incant), + "infuse" => Ok(Command::Infuse), + "shelve" => Ok(Command::Shelve), + "focus" => Ok(Command::Focus), + "volume" => Ok(Command::Volume), + "volumes" => Ok(Command::Volumes), + "spot" => Ok(Command::Spot), + "span" => Ok(Command::Span), + "pin" => Ok(Command::Pin), + "columns" => Ok(Command::Columns), + "traverse" => Ok(Command::Traverse), + "shift" => Ok(Command::Shift), + "appear" => Ok(Command::Appear), + "infix" => Ok(Command::Infix), + "peer" => Ok(Command::Peer), + "inscribe" => Ok(Command::Inscribe), + "trample" => Ok(Command::Trample), + "burn" => Ok(Command::Burn), + "shave" => Ok(Command::Shave), + "molecule" => Ok(Command::Molecule), + "atoms" => Ok(Command::Atoms), + "pen" => Ok(Command::Pen), + "orbit" => Ok(Command::Orbit), + "decay" => Ok(Command::Decay), + "destroy" => Ok(Command::Destroy), + "tether" => Ok(Command::Tether), + "fray" => Ok(Command::Fray), + "mirror" => Ok(Command::Mirror), + "atom" => Ok(Command::Atom), + "scribe" => Ok(Command::Scribe), + "adieu" => Ok(Command::Adieu), + "nomen" => Ok(Command::Nomen), + "disenchant" => Ok(Command::Disenchant), + "smash" => Ok(Command::Smash), + "merlin" => Ok(Command::Merlin), + "summon" => Ok(Command::Summon), + "dub" => Ok(Command::Dub), + "carve" => Ok(Command::Carve), + "spellbook" => Ok(Command::Spellbook), + _ => Err(MerlinError::UnknownCommand), } } } impl Command { - // check if the right amount of arguments have been supplied - - fn valid(&self, args: usize) -> bool { - match self { - Command::Genesis | Command::Spot | Command::Span | Command::Pin | Command::Columns | Command::Molecule | Command::Pen | Command::Orbit | - Command::Decay | Command::Destroy | Command::Mirror | Command::Atom | Command::Scribe | Command::Adieu | Command::Carve | Command::Burn | Command::Volume | - Command::Volumes | Command::Carved => true, - Command::Focus | Command::Traverse | Command::Appear | Command::Shave | Command::Shelve | Command::Incant | Command::Inscribe | Command::Trample | Command::Summon | - Command::Dub | Command::Spellbook | Command::Shift | Command::Infix | Command::Spine | Command::Nomen | Command::Merlin => args >= 1, - Command::Infuse | Command::Tether | Command::Fray | Command::Peer => args >= 2, - } - } - // check if the number of arguments are valid, and if so return the needed amount of arguments pub fn get_needed(&self, args: usize) -> Result { - if self.valid(args) { - // choose the number of atoms we need, based on those available + // choose the number of atoms we need, based on those available - let choose_mm = |max, min| { - if args >= max { - return max; - } + let choose_mm = |max, min| { + if args >= max { + max + } else { + min + } + }; - return min; - }; + let needed = match self { + Command::Tether => choose_mm(3, args+1), // we need a minimum of 3 + Command::Nomen => choose_mm(2, args+1), // min of 1 + Command::Spot | Command::Span | Command::Molecule | Command::Pen | Command::Orbit | Command::Decay | Command::Destroy | Command::Mirror | + Command::Atom | Command::Scribe | Command::Adieu | Command::Carve | Command::Pin | Command::Columns | Command::Burn | Command::Volume | + Command::Volumes | Command::Carved | Command::Atoms => 0, + Command::Focus | Command::Traverse | Command::Appear | Command::Shave | Command::Shelve | Command::Inscribe | Command::Trample | Command::Incant | + Command::Summon | Command::Dub | Command::Spellbook | Command::Shift | Command::Infix | Command::Spine | Command::Merlin | Command::Disenchant | + Command::Smash => 1, + Command::Infuse | Command::Peer | Command::Fray => 2, + Command::Genesis => choose_mm(1, 0), + }; - match self { - Command::Tether | Command::Nomen => return Ok(args), - Command::Spot | Command::Span | Command::Molecule | Command::Pen | Command::Orbit | Command::Decay | Command::Destroy | Command::Mirror | - Command::Atom | Command::Scribe | Command::Adieu | Command::Carve | Command::Pin | Command::Columns | Command::Burn | Command::Volume | - Command::Volumes | Command::Carved => return Ok(0), - Command::Focus | Command::Traverse | Command::Appear | Command::Shave | Command::Shelve | Command::Inscribe | Command::Trample | Command::Incant | - Command::Summon | Command::Dub | Command::Spellbook | Command::Shift | Command::Infix | Command::Spine | Command::Merlin => return Ok(1), - Command::Infuse | Command::Peer | Command::Fray => return Ok(2), - Command::Genesis => return Ok(choose_mm(1, 0)) - } + if needed <= args { + Ok(needed) + } else { + Err(MerlinError::InvalidOrNoArguments) } - - return Err(MerlinError::InvalidOrNoArguments); } } diff --git a/src/error.rs b/src/error.rs index 9a15574..79f7867 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,6 +14,7 @@ pub enum MerlinError { ReadFailed, FileAlreadyExists, BufferNotNamed, + UnknownNomen, } impl fmt::Display for MerlinError { @@ -28,7 +29,8 @@ impl fmt::Display for MerlinError { MerlinError::CreationOrWriteFailed => "failed to create / write a file", MerlinError::ReadFailed => "failed to read a file", MerlinError::FileAlreadyExists => "file already exists", - MerlinError::BufferNotNamed => "buffer is not named" + MerlinError::BufferNotNamed => "buffer is not named", + MerlinError::UnknownNomen => "unknown nomen", }; write!(f, "merlin: {}", msg) diff --git a/src/plane/mod.rs b/src/plane/mod.rs index 972b04c..cdd9b78 100644 --- a/src/plane/mod.rs +++ b/src/plane/mod.rs @@ -1,4 +1,4 @@ -use crate::{volume::Volume}; +use crate::{volume::Volume, error::MerlinError}; use stack::Stack; use nomen::Nomen; @@ -75,6 +75,12 @@ impl Plane { self.nomens.iter().position(|n| n == name) } + // get_nomen but it returns an error if it can't find what it's looking for + + fn get_nomen_err(&self, name: &str) -> Result { + self.get_nomen(name).ok_or(MerlinError::UnknownNomen) + } + // add a new volume fn push_volume(&mut self, v: Volume) { diff --git a/src/plane/parse.rs b/src/plane/parse.rs index 16558eb..c584265 100644 --- a/src/plane/parse.rs +++ b/src/plane/parse.rs @@ -140,6 +140,8 @@ impl Plane { let n = data.pop().unwrap(); self.nomen(data, n); } + Command::Disenchant => self.disenchant(&data[0])?, + Command::Smash => self.smash(&data[0])?, Command::Merlin => { // make sure we are always *starting* in atom mode, but preserving the original mode // for when we finish parsing @@ -159,6 +161,7 @@ impl Plane { Command::Spellbook => self.spellbook(&data[0])?, Command::Volume => return oksome(self.volume().to_string()), Command::Volumes => return oksome(self.volumes.len().to_string()), + Command::Atoms => return oksome(self.stack.len().to_string()), _ => { // the following commands require buffers to be open if self.volumes.len() > 0 { // buffers / files are open let cvol = &mut self.volumes[self.current_volume]; // current volume diff --git a/src/plane/plane_commands.rs b/src/plane/plane_commands.rs index c3310a1..4a1135a 100644 --- a/src/plane/plane_commands.rs +++ b/src/plane/plane_commands.rs @@ -60,13 +60,30 @@ impl Plane { Ok(()) } + // "clear" a nomen + + pub fn disenchant(&mut self, name: &str) -> Result<(), MerlinError> { + // empty the vector of atoms for a certain nomen, reutrn an error if we can't find it + + let nomen_index = self.get_nomen_err(name)?; + Ok(self.nomens[nomen_index] + .atoms + .clear()) + } + + // remove a nomen + + pub fn smash(&mut self, name: &str) -> Result<(), MerlinError> { + // remove the nomen from the list if it exists, otherwise return an error + + let _ = self.nomens.remove(self.get_nomen_err(name)?); + Ok(()) + } + // create a new nomen pub fn nomen(&mut self, atoms: Vec, name: String) { - if let Some(i) = self.get_nomen(&name) { - self.nomens.remove(i); - } - + let _ = self.smash(&name); // remove the nomen if it exists self.nomens.push(Nomen::new(name, atoms)) }