use super::{
argument,
Argument,
ArgExpansion,
Cursor,
Checkpoint,
State,
Transition,
};
pub(super) trait ExpansionContext {
fn produce(self, expansion: ArgExpansion) -> Transition;
fn rollback(self, checkpoint: Checkpoint) -> Transition;
fn is_expansion_word(value: u8) -> bool;
}
#[derive(Debug)]
pub(super) struct Expansion<C> {
start: Checkpoint,
allow_home: bool,
tilde_consumed: bool,
context: C,
}
impl<C> Expansion<C>
where
C: ExpansionContext,
State: From<Self>,
{
pub fn at(cursor: &Cursor, allow_home: bool, context: C) -> Self {
Self {
start: cursor.checkpoint(),
allow_home,
tilde_consumed: false,
context,
}
}
pub fn visit(mut self, cursor: &Cursor) -> Transition {
let allow_home = self.allow_home;
self.allow_home = false;
match cursor.peek() {
Some(b'~') if allow_home => {
self.tilde_consumed = true;
Transition::step(self)
}
Some(b'/') if self.tilde_consumed => {
self.context.produce(ArgExpansion::Home)
}
Some(_) if self.tilde_consumed => self.context.rollback(self.start),
Some(b'*') => {
self.context.produce(ArgExpansion::Star)
}
Some(b'%') => {
self.context.produce(ArgExpansion::Percent)
}
Some(b'[') => {
todo!() }
Some(b'{') => {
todo!() }
_ => self.context.rollback(self.start)
}
}
}
impl From<Expansion<Argument>> for State {
fn from(state: Expansion<Argument>) -> Self {
Self::Expansion(state)
}
}
impl From<Expansion<argument::Word<Argument>>> for State {
fn from(state: Expansion<argument::Word<Argument>>) -> Self {
Self::ExpansionWord(state)
}
}
pub fn is_start(c: u8) -> bool {
b"{[~*%".contains(&c)
}