summaryrefslogtreecommitdiffstats
path: root/src/poem/read
diff options
context:
space:
mode:
authorRory Dudley2024-05-19 18:50:06 -0600
committerRory Dudley2024-05-19 18:50:06 -0600
commit4b1b8061e79b42128df4f06fd1e439549bf9696b (patch)
tree80db43cf7295937751d61435fb4e60118b8a3ea9 /src/poem/read
parent8756d3e7512c1416cc15a688c62b8f51f030b192 (diff)
downloaddwarvish-4b1b8061e79b42128df4f06fd1e439549bf9696b.tar.gz
Handle STDERR, in addition to STDOUT
This patch overhauls the reading and reciting of verses, such that the redirection of STDERR (in addition to STDOUT, which was already a feature), is now possible. Removed the 'stdout' argument from recite(), since it is no longer needed with how incantations function. A verse's couplet indicator is now a u8, instead of a bool, with certain values corresponding to types of couplets, for instance: ls | grep Ca | lolcat ^ ^ ^ | | 2: right side of a couplet | 3: both sides of a couplet 1: left side of a couplet Incantions are no longer hanlded in rune.rs, and the task macros have been removed. Now, a verse incants itself, matching on its own meter to determine how to handle the next verse. The following runes were added to help with handling STDERR: Write2 -> 2> WriteAll -> &> Addendum2 -> 2>> AddendumAll -> &>> The 'io' field in verse was changed from an Option<Rune>, to an array of Runes, since a single verse might have multiple IO operations. The following fields were added to Verse, to assist with handling STDERR: ip -> List of filenames to read into STDIN op -> List of filenames to send STDOUT to ep -> List of filenames to send STDERR to Keep track of channels when reading a poem. Channels are relating to IO operations. If channel is None, words get pushed to the verse's primary stanza (i.e. the verb or the clause). If a channel is selected, words are pushed to one of the aforementioned new fields in Verse. Read -> ip Write/Addedum -> op Write2/Addedum2 -> ep WriteAll/AddendumAll -> op and ep
Notes
Notes: This commit also added tests for the new Runes.
Diffstat (limited to 'src/poem/read')
-rw-r--r--src/poem/read/parse.rs52
1 files changed, 34 insertions, 18 deletions
diff --git a/src/poem/read/parse.rs b/src/poem/read/parse.rs
index 27c4728..fc1979f 100644
--- a/src/poem/read/parse.rs
+++ b/src/poem/read/parse.rs
@@ -15,29 +15,45 @@ use std::str::Chars;
///
/// # Examples:
/// ```
-/// next(&mut chars, &mut i, Rune::Write, vec![('>', Rune::Addendum)])
-/// next(&mut chars, &mut i, Rune::Quiet, vec![('&', Rune::And)])
+/// next(&mut chars, &mut i, Rune::Write, vec![(">", Rune::Addendum)])
+/// next(&mut chars, &mut i, Rune::Quiet, vec![("&", Rune::And)])
/// ```
-pub fn next(chars: &mut Chars, i: &mut usize, otherwise: Rune, ahead: Vec<(char, Rune)>) -> Rune {
- // Try to get the next character in the poem
- let next = match chars.peekable().peek() {
- Some(c) => *c,
- None => {
- return otherwise;
- }
- };
+pub fn next(chars: &mut Chars, i: &mut usize, otherwise: Rune, ahead: Vec<(&str, Rune)>) -> Rune {
+ // Initialize rune (the return value) with the default
+ let mut rune = otherwise;
+
+ // We need to peek the iterator
+ let mut peekable = chars.clone().peekable();
+
+ // Help keep track of matched characters
+ let mut j = 0;
- // Check if that next character matches any characters in ahead
- for (c, rune) in ahead.iter() {
- if next == *c {
- chars.next();
- *i += 1;
- return *rune;
+ // For each tuple pair (string, rune)...
+ for (s, r) in ahead.iter() {
+ // For each character in in the string, starting at length j...
+ for c in s[j..].chars().into_iter() {
+ // If the next char matches...
+ match peekable.peek() {
+ Some(next) if next == &c => {
+ // Increment counters
+ chars.next();
+ peekable.next();
+ *i += 1;
+ j += 1;
+
+ // Only update the rune if j equals the length of the string
+ if j == s.len() {
+ rune = *r;
+ }
+ }
+ Some(_) => {}
+ None => {}
+ }
}
}
- // If it doesn't match, return the default
- otherwise
+ // Return whatever the rune was determined to be
+ rune
}
/// Keep pushing to the [Word][super::super::elements::word::Word] stack