summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compose.rs2
-rw-r--r--src/main.rs2
-rw-r--r--src/poem.rs74
-rw-r--r--src/poem/anthology/alias.rs2
-rw-r--r--src/poem/anthology/source.rs2
-rw-r--r--src/poem/read.rs34
-rw-r--r--src/poem/read/parse.rs32
-rw-r--r--src/poem/recite.rs25
8 files changed, 98 insertions, 75 deletions
diff --git a/src/compose.rs b/src/compose.rs
index c90f470..f59b719 100644
--- a/src/compose.rs
+++ b/src/compose.rs
@@ -53,7 +53,7 @@ fn rrr(path: PathBuf, env: &mut Environment) {
}
};
- let poem = match Poem::read(poetry) {
+ let poem = match Poem::read(poetry, &Environment::new()) {
Ok(poem) => poem,
Err(e) => {
eprintln!(
diff --git a/src/main.rs b/src/main.rs
index e0d0ed1..3e0a2e8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -65,7 +65,7 @@ fn repl(away: &mut Arc<Mutex<bool>>, env: &mut Environment) {
*away.lock().unwrap() = true;
// Parse the poem
- let poem = Poem::read(poetry);
+ let poem = Poem::read(poetry, env);
let poem = match poem {
Ok(poem) => poem,
Err(e) => {
diff --git a/src/poem.rs b/src/poem.rs
index 0eda6b7..a063a14 100644
--- a/src/poem.rs
+++ b/src/poem.rs
@@ -15,10 +15,11 @@ mod tests {
use super::elements::rune::Rune;
use super::read::Readable;
use super::*;
+ use crate::compose::Environment;
#[test]
fn it_parses_a_verse_with_no_meter() {
- let poem = Poem::read("cargo build --release".to_string());
+ let poem = Poem::read("cargo build --release".to_string(), &Environment::new());
assert!(poem.is_ok());
let poem = poem.unwrap();
assert_eq!(poem.first().unwrap().verb(), "cargo");
@@ -26,7 +27,7 @@ mod tests {
#[test]
fn it_parses_a_verse_with_the_couplet_meter() {
- let poem = Poem::read("ls -la | lolcat".to_string());
+ let poem = Poem::read("ls -la | lolcat".to_string(), &Environment::new());
assert!(poem.is_ok());
let poem = poem.unwrap();
assert_eq!(poem.first().unwrap().verb(), "ls");
@@ -35,7 +36,7 @@ mod tests {
#[test]
fn it_parses_a_verse_with_the_quiet_meter() {
- let poem = Poem::read("sleep 20 &".to_string());
+ let poem = Poem::read("sleep 20 &".to_string(), &Environment::new());
assert!(poem.is_ok());
let poem = poem.unwrap();
assert_eq!(poem.first().unwrap().verb(), "sleep");
@@ -44,7 +45,7 @@ mod tests {
#[test]
fn it_parses_a_verse_with_the_and_meter() {
- let poem = Poem::read("sleep 2 && ls -la".to_string());
+ let poem = Poem::read("sleep 2 && ls -la".to_string(), &Environment::new());
assert!(poem.is_ok());
let poem = poem.unwrap();
assert_eq!(poem.first().unwrap().verb(), "sleep");
@@ -53,7 +54,7 @@ mod tests {
#[test]
fn it_parses_a_verse_with_the_continue_meter() {
- let poem = Poem::read("sleep 2; ls -la".to_string());
+ let poem = Poem::read("sleep 2; ls -la".to_string(), &Environment::new());
assert!(poem.is_ok());
let poem = poem.unwrap();
assert_eq!(poem.first().unwrap().verb(), "sleep");
@@ -62,7 +63,7 @@ mod tests {
#[test]
fn it_parses_a_verse_with_the_read_rune() {
- let poem = Poem::read("lolcat < src/main.rs".to_string());
+ let poem = Poem::read("lolcat < src/main.rs".to_string(), &Environment::new());
assert!(poem.is_ok());
let mut verses = poem.unwrap().into_iter();
let verse = verses.next().unwrap();
@@ -78,7 +79,10 @@ mod tests {
#[test]
fn it_parses_a_verse_with_the_write_rune() {
- let poem = Poem::read("cat src/main.rs > /dev/null".to_string());
+ let poem = Poem::read(
+ "cat src/main.rs > /dev/null".to_string(),
+ &Environment::new(),
+ );
assert!(poem.is_ok());
let mut verses = poem.unwrap().into_iter();
let verse = verses.next().unwrap();
@@ -94,7 +98,10 @@ mod tests {
#[test]
fn it_parses_a_verse_with_the_addendum_rune() {
- let poem = Poem::read("cat src/main.rs >> /dev/null".to_string());
+ let poem = Poem::read(
+ "cat src/main.rs >> /dev/null".to_string(),
+ &Environment::new(),
+ );
assert!(poem.is_ok());
let mut verses = poem.unwrap().into_iter();
let verse = verses.next().unwrap();
@@ -110,37 +117,40 @@ mod tests {
#[test]
fn it_throws_a_parse_error_if_no_files_are_specified_for_the_read_rune() {
- let poem = Poem::read("lolcat <".to_string());
+ let poem = Poem::read("lolcat <".to_string(), &Environment::new());
assert!(poem.is_err());
- let poem = Poem::read("lolcat <;".to_string());
+ let poem = Poem::read("lolcat <;".to_string(), &Environment::new());
assert!(poem.is_err());
- let poem = Poem::read("lolcat < && ls -la".to_string());
+ let poem = Poem::read("lolcat < && ls -la".to_string(), &Environment::new());
assert!(poem.is_err());
}
#[test]
fn it_throws_a_parse_error_if_no_files_are_specified_for_the_write_rune() {
- let poem = Poem::read("cat src/main.rs >".to_string());
+ let poem = Poem::read("cat src/main.rs >".to_string(), &Environment::new());
assert!(poem.is_err());
- let poem = Poem::read("cat src/main.rs >;".to_string());
+ let poem = Poem::read("cat src/main.rs >;".to_string(), &Environment::new());
assert!(poem.is_err());
- let poem = Poem::read("cat > && ls -la".to_string());
+ let poem = Poem::read("cat > && ls -la".to_string(), &Environment::new());
assert!(poem.is_err());
}
#[test]
fn it_throws_a_parse_error_if_no_files_are_specified_for_the_addendum_rune() {
- let poem = Poem::read("cat src/main.rs >>".to_string());
+ let poem = Poem::read("cat src/main.rs >>".to_string(), &Environment::new());
assert!(poem.is_err());
- let poem = Poem::read("cat src/main.rs >>;".to_string());
+ let poem = Poem::read("cat src/main.rs >>;".to_string(), &Environment::new());
assert!(poem.is_err());
- let poem = Poem::read("cat >> && ls -la".to_string());
+ let poem = Poem::read("cat >> && ls -la".to_string(), &Environment::new());
assert!(poem.is_err());
}
#[test]
fn it_parses_a_complex_verse_with_lots_of_different_meters() {
- let poem = Poem::read("ls -la | lolcat && echo hello | lolcat && sleep 2 &".to_string());
+ let poem = Poem::read(
+ "ls -la | lolcat && echo hello | lolcat && sleep 2 &".to_string(),
+ &Environment::new(),
+ );
assert!(poem.is_ok());
let mut verses = poem.unwrap().into_iter();
@@ -170,25 +180,25 @@ mod tests {
#[test]
fn it_parses_the_continue_meter_without_a_stanza() {
- let poem = Poem::read(";;;;;;;".to_string());
+ let poem = Poem::read(";;;;;;;".to_string(), &Environment::new());
assert!(poem.is_ok());
}
#[test]
fn it_errors_if_the_couplet_meter_is_used_without_a_stanza() {
- let poem = Poem::read("|".to_string());
+ let poem = Poem::read("|".to_string(), &Environment::new());
assert!(poem.is_err());
}
#[test]
fn it_errors_if_the_quiet_meter_is_used_without_a_stanza() {
- let poem = Poem::read("&".to_string());
+ let poem = Poem::read("&".to_string(), &Environment::new());
assert!(poem.is_err());
}
#[test]
fn it_errors_if_the_and_meter_is_used_without_a_stanza() {
- let poem = Poem::read("&&".to_string());
+ let poem = Poem::read("&&".to_string(), &Environment::new());
assert!(poem.is_err());
}
@@ -199,7 +209,7 @@ mod tests {
sleep 2
";
- let poem = Poem::read(file.to_string());
+ let poem = Poem::read(file.to_string(), &Environment::new());
assert!(poem.is_ok());
let poem = poem.unwrap();
@@ -239,7 +249,7 @@ mod tests {
wc -l src/**/*.rs | lolcat; ls -la | grep git
";
- let poem = Poem::read(file.to_string());
+ let poem = Poem::read(file.to_string(), &Environment::new());
assert!(poem.is_ok());
let poem = poem.unwrap();
@@ -249,36 +259,36 @@ mod tests {
#[test]
fn it_catches_parser_errors_related_to_invalid_use_of_special_runes() {
let poetry = "cat file.txt &&&".to_string();
- assert_eq!(Poem::read(poetry).is_err(), true);
+ assert_eq!(Poem::read(poetry, &Environment::new()).is_err(), true);
let poetry = "cat file.txt&&|".to_string();
- assert_eq!(Poem::read(poetry).is_err(), true);
+ assert_eq!(Poem::read(poetry, &Environment::new()).is_err(), true);
let poetry = "cat <".to_string();
- assert_eq!(Poem::read(poetry).is_err(), true);
+ assert_eq!(Poem::read(poetry, &Environment::new()).is_err(), true);
}
#[test]
fn it_catches_parser_errors_related_to_strings() {
let poetry = "echo 'hello".to_string();
- assert_eq!(Poem::read(poetry).is_err(), true);
+ assert_eq!(Poem::read(poetry, &Environment::new()).is_err(), true);
let poetry = "echo \"hello".to_string();
- assert_eq!(Poem::read(poetry).is_err(), true);
+ assert_eq!(Poem::read(poetry, &Environment::new()).is_err(), true);
let poetry = "`true".to_string();
- assert_eq!(Poem::read(poetry).is_err(), true);
+ assert_eq!(Poem::read(poetry, &Environment::new()).is_err(), true);
}
#[test]
fn it_interprets_tilda_as_home() {
let poetry = "cd ~".to_string();
- let poem = Poem::read(poetry).unwrap();
+ let poem = Poem::read(poetry, &Environment::new()).unwrap();
assert_eq!(poem[0].verb(), "cd");
assert_eq!(poem[0].clause(), Some(vec![env!("HOME").to_string()]));
let poetry = "cd ~/Code/dwarvish".to_string();
- let poem = Poem::read(poetry).unwrap();
+ let poem = Poem::read(poetry, &Environment::new()).unwrap();
assert_eq!(poem[0].verb(), "cd");
assert_eq!(
poem[0].clause(),
diff --git a/src/poem/anthology/alias.rs b/src/poem/anthology/alias.rs
index 0183ec2..4c9b7b6 100644
--- a/src/poem/anthology/alias.rs
+++ b/src/poem/anthology/alias.rs
@@ -39,7 +39,7 @@ pub fn incant(verse: &Verse, out: &mut String, aliases: &mut HashMap<String, Str
}
if verse.couplet {
- *out = lines.join("\n");
+ *out = format!("{}\n", lines.join("\n"));
} else {
println!("{}", lines.join("\n"));
}
diff --git a/src/poem/anthology/source.rs b/src/poem/anthology/source.rs
index 77d1330..182fef4 100644
--- a/src/poem/anthology/source.rs
+++ b/src/poem/anthology/source.rs
@@ -34,7 +34,7 @@ pub fn incant(verse: &Verse, out: &mut String, env: &mut Environment) -> i32 {
}
};
- let poem = match Poem::read(poetry) {
+ let poem = match Poem::read(poetry, env) {
Ok(poem) => poem,
Err(e) => {
eprintln!("dwvsh: {}", e.to_string().to_lowercase());
diff --git a/src/poem/read.rs b/src/poem/read.rs
index d88cf0d..0af7fec 100644
--- a/src/poem/read.rs
+++ b/src/poem/read.rs
@@ -4,7 +4,8 @@ use super::{
};
use core::fmt;
mod parse;
-use crate::{next, poem, remark, string};
+use crate::compose::Environment;
+use crate::{append, next, poem, remark, string};
#[derive(Debug, PartialEq, Eq)]
pub enum Mishap {
@@ -51,20 +52,25 @@ impl Appendable for Poem {
/// Push a [Verse] to the [Poem] after checking that the [Verse] is not
/// empty. Also sets the meter of the [Verse].
fn add(&mut self, verse: &mut Self::Type, last: Rune, meter: Rune) {
- if !verse.is_empty() {
- verse.meter = meter;
- if last == Rune::Couplet || meter == Rune::Couplet {
- verse.couplet = true;
- }
- self.push(verse.clone());
- verse.clear();
+ if verse.is_empty() {
+ return;
+ }
+
+ // Check the meter
+ verse.meter = meter;
+ if last == Rune::Couplet || meter == Rune::Couplet {
+ verse.couplet = true;
}
+
+ // Push verse(s) and clear the current verse stack
+ self.push(verse.clone());
+ verse.clear();
}
}
/// A [Poem] can parse poetry
pub trait Readable {
- fn read(poetry: String) -> Result<Poem, Mishap>;
+ fn read(poetry: String, env: &Environment) -> Result<Poem, Mishap>;
}
impl Readable for Poem {
@@ -74,7 +80,7 @@ impl Readable for Poem {
/// machine-runnable [Poem]. If there is a parse error, [Poem::read] may
/// return a [Mishap]. See [Poem::recite][super::recite] for how each
/// [Verse] in a [Poem] is called.
- fn read(poetry: String) -> Result<Poem, Mishap> {
+ fn read(poetry: String, env: &Environment) -> Result<Poem, Mishap> {
// Get all the characters in the input string as an iterator
let mut chars = poetry.chars().into_iter();
@@ -118,7 +124,8 @@ impl Readable for Poem {
}
// Push the verse and break
- poem.add(&mut verse, last, Rune::None);
+ // poem.add(&mut verse, last, Rune::None);
+ append!(poem, last, Rune::None, verse, env);
break;
}
};
@@ -207,7 +214,7 @@ impl Readable for Poem {
// Indicates a sub-poem
Rune::Poem => {
- poem!(chars, j, i, c, verse, word);
+ poem!(chars, j, i, c, verse, word, env);
}
// Indicates a file operation (<, >, or >>)
@@ -221,7 +228,8 @@ impl Readable for Poem {
// These meters indicate the end of a verse
Rune::Couplet | Rune::Quiet | Rune::And | Rune::Continue => {
verse.add(&mut word);
- poem.add(&mut verse, last, rune);
+ // poem.add(&mut verse, last, rune);
+ append!(poem, last, rune, verse, env);
}
// Interpret ~ as $HOME
diff --git a/src/poem/read/parse.rs b/src/poem/read/parse.rs
index 0836eea..70367c4 100644
--- a/src/poem/read/parse.rs
+++ b/src/poem/read/parse.rs
@@ -63,7 +63,7 @@ macro_rules! remark {
/// Same as the [string!] macro, but don't `continue`
#[macro_export]
macro_rules! poem {
- ($chars:expr, $j:expr, $i:expr, $c:expr, $verse:expr, $word:expr) => {
+ ($chars:expr, $j:expr, $i:expr, $c:expr, $verse:expr, $word:expr, $env:expr) => {
let token = $c;
let mut poetry = Word::new();
loop {
@@ -76,7 +76,7 @@ macro_rules! poem {
}
}
}
- let sp = Poem::read(poetry.iter().collect());
+ let sp = Poem::read(poetry.iter().collect(), $env);
let sp = match sp {
Ok(sp) => sp,
Err(e) => return Err(e),
@@ -85,3 +85,31 @@ macro_rules! poem {
$word.push('\x0b');
};
}
+
+/// Append a verse to the poem
+///
+/// Append a verse to poem, first checking for aliases in the environment, and
+/// processing the alias first, if necessary.
+#[macro_export]
+macro_rules! append {
+ ($poem:expr, $last:expr, $meter:expr, $verse:expr, $env:expr) => {
+ if !$verse.is_empty() {
+ match $env.aliases.get(&$verse.verb()) {
+ Some(alias) => {
+ let alias = alias.to_string();
+ let mut poem = Poem::read(alias, $env)?;
+ let len = poem.len();
+ for (i, verse) in poem.iter_mut().enumerate() {
+ if $verse.clause().is_some() && i + 1 == len {
+ verse.stanza.append(&mut $verse.clause().unwrap());
+ }
+ $poem.push(verse.clone());
+ }
+ }
+ None => {
+ $poem.add(&mut $verse, $last, $meter);
+ }
+ }
+ }
+ };
+}
diff --git a/src/poem/recite.rs b/src/poem/recite.rs
index 1f24d14..4038e37 100644
--- a/src/poem/recite.rs
+++ b/src/poem/recite.rs
@@ -4,7 +4,6 @@ use crate::compose::Environment;
use crate::path;
use crate::poem::anthology;
use crate::poem::elements::rune::Rune;
-use crate::poem::read::Readable;
use std::env;
use std::{
io,
@@ -26,30 +25,8 @@ impl Reciteable for Poem {
// Keep track of pids for background processes
let mut pids: Arc<Mutex<Vec<i32>>> = Arc::new(Mutex::new(Vec::new()));
- // Check for aliases
- let mut vv = Poem::new();
- for verse in self.iter() {
- let alias = match env.aliases.get(&verse.verb()) {
- Some(alias) => alias,
- None => {
- vv.push(verse.clone());
- continue;
- }
- }
- .to_string();
-
- let mut poem = Poem::read(alias).unwrap();
- let len = poem.len();
- for (i, new_verse) in poem.iter_mut().enumerate() {
- if verse.clause().is_some() && i + 1 == len {
- new_verse.stanza.append(&mut verse.clause().unwrap());
- }
- vv.push(new_verse.clone());
- }
- }
-
// Loop through each verse in the poem
- for verse in vv.iter() {
+ for verse in self.iter() {
// Verse may need to be mutable
let mut verse = verse.clone();