From 9b3e4dd71ec1491e3580e079e9be1b42117a74c9 Mon Sep 17 00:00:00 2001
From: Rory Dudley
Date: Thu, 4 Apr 2024 00:47:24 -0600
Subject: Add better support for aliases

Make sure to interpret alias values as their own poems, since aliases
can be fairly complex.
---
 src/poem/anthology.rs        |  6 +++---
 src/poem/anthology/alias.rs  | 24 ++++++++++++++++--------
 src/poem/anthology/source.rs | 10 ++++++----
 src/poem/recite.rs           | 39 +++++++++++++++++++++++++--------------
 4 files changed, 50 insertions(+), 29 deletions(-)

diff --git a/src/poem/anthology.rs b/src/poem/anthology.rs
index e48e6c6..79f48f2 100644
--- a/src/poem/anthology.rs
+++ b/src/poem/anthology.rs
@@ -43,14 +43,14 @@ pub fn lookup(verb: &str) -> Option<usize> {
 ///     ...
 /// }
 /// ```
-pub fn incant(verse: &Verse, index: usize, env: &mut Environment) -> i32 {
+pub fn incant(verse: &Verse, out: &mut String, index: usize, env: &mut Environment) -> i32 {
     let verb = INDEX[index];
     match verb {
-        "alias" => alias::incant(verse, &mut env.aliases),
+        "alias" => alias::incant(verse, out, &mut env.aliases),
         "cd" => cd::incant(verse),
         "exit" => exit::incant(),
         "export" => export::incant(verse),
-        "source" => source::incant(verse, env),
+        "source" => source::incant(verse, out, env),
         "unalias" => alias::unincant(verse, &mut env.aliases),
         "unset" => export::unincant(verse),
         _ => unreachable!(),
diff --git a/src/poem/anthology/alias.rs b/src/poem/anthology/alias.rs
index 96682db..0183ec2 100644
--- a/src/poem/anthology/alias.rs
+++ b/src/poem/anthology/alias.rs
@@ -10,7 +10,7 @@ use std::collections::HashMap;
 /// ```sh
 /// alias vim=nvim
 /// ```
-pub fn incant(verse: &Verse, aliases: &mut HashMap<String, String>) -> i32 {
+pub fn incant(verse: &Verse, out: &mut String, aliases: &mut HashMap<String, String>) -> i32 {
     match verse.clause() {
         Some(clause) => {
             for stanza in clause {
@@ -22,18 +22,26 @@ pub fn incant(verse: &Verse, aliases: &mut HashMap<String, String>) -> i32 {
             }
         }
         None => {
+            let mut lines = Vec::new();
             for (key, val) in aliases {
-                if key.contains(' ') && val.contains(' ') {
-                    println!("'{}'='{}'", key, val);
+                let line = if key.contains(' ') && val.contains(' ') {
+                    format!("'{}'='{}'", key, val)
                 } else if key.contains(' ') {
-                    println!("'{}'={}", key, val);
+                    format!("'{}'={}", key, val)
                 } else if val.contains(' ') {
-                    println!("{}='{}'", key, val);
+                    format!("{}='{}'", key, val)
                 } else if val.is_empty() {
-                    println!("{}=''", key);
+                    format!("{}=''", key)
                 } else {
-                    println!("{}={}", key, val);
-                }
+                    format!("{}={}", key, val)
+                };
+                lines.push(line);
+            }
+
+            if verse.couplet {
+                *out = lines.join("\n");
+            } else {
+                println!("{}", lines.join("\n"));
             }
         }
     }
diff --git a/src/poem/anthology/source.rs b/src/poem/anthology/source.rs
index ed4ed13..77d1330 100644
--- a/src/poem/anthology/source.rs
+++ b/src/poem/anthology/source.rs
@@ -12,7 +12,7 @@ use std::fs;
 /// ```sh
 /// source ~/.dwvshrc
 /// ```
-pub fn incant(verse: &Verse, env: &mut Environment) -> i32 {
+pub fn incant(verse: &Verse, out: &mut String, env: &mut Environment) -> i32 {
     let files = match verse.clause() {
         Some(clause) => clause,
         None => {
@@ -42,13 +42,15 @@ pub fn incant(verse: &Verse, env: &mut Environment) -> i32 {
             }
         };
 
-        match poem.recite(env, None) {
-            Ok(_) => {}
+        let stdout = if verse.couplet { Some(true) } else { None };
+
+        *out = match poem.recite(env, stdout) {
+            Ok(out) => out,
             Err(e) => {
                 eprintln!("dwvsh: {}", e.to_string().to_lowercase());
                 continue;
             }
-        }
+        };
     }
 
     0
diff --git a/src/poem/recite.rs b/src/poem/recite.rs
index 45d4d2e..1f24d14 100644
--- a/src/poem/recite.rs
+++ b/src/poem/recite.rs
@@ -4,6 +4,7 @@ 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,
@@ -25,8 +26,30 @@ impl Reciteable for Poem {
         // Keep track of pids for background processes
         let mut pids: Arc<Mutex<Vec<i32>>> = Arc::new(Mutex::new(Vec::new()));
 
-        // Loop through each verse in the poem
+        // 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() {
             // Verse may need to be mutable
             let mut verse = verse.clone();
 
@@ -59,18 +82,6 @@ impl Reciteable for Poem {
                 *word = word.replace('\x0e', "$");
             }
 
-            // Check for aliases
-            match env.aliases.get(&verse.verb()) {
-                Some(verb) => {
-                    let mut split: Vec<String> = verb.split(" ").map(|s| s.to_string()).collect();
-                    let mut old_stanza = verse.stanza.clone();
-                    old_stanza.remove(0);
-                    split.append(&mut old_stanza);
-                    verse.stanza = split;
-                }
-                None => {}
-            };
-
             // Check if verse is a builtin
             let index = anthology::lookup(&verse.verb());
 
@@ -142,7 +153,7 @@ impl Reciteable for Poem {
 
             // Incant the verse if it's a built-in
             let status = if index.is_some() {
-                anthology::incant(&verse, index.unwrap(), env)
+                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
-- 
cgit v1.2.3