Skip to content

Commit

Permalink
Merge pull request #19 from epage/winnow
Browse files Browse the repository at this point in the history
chore!: Upgrade to winnow 0.5
  • Loading branch information
epage authored Jul 14, 2023
2 parents b014891 + 5619188 commit d5a3a1e
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 24 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ pre-release-replacements = [
]

[dependencies]
winnow = "0.4.0"
winnow = "0.5.0"
itertools = "0.11"
7 changes: 3 additions & 4 deletions src/param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ impl<'s> Iterator for ConfigParametersIter<'s> {

fn next(&mut self) -> Option<Self::Item> {
// See git's config.c's `parse_config_env_list`
let (values, key) = crate::quote::sq_dequote_step(self.values.trim_start()).ok()?;
self.values = values;
self.values = self.values.trim_start();
let key = crate::quote::sq_dequote(&mut self.values).ok()?;

if let Some(values) = self.values.strip_prefix('=') {
// new-style 'key'='value'
Expand All @@ -68,8 +68,7 @@ impl<'s> Iterator for ConfigParametersIter<'s> {
self.values = values;
Some((key, None))
} else {
let (values, value) = crate::quote::sq_dequote_step(self.values).ok()?;
self.values = values;
let value = crate::quote::sq_dequote(&mut self.values).ok()?;
Some((key, Some(value)))
}
} else {
Expand Down
47 changes: 30 additions & 17 deletions src/quote.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
use std::borrow::Cow;

use itertools::Itertools;
use winnow::branch::*;
use winnow::bytes::*;
use winnow::multi::*;
use winnow::combinator::*;
use winnow::prelude::*;
use winnow::sequence::*;
use winnow::token::*;

pub fn sq_dequote_step(input: &str) -> IResult<&str, Cow<str>> {
#[derive(Debug)]
pub struct QuoteError;

impl std::fmt::Display for QuoteError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid quoting")
}
}

impl std::error::Error for QuoteError {}

pub fn sq_dequote_step<'i>(input: &mut &'i str) -> Result<Cow<'i, str>, QuoteError> {
sq_dequote.parse_next(input).map_err(|_e| QuoteError)
}

pub fn sq_dequote<'i>(input: &mut &'i str) -> PResult<Cow<'i, str>, ()> {
// See git's quote.c's `sq_dequote_step`
alt((sq_dequote_escaped, sq_dequote_no_escaped)).parse_next(input)
}

fn sq_dequote_escaped(input: &str) -> IResult<&str, Cow<str>> {
fn sq_dequote_escaped<'i>(input: &mut &'i str) -> PResult<Cow<'i, str>, ()> {
(
sq_dequote_section,
sq_dequote_trail,
many0(sq_dequote_trail),
repeat(0.., sq_dequote_trail),
)
.map(|(start, trail, mut trails): (_, _, Vec<_>)| {
trails.insert(0, trail);
Expand All @@ -27,22 +40,22 @@ fn sq_dequote_escaped(input: &str) -> IResult<&str, Cow<str>> {
.parse_next(input)
}

fn sq_dequote_no_escaped(input: &str) -> IResult<&str, Cow<str>> {
fn sq_dequote_no_escaped<'i>(input: &mut &'i str) -> PResult<Cow<'i, str>, ()> {
sq_dequote_section.map(Cow::Borrowed).parse_next(input)
}

fn sq_dequote_section(input: &str) -> IResult<&str, &str> {
terminated(preceded('\'', take_while0(|c| c != '\'')), '\'').parse_next(input)
fn sq_dequote_section<'i>(input: &mut &'i str) -> PResult<&'i str, ()> {
terminated(preceded('\'', take_while(0.., |c| c != '\'')), '\'').parse_next(input)
}

fn sq_dequote_trail(input: &str) -> IResult<&str, [&str; 2]> {
fn sq_dequote_trail<'i>(input: &mut &'i str) -> PResult<[&'i str; 2], ()> {
(escaped, sq_dequote_section)
.map(|(e, s)| [e, s])
.parse_next(input)
}

fn escaped(input: &str) -> IResult<&str, &str> {
preceded('\\', one_of("'!").recognize()).parse_next(input)
fn escaped<'i>(input: &mut &'i str) -> PResult<&'i str, ()> {
preceded('\\', one_of(['\'', '!']).recognize()).parse_next(input)
}

#[cfg(test)]
Expand All @@ -53,31 +66,31 @@ mod test_sq_dequote_step {
fn word() {
let fixture = "'name'";
let expected = Cow::Borrowed("name");
let (_, actual) = sq_dequote_step(fixture).unwrap();
let (_, actual) = sq_dequote.parse_peek(fixture).unwrap();
assert_eq!(actual, expected);
}

#[test]
fn space() {
let fixture = "'a b'";
let expected = Cow::Borrowed("a b");
let (_, actual) = sq_dequote_step(fixture).unwrap();
let (_, actual) = sq_dequote.parse_peek(fixture).unwrap();
assert_eq!(actual, expected);
}

#[test]
fn sq_escaped() {
let fixture = "'a'\\''b'";
let expected: Cow<str> = Cow::Owned("a'b".into());
let (_, actual) = sq_dequote_step(fixture).unwrap();
let (_, actual) = sq_dequote.parse_peek(fixture).unwrap();
assert_eq!(actual, expected);
}

#[test]
fn exclamation_escaped() {
let fixture = "'a'\\!'b'";
let expected: Cow<str> = Cow::Owned("a!b".into());
let (_, actual) = sq_dequote_step(fixture).unwrap();
let (_, actual) = sq_dequote.parse_peek(fixture).unwrap();
assert_eq!(actual, expected);
}
}

0 comments on commit d5a3a1e

Please sign in to comment.