Skip to content

Commit bd82435

Browse files
committed
wip: parse3 example
1 parent 7f3b4d8 commit bd82435

File tree

1 file changed

+102
-24
lines changed

1 file changed

+102
-24
lines changed

src/ansi.rs

Lines changed: 102 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -573,11 +573,17 @@ fn parse4<'a>(input: &'a str) -> OpResult {
573573
nom::sequence::terminated(nom::combinator::map_res(P::recognize, P::map), tail)
574574
}
575575

576-
fn opt_param<'a, P: Params<'a>, Any>(
576+
fn opt_param<'a, P: Params<'a> + Copy, Any>(
577577
tail: impl StrParser<'a, Any>,
578578
default: P,
579579
) -> impl StrParser<'a, P> {
580-
move |input| todo!()
580+
nom::sequence::terminated(
581+
nom::combinator::map_res(nom::combinator::opt(P::recognize), move |opt| match opt {
582+
None => Ok(default),
583+
Some(o) => P::map(o),
584+
}),
585+
tail,
586+
)
581587
}
582588

583589
use nom::branch::alt;
@@ -717,7 +723,7 @@ pub fn parse6(input: &str) -> Result<Op, String> {
717723
nom::combinator::success(""),
718724
));
719725
let fin = nom::combinator::recognize(nom::character::streaming::satisfy(|ch| {
720-
'\x40' < ch && ch < '\x7e'
726+
('\x40'..='\x7e').contains(&ch)
721727
}));
722728

723729
let (rest, ((params, intermediate), fin)) =
@@ -792,38 +798,110 @@ pub fn parse6(input: &str) -> Result<Op, String> {
792798
}
793799

794800
fn parse3(input: &str) -> OpResult {
795-
use self::start_with_esc as esc;
796801
use nom::branch::alt;
797802
use nom::character::streaming::char as ch;
798-
use nom::combinator::map;
803+
use nom::combinator::{cut, fail};
804+
use nom::sequence::terminated as term;
805+
806+
// can't use trait aliases in the return type, see: https://github.com/rust-lang/rust-analyzer/issues/13410
807+
fn esc<'a, P: StrParser<'a, O>, O>(
808+
parser: P,
809+
) -> impl nom::Parser<&'a str, O, nom::error::Error<&'a str>> {
810+
nom::sequence::preceded(ch('\x1b'), parser)
811+
}
812+
813+
// can't use trait aliases in the return type, see: https://github.com/rust-lang/rust-analyzer/issues/13410
814+
fn csi<'a, P: StrParser<'a, O>, O>(
815+
parser: P,
816+
) -> impl nom::Parser<&'a str, O, nom::error::Error<&'a str>> {
817+
nom::sequence::preceded(
818+
alt((
819+
nom::combinator::recognize(ch('\u{9b}')),
820+
nom::combinator::recognize(nom::bytes::streaming::tag("\x1b[")),
821+
)),
822+
parser,
823+
)
824+
}
825+
826+
trait Params<'a>: Sized {
827+
type O;
828+
type Err;
829+
fn recognize(input: &'a str) -> IResult<&'a str, Self::O>;
830+
fn map(o: Self::O) -> Result<Self, Self::Err>;
831+
}
832+
impl<'a> Params<'a> for (usize, usize) {
833+
type O = (&'a str, &'a str);
834+
type Err = ParseIntError;
835+
836+
fn recognize(input: &'a str) -> IResult<&'a str, (&'a str, &'a str)> {
837+
nom::sequence::separated_pair(
838+
nom::character::streaming::digit1,
839+
nom::character::streaming::char(';'),
840+
nom::character::streaming::digit1,
841+
)(input)
842+
}
843+
844+
fn map((a, b): (&'a str, &'a str)) -> Result<Self, ParseIntError> {
845+
Ok((usize::from_str(a)?, usize::from_str(b)?))
846+
}
847+
}
848+
849+
fn param<'a, P: Params<'a>>() -> impl StrParser<'a, P> {
850+
nom::combinator::map_res(P::recognize, P::map)
851+
}
852+
853+
fn final_char<I, E: nom::error::ParseError<I>>(i: I) -> IResult<I, char, E>
854+
where
855+
I: nom::Slice<nom::lib::std::ops::RangeFrom<usize>> + nom::InputIter,
856+
<I as nom::InputIter>::Item: nom::AsChar,
857+
{
858+
nom::character::streaming::satisfy(|ch| ('\x40'..='\x7e').contains(&ch)).parse(i)
859+
}
860+
861+
fn non_final<I, E: nom::error::ParseError<I>>(i: I) -> IResult<I, I, E>
862+
where
863+
I: nom::Slice<nom::lib::std::ops::RangeFrom<usize>>
864+
+ nom::Slice<nom::lib::std::ops::RangeTo<usize>>
865+
+ nom::InputIter
866+
+ Clone
867+
+ nom::Offset
868+
+ nom::InputLength,
869+
<I as nom::InputIter>::Item: nom::AsChar,
870+
{
871+
nom::combinator::recognize(nom::multi::many0_count(nom::character::streaming::satisfy(
872+
|ch| !('\x40'..='\x7e').contains(&ch),
873+
)))
874+
.parse(i)
875+
}
876+
877+
fn bail<I, O, E: nom::error::ParseError<I>>(i: I) -> IResult<I, O, E> {
878+
cut(fail)(i)
879+
}
799880

800881
alt((
801882
alt((
802-
esc(map(ch('7'), |_| Op::SaveCursorPos)),
803-
esc(map(ch('8'), |_| Op::RestoreCursorPos)),
804-
)),
805-
esc(nom::sequence::preceded(
806-
ch('['),
807-
map(ch('H'), |_| Op::MoveCursorAbs { x: 0, y: 0 }),
808-
)),
809-
esc(nom::sequence::preceded(
810-
ch('['),
811-
map(dual_int_parameter_sequence::<usize>('H'), |(a, b)| {
812-
Op::MoveCursorAbs {
813-
x: b.saturating_sub(1),
814-
y: a.saturating_sub(1),
815-
}
816-
}),
883+
esc(ch('7')).map(|_| Op::SaveCursorPos),
884+
esc(ch('8')).map(|_| Op::RestoreCursorPos),
817885
)),
818-
esc(nom::sequence::preceded(
819-
ch('['),
820-
map(dual_int_parameter_sequence::<usize>('f'), |(a, b)| {
886+
csi(alt((alt((
887+
alt((ch('H'), ch('f'))).map(|_| Op::MoveCursorAbs { x: 0, y: 0 }),
888+
term(param::<(usize, usize)>(), alt((ch('H'), ch('f')))).map(|(a, b)| {
821889
Op::MoveCursorAbs {
822890
x: b.saturating_sub(1),
823891
y: a.saturating_sub(1),
824892
}
825893
}),
826-
)),
894+
term(non_final, alt((ch('H'), ch('f')))).and_then(bail),
895+
)),))),
896+
// unknown sequence
897+
nom::combinator::recognize(nom::sequence::preceded(
898+
alt((
899+
esc(nom::combinator::success(())),
900+
csi(nom::combinator::success(())),
901+
)),
902+
term(non_final, final_char),
903+
))
904+
.and_then(bail),
827905
))(input)
828906
}
829907

0 commit comments

Comments
 (0)