aboutsummaryrefslogtreecommitdiffstats
path: root/src/parse/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse/mod.rs')
-rw-r--r--src/parse/mod.rs46
1 files changed, 43 insertions, 3 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 006fce2..9d3164e 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -912,6 +912,20 @@ struct Cursor<'a> {
backtrace: bool,
}
+#[derive(Default)]
+struct SpaceStats {
+ space: u32,
+ tab: u32,
+ lf: u32,
+ cr: u32,
+}
+
+impl SpaceStats {
+ fn is_empty(&self) -> bool {
+ self.space == 0 && self.tab == 0 && self.lf == 0 && self.cr == 0
+ }
+}
+
impl<'a> Cursor<'a> {
fn new(buf: &'a [u8], mode: ParseMode) -> Self {
Self {
@@ -978,6 +992,31 @@ impl<'a> Cursor<'a> {
}
}
+ fn spaces_stats(&mut self) -> SpaceStats {
+ let mut stats = SpaceStats::default();
+ while self.has() && b" \t\n\r".contains(&self.buf[0]) {
+ match self.buf[0] {
+ b' ' => stats.space += 1,
+ b'\t' => stats.tab += 1,
+ b'\n' => stats.lf += 1,
+ b'\r' => stats.cr += 1,
+ _ => unreachable!(),
+ }
+ self.adv();
+ }
+ stats
+ }
+
+ /// returns true if the next thing in the buffer is whitespace (including at least one newline)
+ ///
+ /// does not modify the buffer
+ fn whitespace_newline(&mut self) -> bool {
+ let x = self.buf;
+ let s = self.spaces_stats();
+ self.buf = x;
+ s.lf > 0
+ }
+
fn is_completion(&self) -> bool {
matches!(self.mode, ParseMode::Completion)
}
@@ -1015,7 +1054,7 @@ impl Parse for Command<PreExpansion> {
fn parse(b: &mut Cursor<'_>) -> Result<Self> {
let path: ExpString = b.parse()?;
let mut args = Vec::new();
- loop {
+ while !b.whitespace_newline() {
match ExpString::parse(b) {
Ok(arg) => args.push(arg),
Err(ParseError::NotAString) => break,
@@ -1031,7 +1070,8 @@ impl Parse for Pipes<PreExpansion> {
let mut cmds: Vec<Command<PreExpansion>> = vec![b.parse()?];
loop {
- b.spaces();
+ let space_stats = b.spaces_stats();
+
if b.is_empty() {
return Ok(Pipes { cmds });
}
@@ -1040,7 +1080,7 @@ impl Parse for Pipes<PreExpansion> {
if c == b'|' {
b.adv();
cmds.push(b.parse()?);
- } else if is_symbol(c) {
+ } else if space_stats.lf > 0 || is_symbol(c) {
return Ok(Pipes { cmds });
} else {
Err(ParseError::Unknown(c))?;