use winnow::{
Parser,
ascii::{space0, space1},
combinator::{alt, eof, opt},
error::ErrMode,
token::literal,
};
pub fn parse(
input: &mut &str,
) -> winnow::error::Result<super::Metacommand, ErrMode<winnow::error::ContextError>> {
literal('\\').parse_next(input)?;
alt((literal("describe"), literal('d'))).parse_next(input)?;
let has_plus_first = opt(literal("+")).parse_next(input)?.is_some();
let has_exclaim_first = opt(literal("!")).parse_next(input)?.is_some();
let has_plus_second = opt(literal("+")).parse_next(input)?.is_some();
let has_exclaim_second = opt(literal("!")).parse_next(input)?.is_some();
let detail = has_plus_first || has_plus_second;
let sameconn = has_exclaim_first || has_exclaim_second;
space1.parse_next(input)?;
let start = *input;
let mut end_pos = 0;
for (pos, ch) in start.char_indices() {
if ch.is_whitespace() {
break;
}
end_pos = pos + ch.len_utf8();
}
if end_pos == 0 {
return Err(ErrMode::Backtrack(winnow::error::ContextError::new()));
}
let item = &start[..end_pos];
*input = &start[end_pos..];
space0.parse_next(input)?;
eof.parse_next(input)?;
Ok(super::Metacommand::Describe {
item: item.to_string(),
detail,
sameconn,
})
}
#[cfg(test)]
mod tests {
use super::super::*;
#[test]
fn test_parse_describe() {
let result = parse_metacommand("\\d users").unwrap();
assert_eq!(
result,
Some(Metacommand::Describe {
item: "users".to_string(),
detail: false,
sameconn: false,
})
);
}
#[test]
fn test_parse_describe_plus() {
let result = parse_metacommand("\\d+ users").unwrap();
assert_eq!(
result,
Some(Metacommand::Describe {
item: "users".to_string(),
detail: true,
sameconn: false,
})
);
}
#[test]
fn test_parse_describe_sameconn() {
let result = parse_metacommand("\\d! users").unwrap();
assert_eq!(
result,
Some(Metacommand::Describe {
item: "users".to_string(),
detail: false,
sameconn: true,
})
);
}
#[test]
fn test_parse_describe_plus_sameconn() {
let result = parse_metacommand("\\d+! users").unwrap();
assert_eq!(
result,
Some(Metacommand::Describe {
item: "users".to_string(),
detail: true,
sameconn: true,
})
);
}
#[test]
fn test_parse_describe_sameconn_plus() {
let result = parse_metacommand("\\d!+ users").unwrap();
assert_eq!(
result,
Some(Metacommand::Describe {
item: "users".to_string(),
detail: true,
sameconn: true,
})
);
}
#[test]
fn test_parse_describe_qualified() {
let result = parse_metacommand("\\d public.users").unwrap();
assert_eq!(
result,
Some(Metacommand::Describe {
item: "public.users".to_string(),
detail: false,
sameconn: false,
})
);
}
#[test]
fn test_parse_describe_long_form() {
let result = parse_metacommand("\\describe users").unwrap();
assert_eq!(
result,
Some(Metacommand::Describe {
item: "users".to_string(),
detail: false,
sameconn: false,
})
);
}
#[test]
fn test_parse_describe_long_form_plus() {
let result = parse_metacommand("\\describe+ users").unwrap();
assert_eq!(
result,
Some(Metacommand::Describe {
item: "users".to_string(),
detail: true,
sameconn: false,
})
);
}
}