From fedd4c31b0d1c6d036b1105a74b6e6a1f135f2b4 Mon Sep 17 00:00:00 2001 From: Rory Dudley Date: Fri, 14 Jun 2024 20:29:32 -0400 Subject: Add back spellcheck This commit reworks spellcheck() so it is more verbose about what it returns. It also re-introduces the use of spellcheck() in Poem::recite(). Spellcheck now returns a value in the enum, Spelling: FullPath -> Indicates a full path was specified as the verb OnPath -> Indicates the verb is on the $PATH BuiltIn -> Indicates the verb is a built-in command None (Option) -> The verb does not exist This commit also removes some defunct (commented-out) code. --- src/poem/anthology.rs | 41 +++--------------------------------- src/poem/anthology/which.rs | 29 ++++++++++++++------------ src/poem/elements/verse.rs | 31 ++++++++++++++++++++------- src/poem/recite.rs | 51 +++++++++++++++++++-------------------------- 4 files changed, 64 insertions(+), 88 deletions(-) diff --git a/src/poem/anthology.rs b/src/poem/anthology.rs index a35eafb..086864c 100644 --- a/src/poem/anthology.rs +++ b/src/poem/anthology.rs @@ -29,38 +29,6 @@ pub fn lookup(verb: &str) -> Option { INDEX.iter().position(|v| v.to_string() == verb) } -/// Run a builtin command, based on its verb -/// -/// Use [lookup] to check if a verb is in the anthology's index (i.e. is a -/// builtin), then call this with the current verse, the index found by -/// [lookup], and the shell's global environment state. -/// -/// # Example -/// ``` -/// let index = anthology::lookup(verse.verb()); -/// if index.is_some() { -/// anthology::incant(&verse, index.unwrap(), env); -/// } else { -/// // Run an external command -/// ... -/// } -/// ``` -// pub fn incant(verse: &Verse, out: &mut Vec, index: usize, env: &mut Environment) -> i32 { -// // let verb = INDEX[index]; -// // match verb { -// // "alias" => alias::incant(verse, out, &mut env.aliases), -// // "cd" => cd::incant(verse), -// // "exit" => exit::incant(), -// // "export" => export::incant(verse), -// // "source" => source::incant(verse, out, env), -// // "unalias" => alias::unincant(verse, &mut env.aliases), -// // "unset" => export::unincant(verse), -// // "which" => which::incant(verse, out, env), -// // _ => unreachable!(), -// // } -// 0 -// } - #[derive(Debug, PartialEq, Eq, Clone)] pub struct AnthologyStdin { data: Vec, @@ -101,9 +69,9 @@ impl Anthology { /// ``` /// let mut command = Anthology::new("alias"); /// ``` - pub fn new(verb: String) -> Self { + pub fn new(i: usize) -> Self { Anthology { - verb, + verb: INDEX[i].to_string(), clause: None, uin: false, uout: false, @@ -148,11 +116,8 @@ impl Anthology { } pub fn spawn(&mut self, env: &mut Environment) -> Result { - let index = lookup(self.verb.as_str()).unwrap(); - let verb = INDEX[index]; - // Incant the built-in and set the output - self.output = Some(match verb { + self.output = Some(match self.verb.as_str() { "alias" => alias::incant(&self.clause, self.uout, &mut env.aliases), "cd" => cd::incant(&self.clause, self.uerr), "exit" => exit::incant(), diff --git a/src/poem/anthology/which.rs b/src/poem/anthology/which.rs index 6fe709c..0872dda 100644 --- a/src/poem/anthology/which.rs +++ b/src/poem/anthology/which.rs @@ -1,4 +1,5 @@ use crate::compose::Environment; +use crate::poem::elements::verse::Spelling; use crate::poem::Verse; use std::os::unix::process::ExitStatusExt; use std::process::{ExitStatus, Output}; @@ -22,26 +23,28 @@ pub fn incant(clause: &Option>, uout: bool, uerr: bool, env: &Enviro continue; } - // Check if it's a built-in - match super::lookup(&word) { - Some(_) => { + // Manually check the path + let mut verb = Verse::new(); + verb.push(word.clone()); + match verb.spellcheck(&env.bins) { + Some(Spelling::OnPath(i)) => { + output = format!("{}\n", env.bins[i]); + if uout { + out.append(&mut output.as_bytes().to_vec()); + } else { + print!("{}", output); + } + } + Some(Spelling::BuiltIn(_)) => { output = format!("{}: shell built-in command\n", word); if uout { out.append(&mut output.as_bytes().to_vec()); } else { print!("{}", output); } - continue; } - None => {} - } - - // Manually check the path - let mut verb = Verse::new(); - verb.push(word.clone()); - match verb.spellcheck(&env.bins) { - Some(i) => { - output = format!("{}\n", env.bins[i]); + Some(Spelling::FullPath) => { + output = format!("{}\n", word); if uout { out.append(&mut output.as_bytes().to_vec()); } else { diff --git a/src/poem/elements/verse.rs b/src/poem/elements/verse.rs index 42d7c6a..b4f41ba 100644 --- a/src/poem/elements/verse.rs +++ b/src/poem/elements/verse.rs @@ -1,6 +1,7 @@ use super::rune::Rune; use super::stanza::Stanza; use super::word::Word; +use crate::poem::anthology; use crate::poem::anthology::Anthology; use crate::poem::Poem; mod logic; @@ -32,6 +33,13 @@ pub struct Verse { pub meter: Rune, } +#[derive(Debug, Clone)] +pub enum Spelling { + FullPath, + OnPath(usize), + BuiltIn(usize), +} + pub trait Forkable { fn fork(&mut self, env: &mut Environment) -> Result; } @@ -216,7 +224,7 @@ impl Verse { /// stanza_success.spellcheck(bins) // -> Some(i) /// stanza_fail.spellcheck(bins) // -> None /// ``` - pub fn spellcheck(&self, bins: &Vec) -> Option { + pub fn spellcheck(&self, bins: &Vec) -> Option { // An empty verb (i.e. the empty string) cannot be a program, so // return false // Thanks to the parsing in Poem::read, however, it's @@ -225,6 +233,13 @@ impl Verse { return None; } + // Check for built-ins + let i = anthology::lookup(self.verb().as_str()); + match i { + Some(i) => return Some(Spelling::BuiltIn(i)), + None => {} + }; + // Only search the $PATH if a full or relative path was not given, or // if the path given does not exist if !Path::new(self.verb().as_str()).exists() { @@ -232,7 +247,7 @@ impl Verse { // Searches in $PATH order for (i, path) in bins.iter().enumerate() { if path.split('/').last().unwrap() == self.verb() { - return Some(i); + return Some(Spelling::OnPath(i)); } } @@ -241,7 +256,7 @@ impl Verse { } // Return the length of bins if the full path or relative path exists - Some(bins.len()) + Some(Spelling::FullPath) } /// Run a command @@ -256,7 +271,7 @@ impl Verse { out: &mut Vec, pids: &mut Arc>>, env: &mut Environment, - anthology: Option, + spell: Option, ) -> Result { // Read files into 'out' if Rune::Read is present in the verse's IO if self.io.contains(&Rune::Read) { @@ -274,12 +289,12 @@ impl Verse { } // Build and run the command - match anthology { - Some(_) => { - let mut command = Anthology::new(self.verb()); + match spell { + Some(Spelling::BuiltIn(i)) => { + let mut command = Anthology::new(i); incant!(self.verb(), command, out, pids, env, self) } - None => { + _ => { let mut command = Command::new(self.verb()); incant!(self.verb(), command, out, pids, env, self) } diff --git a/src/poem/recite.rs b/src/poem/recite.rs index b33cc87..b27ef75 100644 --- a/src/poem/recite.rs +++ b/src/poem/recite.rs @@ -1,5 +1,6 @@ use super::Poem; use crate::compose::Environment; +use crate::path; use crate::poem::anthology; use crate::poem::elements::rune::Rune; use crate::poem::elements::stanza::Stanza; @@ -141,36 +142,28 @@ impl Reciteable for Poem { None => {} }; + // Check if the verse's verb exists + let mut spell = None; + if !verse.verb().is_empty() { + // Check if the verb exists on the PATH + // If it doesn't exist, try refreshing the binary cache, and check again + // If it still doesn't exist, print an error + spell = verse.spellcheck(&env.bins); + if !spell.is_some() { + env.bins = path::refresh(); + spell = verse.spellcheck(&env.bins); + if !spell.is_some() { + eprintln!("dwvsh: {}: command not found", verse.verb()); + + if verse.meter != Rune::And { + continue; + } + } + } + } + // Incant the verse if it's a built-in - let status = - verse.incant(&mut out, &mut pids, env, anthology::lookup(&verse.verb()))?; - // let status = if index.is_some() { - // anthology::incant(&verse, &mut out, index.unwrap(), env) - // } else { - // // Checking for environment variables and running internal - // // poems may mean that the verb is empty now, so check it once - // // more - // // If it is empty, just continue to the next verse - // if !verse.verb().is_empty() { - // // Check if the verb exists on the PATH - // // If it doesn't exist, try refreshing the binary cache, and check - // // again - // // If it still doesn't exist, print an error - // if !verse.spellcheck(&env.bins).is_some() { - // env.bins = path::refresh(); - // if !verse.spellcheck(&env.bins).is_some() { - // eprintln!("dwvsh: {}: command not found", verse.verb()); - // - // if verse.meter != Rune::And { - // continue; - // } - // } - // } - // } else { - // continue; - // } - // verse.incant(&mut out, &mut pids, anthology::lookup(&verse.verb()))? - // }; + let status = verse.incant(&mut out, &mut pids, env, spell)?; // Break from the loop if the meter is not [Rune::Continue], and // if the status is not 0 -- cgit v1.2.3