diff options
Diffstat (limited to 'src/parse/mod.rs')
| -rw-r--r-- | src/parse/mod.rs | 77 |
1 files changed, 63 insertions, 14 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index d25767d..4806421 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -28,7 +28,7 @@ type Res<T, E> = std::result::Result<T, E>; pub trait Expander { type Error; - fn expand_var(&mut self, v: BString) -> Res<BString, Self::Error>; + fn expand_var(&mut self, v: BString, default: Option<BString>) -> Res<BString, Self::Error>; fn expand_cmd(&mut self, c: Ast<PostExpansion>) -> Res<BString, Self::Error>; } @@ -75,7 +75,17 @@ pub fn plain(x: &[u8]) -> StringPart { } pub fn var(x: &[u8]) -> StringPart { - StringPart::Var(VarName { name: x.to_vec() }) + StringPart::Var(Var { + name: VarName { name: x.to_vec() }, + default: None, + }) +} + +pub fn var_default(x: &[u8], default: ExpString) -> StringPart { + StringPart::Var(Var { + name: VarName { name: x.to_vec() }, + default: Some(default), + }) } pub fn cmdp(x: Ast<PreExpansion>) -> StringPart { @@ -150,10 +160,18 @@ impl CmdDisplay for StringPart { items.as_slice().cdisplay(w)?; write!(w, ")") } - StringPart::Var(var_name) => { - write!(w, "var(")?; - var_name.name.as_slice().cdisplay(w)?; - write!(w, ")") + StringPart::Var(var) => { + if let Some(default) = &var.default { + write!(w, "var_default(")?; + var.name.name.as_slice().cdisplay(w)?; + write!(w, ",")?; + default.cdisplay(w)?; + write!(w, ")") + } else { + write!(w, "var(")?; + var.name.name.as_slice().cdisplay(w)?; + write!(w, ")") + } } StringPart::Cmd(ast) => { write!(w, "cmdp(")?; @@ -312,10 +330,16 @@ impl Pipes<PreExpansion> { #[derive(Debug, Clone, PartialEq)] pub enum StringPart { Boring(BString), - Var(VarName), + Var(Var), Cmd(Ast<PreExpansion>), } +#[derive(Debug, Clone, PartialEq)] +pub struct Var { + name: VarName, + default: Option<ExpString>, +} + impl StringPart { pub fn is_boring(&self) -> bool { matches!(self, StringPart::Boring(..)) @@ -340,7 +364,13 @@ impl ExpString { for part in self.parts.into_iter() { let mut x = match part { StringPart::Boring(items) => items, - StringPart::Var(v) => e.expand_var(v.name)?, + StringPart::Var(v) => { + let default = match v.default { + Some(default) => Some(default.expand(e)?), + None => None, + }; + e.expand_var(v.name.name, default)? + } StringPart::Cmd(ast) => { let exp = ast.expand(e)?; e.expand_cmd(exp)? @@ -483,18 +513,34 @@ impl Parse for ExpString { if x == b'?' || x == b'!' { b.adv(); - p.push(StringPart::Var(VarName { name: vec![x] })) + p.push(StringPart::Var(Var { + name: VarName { name: vec![x] }, + default: None, + })) } else if is_var_begin(x) { let v = VarName::parse(b)?; - p.push(StringPart::Var(v)); + p.push(StringPart::Var(Var { + name: v, + default: None, + })); } else if x == b'{' { b.adv(); let v = VarName::parse(b)?; + let mut default = None; if !b.has() { return Err(ParseError::Eof); } else if b.peek() == b':' { - todo!(": in var expansion") + b.adv(); + if !b.has() { + return Err(ParseError::Eof); + } + if b.peek() == b'-' { + b.adv(); + default = Some(ExpString::parse(b)?); + } else { + todo!(": in var expansion") + } } if !b.has() { @@ -504,7 +550,7 @@ impl Parse for ExpString { } b.adv(); - p.push(StringPart::Var(v)); + p.push(StringPart::Var(Var { name: v, default })); } else if x == b'(' { b.adv(); let cmd = Ast::parse(b)?; @@ -530,8 +576,11 @@ impl Parse for ExpString { } if delim == b' ' && x == b'~' { - p.push(StringPart::Var(VarName { - name: b"HOME".to_vec(), + p.push(StringPart::Var(Var { + name: VarName { + name: b"HOME".to_vec(), + }, + default: None, })); } else { add_char(p, x); |
