Skip to content

Commit 1731b1c

Browse files
committed
wip: parse3 example
1 parent 9b9ac96 commit 1731b1c

File tree

1 file changed

+103
-25
lines changed

1 file changed

+103
-25
lines changed

src/ansi.rs

Lines changed: 103 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use alloc::{
5555
vec,
5656
vec::Vec,
5757
};
58-
use core::{fmt::Debug, marker::PhantomData, num::ParseIntError, str::FromStr};
58+
use core::{fmt::Debug, num::ParseIntError, str::FromStr};
5959
use nom::{IResult, Parser};
6060

6161
const ESC: char = '\u{1B}';
@@ -546,11 +546,17 @@ fn parse4<'a>(input: &'a str) -> OpResult {
546546
nom::sequence::terminated(nom::combinator::map_res(P::recognize, P::map), tail)
547547
}
548548

549-
fn opt_param<'a, P: Params<'a>, Any>(
549+
fn opt_param<'a, P: Params<'a> + Copy, Any>(
550550
tail: impl StrParser<'a, Any>,
551551
default: P,
552552
) -> impl StrParser<'a, P> {
553-
move |input| todo!()
553+
nom::sequence::terminated(
554+
nom::combinator::map_res(nom::combinator::opt(P::recognize), move |opt| match opt {
555+
None => Ok(default),
556+
Some(o) => P::map(o),
557+
}),
558+
tail,
559+
)
554560
}
555561

556562
use nom::branch::alt;
@@ -690,7 +696,7 @@ pub fn parse6(input: &str) -> Result<Op, String> {
690696
nom::combinator::success(""),
691697
));
692698
let fin = nom::combinator::recognize(nom::character::streaming::satisfy(|ch| {
693-
'\x40' < ch && ch < '\x7e'
699+
('\x40'..='\x7e').contains(&ch)
694700
}));
695701

696702
let (rest, ((params, intermediate), fin)) =
@@ -765,38 +771,110 @@ pub fn parse6(input: &str) -> Result<Op, String> {
765771
}
766772

767773
fn parse3(input: &str) -> OpResult {
768-
use self::start_with_esc as esc;
769774
use nom::branch::alt;
770775
use nom::character::streaming::char as ch;
771-
use nom::combinator::map;
776+
use nom::combinator::{cut, fail};
777+
use nom::sequence::terminated as term;
778+
779+
// can't use trait aliases in the return type, see: https://github.com/rust-lang/rust-analyzer/issues/13410
780+
fn esc<'a, P: StrParser<'a, O>, O>(
781+
parser: P,
782+
) -> impl nom::Parser<&'a str, O, nom::error::Error<&'a str>> {
783+
nom::sequence::preceded(ch('\x1b'), parser)
784+
}
785+
786+
// can't use trait aliases in the return type, see: https://github.com/rust-lang/rust-analyzer/issues/13410
787+
fn csi<'a, P: StrParser<'a, O>, O>(
788+
parser: P,
789+
) -> impl nom::Parser<&'a str, O, nom::error::Error<&'a str>> {
790+
nom::sequence::preceded(
791+
alt((
792+
nom::combinator::recognize(ch('\u{9b}')),
793+
nom::combinator::recognize(nom::bytes::streaming::tag("\x1b[")),
794+
)),
795+
parser,
796+
)
797+
}
798+
799+
trait Params<'a>: Sized {
800+
type O;
801+
type Err;
802+
fn recognize(input: &'a str) -> IResult<&'a str, Self::O>;
803+
fn map(o: Self::O) -> Result<Self, Self::Err>;
804+
}
805+
impl<'a> Params<'a> for (usize, usize) {
806+
type O = (&'a str, &'a str);
807+
type Err = ParseIntError;
808+
809+
fn recognize(input: &'a str) -> IResult<&'a str, (&'a str, &'a str)> {
810+
nom::sequence::separated_pair(
811+
nom::character::streaming::digit1,
812+
nom::character::streaming::char(';'),
813+
nom::character::streaming::digit1,
814+
)(input)
815+
}
816+
817+
fn map((a, b): (&'a str, &'a str)) -> Result<Self, ParseIntError> {
818+
Ok((usize::from_str(a)?, usize::from_str(b)?))
819+
}
820+
}
821+
822+
fn param<'a, P: Params<'a>>() -> impl StrParser<'a, P> {
823+
nom::combinator::map_res(P::recognize, P::map)
824+
}
825+
826+
fn final_char<I, E: nom::error::ParseError<I>>(i: I) -> IResult<I, char, E>
827+
where
828+
I: nom::Slice<nom::lib::std::ops::RangeFrom<usize>> + nom::InputIter,
829+
<I as nom::InputIter>::Item: nom::AsChar,
830+
{
831+
nom::character::streaming::satisfy(|ch| ('\x40'..='\x7e').contains(&ch)).parse(i)
832+
}
833+
834+
fn non_final<I, E: nom::error::ParseError<I>>(i: I) -> IResult<I, I, E>
835+
where
836+
I: nom::Slice<nom::lib::std::ops::RangeFrom<usize>>
837+
+ nom::Slice<nom::lib::std::ops::RangeTo<usize>>
838+
+ nom::InputIter
839+
+ Clone
840+
+ nom::Offset
841+
+ nom::InputLength,
842+
<I as nom::InputIter>::Item: nom::AsChar,
843+
{
844+
nom::combinator::recognize(nom::multi::many0_count(nom::character::streaming::satisfy(
845+
|ch| !('\x40'..='\x7e').contains(&ch),
846+
)))
847+
.parse(i)
848+
}
849+
850+
fn bail<I, O, E: nom::error::ParseError<I>>(i: I) -> IResult<I, O, E> {
851+
cut(fail)(i)
852+
}
772853

773854
alt((
774855
alt((
775-
esc(map(ch('7'), |_| Op::SaveCursorPos)),
776-
esc(map(ch('8'), |_| Op::RestoreCursorPos)),
777-
)),
778-
esc(nom::sequence::preceded(
779-
ch('['),
780-
map(ch('H'), |_| Op::MoveCursorAbs { x: 0, y: 0 }),
781-
)),
782-
esc(nom::sequence::preceded(
783-
ch('['),
784-
map(dual_int_parameter_sequence::<usize>('H'), |(a, b)| {
785-
Op::MoveCursorAbs {
786-
x: b.saturating_sub(1),
787-
y: a.saturating_sub(1),
788-
}
789-
}),
856+
esc(ch('7')).map(|_| Op::SaveCursorPos),
857+
esc(ch('8')).map(|_| Op::RestoreCursorPos),
790858
)),
791-
esc(nom::sequence::preceded(
792-
ch('['),
793-
map(dual_int_parameter_sequence::<usize>('f'), |(a, b)| {
859+
csi(alt((alt((
860+
alt((ch('H'), ch('f'))).map(|_| Op::MoveCursorAbs { x: 0, y: 0 }),
861+
term(param::<(usize, usize)>(), alt((ch('H'), ch('f')))).map(|(a, b)| {
794862
Op::MoveCursorAbs {
795863
x: b.saturating_sub(1),
796864
y: a.saturating_sub(1),
797865
}
798866
}),
799-
)),
867+
term(non_final, alt((ch('H'), ch('f')))).and_then(bail),
868+
)),))),
869+
// unknown sequence
870+
nom::combinator::recognize(nom::sequence::preceded(
871+
alt((
872+
esc(nom::combinator::success(())),
873+
csi(nom::combinator::success(())),
874+
)),
875+
term(non_final, final_char),
876+
))
877+
.and_then(bail),
800878
))(input)
801879
}
802880

0 commit comments

Comments
 (0)