summaryrefslogtreecommitdiffstats
path: root/src/poem/elements
diff options
context:
space:
mode:
Diffstat (limited to 'src/poem/elements')
-rw-r--r--src/poem/elements/rune.rs116
-rw-r--r--src/poem/elements/stanza.rs12
-rw-r--r--src/poem/elements/verse.rs174
-rw-r--r--src/poem/elements/verse/logic.rs14
-rw-r--r--src/poem/elements/word.rs3
5 files changed, 195 insertions, 124 deletions
diff --git a/src/poem/elements/rune.rs b/src/poem/elements/rune.rs
index 688043d..64e3326 100644
--- a/src/poem/elements/rune.rs
+++ b/src/poem/elements/rune.rs
@@ -2,57 +2,75 @@ use core::fmt;
/// Describes one or two characters from the input
///
-/// [Rune]s are a way to mark special characters from the input string (i.e.
-/// poetry). Some [Rune]s are special--as they denote the end of a [Verse]--
-/// and are refered to as a Meter. For instance, `Addendum`, `Couplet`,
-/// `Quiet`, and `And`, are all meters. Meters also determine how the
-/// [Stanza][super::stanza::Stanza] should be interpreted. For instance, a
-/// [Stanza][super::stanza::Stanza] that is piped needs to have
-/// its `STDOUT` captured (rather than printing out to the terminal), and
-/// subsequently sent to the next [Verse] in the [Poem][super::super::Poem].
-///
-/// # Values
-/// * `None` - A shell command with no additional actions (the end of a poem)
-/// * `Pause` - The space character, to dilineate words (` `)
-/// * `Path` - The forward slash character, to dilineate paths (`/`)
-/// * `Remark` - Indicates a single line comment (`#`)
-/// * `String` - Interpret all character as one large
-/// [Word][super::word::Word] (`'` or `"`)
-/// * `Poem` - A subcommand to run first (`\``)
-/// * `Read` - Read files into STDIN (`<`)
-/// * `Write` - Write STDOUT to a file (`>`)
-/// * `Write2` - Write STDERR to a file (`2>`)
-/// * `WriteAll` - Write both STDOUT and STDERR to a file (`&>`)
-/// * `Addendum` - Append STDOUT to a file (`>>`)
-/// * `Addendum2` - Append STDERR to a file (`2>>`)
-/// * `AddendumAll` - Append both STDOUT and STDERR to a file (`&>>`)
-/// * `Couplet` - Pipe the output of this command into the next (`|`)
-/// * `Quiet` - Fork the called process into the background (`&`)
-/// * `And` - Run the next command only if this one succeeds (`&&`)
-/// * `Continue` - String commands together on a single line (`;`)
-/// * `Home` - Interpret `~` as `$HOME`
-/// * `Else` - Any other character
+/// [Rune]s are a way to mark special characters from the input string
+/// (i.e. poetry). Some [Rune]s are special--as they denote the end of a
+/// [Verse][crate::poem::Verse]--and are refered to as a Meter. For
+/// instance, `Addendum`, `Couplet`, `Quiet`, and `And`, are all meters.
+/// Meters also determine how the [Stanza][super::stanza::Stanza] should
+/// be interpreted. For instance, a [Stanza][super::stanza::Stanza] that
+/// is piped needs to have its `STDOUT` captured (rather than printing
+/// out to the terminal), and subsequently sent to the next
+/// [Verse][crate::poem::Verse] in the [Poem][super::super::Poem].
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Rune {
- None, // No meter (the end of a poem)
- Pause, // A space
- Path, // A forward slash
- Remark, // A comment
- String, // Interpret the following as one large [Word]
- Poem, // Run a sub-poem before the main one
- Read, // Read files into STDIN
- Write, // Send STDOUT to a file
- Write2, // Send STDERR to a file
- WriteAll, // Send STDOUT and STDERR to a file
- Addendum, // Append STDOUT to a file
- Addendum2, // Append STDERR to a file
- AddendumAll, // Append STDOUT and STDERR to a file
- Couplet, // Pipe the output of this command into the next
- Quiet, // Fork the command into the background
- And, // Run the next command only if this succeeds
- Continue, // Run the next command, even if this doesn't succeed
- Home, // Interpret '~' as $HOME
- Else, // Any other character
+ /// A shell command with no additional actions (the end of a poem)
+ None,
+
+ /// The space character, to dilineate words (`' '`)
+ Pause,
+
+ /// The forward slash character, to dilineate paths (`/`)
+ Path,
+
+ /// Indicates a single line comment (`#`)
+ Remark,
+
+ /// Interpret all characters as one large [Word][super::word::Word]
+ /// (`'` or `"`)
+ String,
+
+ /// A subcommand to run first (`\``)
+ Poem,
+
+ /// Read files into STDIN (`<`)
+ Read,
+
+ /// Write STDOUT to a file (`>`)
+ Write,
+
+ /// Write STDERR to a file (`2>`)
+ Write2,
+
+ /// Write both STDOUT and STDERR to a file (`&>`)
+ WriteAll,
+
+ /// Append STDOUT to a file (`>>`)
+ Addendum,
+
+ /// Append STDERR to a file (`2>>`)
+ Addendum2,
+
+ /// Append both STDOUT and STDERR to a file (`&>>`)
+ AddendumAll,
+
+ /// Pipe the output of this command into the next (`|`)
+ Couplet,
+
+ /// Fork the called process into the background (`&`)
+ Quiet,
+
+ /// Run the next command, only if this one succeeds (`&&`)
+ And,
+
+ /// Run the next command, regardless of whether or not this command
+ /// succeeds (`;` or a newline in a file)
+ Continue,
+
+ /// Interpret `~` as `$HOME`
+ Home,
+
+ /// Any other character
+ Else,
}
impl fmt::Display for Rune {
diff --git a/src/poem/elements/stanza.rs b/src/poem/elements/stanza.rs
index d58d080..b5acf32 100644
--- a/src/poem/elements/stanza.rs
+++ b/src/poem/elements/stanza.rs
@@ -1,10 +1,10 @@
/// The actionable part of a [Verse][super::verse::Verse]
///
-/// Each [Stanza] has two parts, a `verb()` and a `clause()`. The `verb()` is
-/// the program, or path to the program to call, while the `clause()` contains
-/// arguments to pass to that program.
+/// Each [Stanza] has two parts, a `verb()` and a `clause()`. The
+/// `verb()` is the program, or path to the program to call, while the
+/// `clause()` contains arguments to pass to that program.
///
-/// The [Stanza] is just stored as a [Vec] of [String]s, where the verb is the
-/// first entry in the vector (i.e. `stanza[0]`) and the clause the the
-/// remainder of the vector (i.e. `stanza[1..]`).
+/// The [Stanza] is just stored as a [Vec] of [String]s, where the verb
+/// is the first entry in the vector (i.e. `stanza[0]`) and the clause
+/// the the remainder of the vector (i.e. `stanza[1..]`).
pub type Stanza = Vec<String>;
diff --git a/src/poem/elements/verse.rs b/src/poem/elements/verse.rs
index b4f41ba..1c5bcc1 100644
--- a/src/poem/elements/verse.rs
+++ b/src/poem/elements/verse.rs
@@ -16,27 +16,83 @@ use std::path::Path;
use std::process::{Child, Command, Output, Stdio};
use std::sync::{Arc, Mutex};
-/// A [Stanza] and it's [meter](Rune)
+/// A [Stanza] and its [meter](Rune)
///
-/// In addition to a [Stanza] and a [meter](Rune), this also holds a [bool]
-/// value called `couplet`, indicating that it needs to accept input on `STDIN`
-/// from the previous [Verse].
+/// In addition to a [Stanza] and a [meter](Rune), this also holds a
+/// [bool] value called `couplet`, indicating that it needs to accept
+/// input on `STDIN` from the previous [Verse].
#[derive(Debug, Clone)]
pub struct Verse {
+ /// A command and its arguments (also see [Stanza])
pub stanza: Stanza,
+
+ /// Denote the couplet status (for piping text in/out)
+ ///
+ /// * `0`: Not a couplet
+ /// * `1`: Left side of a couplet
+ /// * `2`: Right side of a couplet
+ /// * `3`: Both sides of a couplet
+ ///
+ /// ```
+ /// ls | grep Ca | lolcat
+ /// ^ ^ ^
+ /// | | 2: right side of a couplet
+ /// | 3: both sides of a couplet
+ /// 1: left side of a couplet
+ /// ```
pub couplet: u8,
+
+ /// A list of IO operations to be performed
+ ///
+ /// For instance, read into STDIN, write STDOUT to a file, etc. May
+ /// be empty. Also see [Rune] for more details.
pub io: Vec<Rune>,
+
+ /// Input paths
+ ///
+ /// A list of files to read into STDIN, may be empty.
pub ip: Stanza,
+
+ /// Output paths
+ ///
+ /// A list of files to send STDOUT to, may be empty.
pub op: Stanza,
+
+ /// Error paths
+ ///
+ /// A list of files to send STDERR to, may be empty.
pub ep: Stanza,
+
+ /// Internal poems (i.e. 'ls \`ls\`')
+ ///
+ /// A list of poems to evaluate before evaluating this one.
pub poems: Vec<Poem>,
+
+ /// Interpret how to handle a poem after forking to its command
+ ///
+ /// * `None`: Indicates the end of a poem
+ /// * `Couplet`: Pipe the output of this command into the next (`|`)
+ /// * `Quiet`: Fork the called process into the background (`&`)
+ /// * `And`: Run the next command, only if this one succeeds (`&&`)
+ /// * `Continue`: Run the next command, regardless of whether or not
+ /// this command succeeds (`;` or a newline in a file)
+ ///
+ /// Also see [Rune] for more details.
pub meter: Rune,
}
+/// Granularity for [spellcheck()][Verse::spellcheck]
+///
+/// Indicates if a given [verb][Verse::verb] exists, and where.
#[derive(Debug, Clone)]
pub enum Spelling {
+ /// The [verb][Verse::verb] is a full path, and that path exists
FullPath,
+
+ /// The [verb][Verse::verb] is on the `$PATH`
OnPath(usize),
+
+ /// The [verb][Verse::verb] is a built-in shell command
BuiltIn(usize),
}
@@ -59,42 +115,8 @@ impl Forkable<Anthology> for Anthology {
impl Verse {
/// Create a new [Verse]
///
- /// Returns a new [Verse], with an empty [Stanza], a meter of [Rune::None],
- /// and `couplet` set to 0.
- ///
- /// # Fields
- /// stanza - The command (a `verb()` and a `clause()`)
- /// couplet - Indicates couplet status
- /// 0: Not a couplet (`cat Cargo.toml`)
- /// 1: Left side of a couplet (`cat Cargo.toml | ...`)
- /// 2: Right side of a couplet (`... | lolcat`)
- /// 3: Sandwiched between couplets (`... | grep Ca | ...`)
- /// io - A list of IO operations ([Rune::Read], [Rune::Write], etc.)
- /// ip - A list of filenames for reading into STDIN when:
- /// [Rune::Read]
- /// is specified
- /// op - A list of filenames for redirecting STDOUT to when:
- /// [Rune::Write],
- /// [Rune::WriteAll],
- /// [Rune::Addendum],
- /// and/or [Rune::AddendumAll]
- /// is specified
- /// ep - A list of filenames for redirecting STDERR to when:
- /// [Rune::Write2],
- /// [Rune::WriteAll],
- /// [Rune::Addendum2],
- /// and/or [Rune::AddendumAll]
- /// is specified
- /// poems - Internal commands to run before the [Verse] is recited
- /// ([Rune::Poem]).
- /// meter - Determines how the verse is recited in relation to the other
- /// verses in the [Poem].
- /// [Rune::None] -> Run the command and print the output
- /// [Rune::Couplet] -> Pipe the output of this verse into the next
- /// [Rune::Quiet] -> Run in the background
- /// [Rune::And] -> Run the next verse only if this verse succeeds
- /// [Rune::Continue] -> Run the next verse, regardless of whether
- /// or not this verse succeeds
+ /// Returns a new [Verse], with an empty [Stanza], a meter of
+ /// [Rune::None], and `couplet` set to 0.
pub fn new() -> Self {
Verse {
stanza: Stanza::new(),
@@ -153,11 +175,11 @@ impl Verse {
/// Push a word to the [Verse]'s [Stanza]
///
- /// Push a word to the [Verse]'s [Stanza], or one of its IO channels. If
- /// `word` is empty, this function will simply return without performing
- /// any operations. A channel of [None] will push to the [Verse]'s
- /// [Stanza], while IO [Rune]s will determine which IO channel a word will
- /// get pushed onto.
+ /// Push a word to the [Verse]'s [Stanza], or one of its IO
+ /// channels. If `word` is empty, this function will simply return
+ /// without performing any operations. A channel of [None] will push
+ /// to the [Verse]'s [Stanza], while IO [Rune]s will determine which
+ /// IO channel a word will get pushed onto.
///
/// # Arguments
/// word - The word to push onto the [Stanza]/channel
@@ -194,35 +216,50 @@ impl Verse {
word.clear();
}
- /// Check if the `verb()` exists in the `$PATH`
+ /// Check if the [verb][Verse::verb] exists
///
- /// First checks if the `verb()` is a relative or full path. If it is,
- /// check whether or not it exists. If it does exist, return true,
- /// otherwise seeif the `verb()` is cached in our list of binaries. Search is
- /// done in $PATH order.
+ /// First checks if the [verb][Verse::verb] is a built-in shell
+ /// command. Then checks if the [verb][Verse::verb] is on the
+ /// `$PATH`. If not, then the [verb][Verse::verb] is a either a full
+ /// path, or it does not exist on the system.
///
/// # Examples
/// ```
- /// let bins = vec!["cargo", "ruby", "cat"]
- /// .into_iter()
- /// .map(String::from)
- /// .collect<Vec<String>>();
+ /// let command_full_path = vec!["/bin/ls"]
+ /// .into_iter()
+ /// .map(String::from)
+ /// .collect<Vec<String>>();
///
- /// let command_success = vec!["cargo", "build", "--release"]
+ /// let command_on_path = vec!["cargo", "build", "--release"]
/// .into_iter()
/// .map(String::from)
/// .collect<Vec<String>>();
///
- /// let command_fail = vec!["make", "-j8"]
- /// .into_iter()
- /// .map(String::from)
- /// .collect<Vec<String>>();
+ /// let command_built_in = vec!["alias", "g=git"]
+ /// .into_iter()
+ /// .map(String::from)
+ /// .collect<Vec<String>>();
+ ///
+ /// let command_no_exist = vec!["thisdoesntexist"]
+ /// .into_iter()
+ /// .map(String::from)
+ /// .collect<Vec<String>>();
+ ///
+ /// let verse = Verse::new();
+ /// verse.stanza = Stanza::new(command_full_path);
+ /// verse.spellcheck(&env.bins); // -> Some(Spelling::FullPath)
+ ///
+ /// let verse = Verse::new();
+ /// verse.stanza = Stanza::new(command_on_path);
+ /// verse.spellcheck(&env.bins); // -> Some(Spelling::OnPath)
///
- /// let stanza_success = Stanza::new(command_success);
- /// let stanza_fail = Stanza::new(command_fail);
+ /// let verse = Verse::new();
+ /// verse.stanza = Stanza::new(command_built_in);
+ /// verse.spellcheck(&env.bins); // -> Some(Spelling::BuiltIn)
///
- /// stanza_success.spellcheck(bins) // -> Some(i)
- /// stanza_fail.spellcheck(bins) // -> None
+ /// let verse = Verse::new();
+ /// verse.stanza = Stanza::new(command_no_exist);
+ /// verse.spellcheck(&env.bins); // -> None
/// ```
pub fn spellcheck(&self, bins: &Vec<String>) -> Option<Spelling> {
// An empty verb (i.e. the empty string) cannot be a program, so
@@ -261,11 +298,12 @@ impl Verse {
/// Run a command
///
- /// The [Poem]::recite() function calls this [Verse::incant] function for
- /// each verse it contains. This function handles the actual setup and
- /// spawning (forking) of a new process specified in the [Verse]. It will
- /// also run IO operations for the verse, and setup appropriate coupling,
- /// as per the [Verse]'s own details, contained throughout its fields.
+ /// The [recite()][crate::poem::recite] function calls this
+ /// [incant()][Verse::incant] function for each verse it contains.
+ /// This function handles the actual setup and spawning (forking) of
+ /// a new process specified in the [Verse]. It will also run IO
+ /// operations for the verse, and setup appropriate coupling, as per
+ /// the [Verse]'s own details, contained throughout its fields.
pub fn incant(
&mut self,
out: &mut Vec<u8>,
diff --git a/src/poem/elements/verse/logic.rs b/src/poem/elements/verse/logic.rs
index f5efdee..e7ed4df 100644
--- a/src/poem/elements/verse/logic.rs
+++ b/src/poem/elements/verse/logic.rs
@@ -1,3 +1,17 @@
+/// Spawn a program
+///
+/// This macro provides a common interface for running system programs,
+/// as well as built-in shell commands. This is possible, since the
+/// shell's homebrew facilities for running built-ins mimic the
+/// interface of [std::process::Command]. See
+/// [crate::poem::anthology::Anthology] for the implementation details.
+///
+/// First, the macro sets the arguments for the command. Next, it
+/// determines the whether or not text should be piped in/out of the
+/// command. The process is spawned, then it determines what to do based
+/// on the [crate::poem::elements::verse::Verse]'s meter (wait, fork to
+/// background, or capture STDOUT). Finally, the macro performs any IO
+/// functions (i.e. writing/appending STDOUT or STDERR to a file).
#[macro_export]
macro_rules! incant {
($verb:expr, $command:expr, $out:expr, $pids:expr, $env:expr, $self:expr) => {{
diff --git a/src/poem/elements/word.rs b/src/poem/elements/word.rs
index dd088e0..f51dc7d 100644
--- a/src/poem/elements/word.rs
+++ b/src/poem/elements/word.rs
@@ -1,2 +1,3 @@
-/// A (typically) space dilineated piece of a [Stanza][super::stanza::Stanza]
+/// A (typically) space dilineated piece of a
+/// [Stanza][super::stanza::Stanza]
pub type Word = Vec<char>;