diff options
| author | Rory Dudley | 2024-06-30 20:09:26 -0600 | 
|---|---|---|
| committer | Rory Dudley | 2024-06-30 20:09:26 -0600 | 
| commit | b8338719e2cc2138bc67c10ad56fb707f5e3b546 (patch) | |
| tree | c27c2dc3a6dc7491da94e47eaad4530e855d17f1 | |
| parent | e23e4a036008a6f3a3356d48434615a05dcc17e0 (diff) | |
| download | dwarvish-b8338719e2cc2138bc67c10ad56fb707f5e3b546.tar.gz | |
Add/update doc comments
This patch update a ton of the documentation comments throughout the
codebase, refactoring some areas, and adding new comments to others.
| -rw-r--r-- | src/compose.rs | 15 | ||||
| -rw-r--r-- | src/compose/environment.rs | 33 | ||||
| -rw-r--r-- | src/poem.rs | 4 | ||||
| -rw-r--r-- | src/poem/anthology.rs | 57 | ||||
| -rw-r--r-- | src/poem/anthology/alias.rs | 4 | ||||
| -rw-r--r-- | src/poem/anthology/cd.rs | 9 | ||||
| -rw-r--r-- | src/poem/anthology/export.rs | 4 | ||||
| -rw-r--r-- | src/poem/anthology/source.rs | 4 | ||||
| -rw-r--r-- | src/poem/anthology/which.rs | 12 | ||||
| -rw-r--r-- | src/poem/elements/rune.rs | 116 | ||||
| -rw-r--r-- | src/poem/elements/stanza.rs | 12 | ||||
| -rw-r--r-- | src/poem/elements/verse.rs | 174 | ||||
| -rw-r--r-- | src/poem/elements/verse/logic.rs | 14 | ||||
| -rw-r--r-- | src/poem/elements/word.rs | 3 | ||||
| -rw-r--r-- | src/poem/read.rs | 39 | ||||
| -rw-r--r-- | src/poem/recite.rs | 11 | 
16 files changed, 351 insertions, 160 deletions
diff --git a/src/compose.rs b/src/compose.rs index dfbbaef..b12d1a4 100644 --- a/src/compose.rs +++ b/src/compose.rs @@ -5,6 +5,14 @@ use std::env;  use std::fs;  use std::path::PathBuf; +/// Setup the global shell environment +/// +/// Sets up the shell's environment via configuration files. In order: +/// * `/etc/dwvshrc` +/// * `~/.dwvshrc` +/// +/// For debug builds, all files will instead be sourced from +/// `./dist/...` with the exception of `~/.dwvshrc`.  pub fn env() -> Environment {      // Create a new Environment object, to store some extra shell info      let mut env = Environment::new(); @@ -39,6 +47,13 @@ pub fn env() -> Environment {      env  } +/// Read, read, and recite +/// +/// Small, reusable function used to do the heavy lifting in regards to +/// sourcing configuration files. [Read][fs::read_to_string]s a file +/// from disk, then [read][crate::poem::read]s (parses) a [Poem], +/// then [recite][crate::poem::recite]s that [Poem]. +/// Configuration files are just shell scripts.  fn rrr(path: PathBuf, env: &mut Environment) {      let poetry = match fs::read_to_string(&path) {          Ok(poetry) => poetry, diff --git a/src/compose/environment.rs b/src/compose/environment.rs index 151c7a5..540401b 100644 --- a/src/compose/environment.rs +++ b/src/compose/environment.rs @@ -2,19 +2,13 @@ use std::collections::HashMap;  /// Record the shell state  /// -/// The [Environment] struct keeps track of various fields, all relating to the -/// shell state. The environment is the first thing setup at the beginning of -/// the shell, and is maintained throughout the lifetime of the process. +/// The [Environment] struct keeps track of various fields, all relating +/// to the shell state. The environment is the first thing setup at the +/// beginning of the shell, and is maintained throughout the lifetime of +/// the process.  /// -/// Both [crate::Poem]::read() and [crate::Poem]::recite() rely on this struct -/// for various functions and features. -/// -/// # Fields -/// aliases - A table of aliases, set by the user using the built-in 'alias' -/// bins - A lookup table for +x files, constructed from the $PATH -/// cs - Indication of callstack level, helpful for recursively dealing with -///      aliases -/// fc - Force the capture of stdout (for internal poems) +/// Both [read()][crate::poem::read] and [recite()][crate::poem::recite] +/// rely on this struct for various functions and features.  ///  /// # Examples  /// ``` @@ -22,14 +16,27 @@ use std::collections::HashMap;  ///     let mut env = compose::env();  ///     let poem = Poem::read("alias", &mut env)?;  ///     poem.recite(&mut env)?; -///     () +///     Ok(())  /// }  /// ```  #[derive(Debug, PartialEq, Eq, Clone)]  pub struct Environment { +    /// A table of aliases, set by the user using the built-in 'alias' +    /// command      pub aliases: HashMap<String, String>, + +    /// A lookup table for +x files, constructed from the $PATH (see +    /// [spellcheck()][crate::poem::elements::verse::Verse::spellcheck] +    /// for more details)      pub bins: Vec<String>, + +    /// Indication of callstack level, helpful for recursively dealing +    /// with aliases (see +    /// [add()][crate::poem::elements::verse::Verse::add] for more +    /// details)      pub cs: u8, + +    /// Force the capture of STDOUT (for internal poems)      pub fc: bool,  } diff --git a/src/poem.rs b/src/poem.rs index 362eaaa..e330679 100644 --- a/src/poem.rs +++ b/src/poem.rs @@ -1,8 +1,8 @@  mod anthology; -mod elements; -use elements::verse::Verse; +pub mod elements;  pub mod read;  pub mod recite; +use elements::verse::Verse;  /// Parse and run shell commands or `dwvsh` files  /// diff --git a/src/poem/anthology.rs b/src/poem/anthology.rs index 086864c..0026b8d 100644 --- a/src/poem/anthology.rs +++ b/src/poem/anthology.rs @@ -15,7 +15,8 @@ static INDEX: [&str; 8] = [  /// Lookup the index of a built-in command  /// -/// Looks up the index of a built-in command in [INDEX], accounting for aliases. +/// Looks up the index of a built-in command in [INDEX], accounting for +/// aliases.  ///  /// # Aliases  /// * quit -> exit @@ -29,34 +30,67 @@ pub fn lookup(verb: &str) -> Option<usize> {      INDEX.iter().position(|v| v.to_string() == verb)  } +/// Dummy interface for STDIN +/// +/// A helper struct for dealing with STDIN in built-in commands. +/// Currently, there are no built-in commands that actually use this, +/// but it needs to exist for the `incant!()` macro to function +/// properly. See [Anthology] for more details.  #[derive(Debug, PartialEq, Eq, Clone)]  pub struct AnthologyStdin { +    /// Bytes      data: Vec<u8>,  }  impl AnthologyStdin { +    /// Create a new instance of AnthologyStdin      pub fn new() -> Self {          AnthologyStdin { data: Vec::new() }      } +    /// Return a mutable version of self      pub fn as_mut(&mut self) -> Option<&mut Self> {          Some(self)      } +    /// Write bytes specified by data into STDIN      pub fn write_all(&mut self, data: &[u8]) -> Result<(), io::Error> {          self.data.append(&mut data.to_vec());          Ok(())      }  } +/// Interface for built-in commands +/// +/// The implementation of [Anthology] is designed to mimic +/// [std::process::Command], in order to avoid code redundancy. The +/// internal structure of [Anthology] is fairly irrelevant to this +/// `impl`, with the exception of the `stdin`, and `output` fields. In +/// addition to the documentation below, it may also be helpful to read +/// through the `incant!()` macro, so see how processes are actually +/// forked.  #[derive(Debug, Clone)]  pub struct Anthology { +    /// Name of the built-in command (see [lookup()] and/or [INDEX])      verb: String, + +    /// Arguments to pass to the built-in command      clause: Option<Vec<String>>, + +    /// Indicates STDIN should be read in (but no built-ins use STDIN)      uin: bool, + +    /// Indicates STDOUT should be captured      uout: bool, + +    /// Indicates STDERR should be captured      uerr: bool, + +    /// Compatability with [std::process::Command]      pub stdin: AnthologyStdin, + +    /// Stores the built-in output (return code, STDOUT, STDERR), also +    /// needed for compatability with [std::process::Command]      output: Option<Output>,  } @@ -110,11 +144,28 @@ impl Anthology {          self.uerr = true;      } +    /// Set the process group +    /// +    /// This is only needed if a process is forked into the background. +    /// Technically this is possible with the built-ins, but not really +    /// useful, so this function simply does nothing. As a result, +    /// built-ins that get forked into the background always return +    /// immediately.      pub fn process_group(&mut self, _id: usize) {} + +    /// Get the process id +    /// +    /// This is only needed if a process is forked into the background. +    /// Will always return `0` for built-in commands. Also see +    /// [process_group()][Anthology::process_group].      pub fn id(&mut self) -> i32 {          0      } +    /// Run a built-in command +    /// +    /// Runs a built-in command based on the `verb`, appropriately +    /// passing arguments and [Environment] fields as necessary.      pub fn spawn(&mut self, env: &mut Environment) -> Result<Self, io::Error> {          // Incant the built-in and set the output          self.output = Some(match self.verb.as_str() { @@ -132,6 +183,10 @@ impl Anthology {          Ok(self.clone())      } +    /// Get the output of a built-in +    /// +    /// Return the [Output] of a built-in command. This function needed +    /// for compatibility with [std::process::Command].      pub fn wait_with_output(&self) -> Result<Output, io::Error> {          match &self.output {              Some(output) => Ok(output.clone()), diff --git a/src/poem/anthology/alias.rs b/src/poem/anthology/alias.rs index 0746b59..fdd1224 100644 --- a/src/poem/anthology/alias.rs +++ b/src/poem/anthology/alias.rs @@ -5,8 +5,8 @@ use std::process::{ExitStatus, Output};  /// alias  /// -/// The builtin `alias` command. Used to monikers for other verbs, or entire -/// verses. +/// The builtin `alias` command. Used to monikers for other verbs, or +/// entire verses.  ///  /// # Shell Example  /// ```sh diff --git a/src/poem/anthology/cd.rs b/src/poem/anthology/cd.rs index bdf04f6..4427536 100644 --- a/src/poem/anthology/cd.rs +++ b/src/poem/anthology/cd.rs @@ -5,13 +5,16 @@ use std::process::{ExitStatus, Output};  /// cd  ///  /// The builtin `cd` command. Used to change directories. This must be -/// implemented by the shell, since the `pwd` is context sensitive within a -/// process. If no arguments are given, `cd` will take the user back to their -/// home directory (i.e. `~`). +/// implemented by the shell, since the present working directory +/// (`pwd`) is context sensitive within a process. If no arguments are +/// given, `cd` will take the user back to their home directory (i.e. +/// `~` / `$HOME`).  ///  /// # Shell Example  /// ```sh  /// cd ~/.config # Change into /home/<user>/.config +/// cd / # Change into the root directory +/// cd # Change into the home directory  /// ```  pub fn incant(clause: &Option<Vec<String>>, uerr: bool) -> Output {      let status; diff --git a/src/poem/anthology/export.rs b/src/poem/anthology/export.rs index 35a24ae..4c8e46d 100644 --- a/src/poem/anthology/export.rs +++ b/src/poem/anthology/export.rs @@ -5,8 +5,8 @@ use std::process::{ExitStatus, Output};  /// export  /// -/// The builtin `export` command. Used to set global environment variables for -/// the current instance of the shell. +/// The builtin `export` command. Used to set global environment +/// variables for the current instance of the shell.  ///  /// # Aliases  /// * export diff --git a/src/poem/anthology/source.rs b/src/poem/anthology/source.rs index 0ed759c..fc27caf 100644 --- a/src/poem/anthology/source.rs +++ b/src/poem/anthology/source.rs @@ -6,8 +6,8 @@ use std::process::{ExitStatus, Output};  /// source  /// -/// The builtin `source` command. Used to change the shell's global environment -/// state via a `.sh` or `.dwvsh` file. +/// The built-in `source` command. Used to change the shell's global +/// environment state via a `.sh` or `.dwvsh` file.  ///  /// # Shell Examples  /// ```sh diff --git a/src/poem/anthology/which.rs b/src/poem/anthology/which.rs index 0872dda..9a1708a 100644 --- a/src/poem/anthology/which.rs +++ b/src/poem/anthology/which.rs @@ -4,6 +4,18 @@ use crate::poem::Verse;  use std::os::unix::process::ExitStatusExt;  use std::process::{ExitStatus, Output}; +/// which +/// +/// The built-in `which` command. Used to check what program would be +/// called when not providing a full path. On Linux, it seems most +/// distros ship with a standalone `which` program. BSD systems, on the +/// other hand, tend to just use the shell built-in. +/// +/// # Shell Examples +/// ```sh +/// which ls # -> /bin/ls +/// which exit # -> shell built-in command +/// ```  pub fn incant(clause: &Option<Vec<String>>, uout: bool, uerr: bool, env: &Environment) -> Output {      let mut status = 0;      let mut out: Vec<u8> = Vec::new(); 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>; diff --git a/src/poem/read.rs b/src/poem/read.rs index 0418738..6d7550b 100644 --- a/src/poem/read.rs +++ b/src/poem/read.rs @@ -8,10 +8,35 @@ use crate::compose::Environment;  use crate::{poem, remark, string};  use parse::next; +/// Custom errors for the parser ([read()][crate::poem::read])  #[derive(Debug, PartialEq, Eq)]  pub enum Mishap { +    /// Generic parser error      ParseMishap(usize, usize, char), + +    /// IO operation parse errors +    /// +    /// Raised when an IO operation is specified, but a filepath was not +    /// given. +    /// +    /// # Examples +    /// ```sh +    /// cat < # No file specified for Rune::Read +    /// cat file.txt >> # No file specified for Rune::Addendum +    /// ```      IOMishap(usize, usize, char), + +    /// Missing end character +    /// +    /// Some [Rune]s consists of two characters, that may contain other +    /// characters between them (i.e. [String][Rune::String]). This is +    /// raised when the ending character was left out. +    /// +    /// # Examples +    /// ```sh +    /// echo 'Hello # Ending ' character is missing +    /// mv file.txt hello.txt" # Beginning " character is missing +    /// ```      PartialMishap(usize, usize, char),  } @@ -55,13 +80,14 @@ impl Appendable for Poem {      /// Push a [Verse] to the [Poem]      /// -    /// Push a [Verse] to the [Poem] after checking that the [Verse] is not -    /// empty. It also: +    /// Push a [Verse] to the [Poem] after checking that the [Verse] is +    /// not empty. It also:      ///  - sets the meter of the [Verse],      ///  - determines the couplet status of the [Verse],      ///  - and checks for aliases associated the the [Verse]'s verb.      /// -    /// Once the [Verse] is pushed to the [Poem], the verse stack is cleared. +    /// Once the [Verse] is pushed to the [Poem], the verse stack is +    /// cleared.      ///      /// # Examples      /// ``` @@ -157,9 +183,10 @@ impl Readable for Poem {      /// Parse a [Poem] from a raw [String] input      ///      /// Takes a shell command/program or file and converts it to a -    /// machine-runnable [Poem]. If there is a parse error, [Poem::read] may -    /// return a [Mishap]. See [Poem::recite][super::recite] or [Verse::incant] -    /// for how each [Verse] in a [Poem] is called. +    /// machine-runnable [Poem]. If there is a parse error, +    /// [read()][Poem::read] may return a [Mishap]. See +    /// [recite()][crate::poem::recite] or [incant()][Verse::incant] for +    /// how each [Verse] in a [Poem] is called.      fn read(poetry: String, env: &mut Environment) -> Result<Poem, Mishap> {          // Get all the characters in the input string as an iterator          let mut chars = poetry.chars().into_iter(); diff --git a/src/poem/recite.rs b/src/poem/recite.rs index 7ceecca..89f71c8 100644 --- a/src/poem/recite.rs +++ b/src/poem/recite.rs @@ -17,11 +17,12 @@ pub trait Reciteable {  impl Reciteable for Poem {      /// Recite a [Poem]      /// -    /// Runs the commands specified in all verses for a given [Poem]. See -    /// [crate::poem::Verse::incant] for more details on how processes are -    /// forked. In addition to running each [crate::poem::Verse], -    /// [Poem::recite] also checks for the presence of environment variables, -    /// as well as sub-poems, before running the [crate::poem::Verse]'s +    /// Runs the commands specified in all verses for a given [Poem]. +    /// See [incant()][crate::poem::Verse::incant] for more details on +    /// how processes are forked. In addition to running each +    /// [Verse][crate::poem::Verse], [recite()][Poem::recite] also +    /// checks for the presence of environment variables, as well as +    /// internal poems, before running the [Verse][crate::poem::Verse]'s      /// [Stanza].      fn recite(&self, env: &mut Environment) -> Result<Vec<u8>, io::Error> {          // Variable for storing the output of a piped verse  | 
