Skip to content

Commit 9b9ac96

Browse files
committed
wip: everything compiles now, so it must work
1 parent 90442d4 commit 9b9ac96

File tree

1 file changed

+192
-72
lines changed

1 file changed

+192
-72
lines changed

src/ansi.rs

Lines changed: 192 additions & 72 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, str::FromStr};
58+
use core::{fmt::Debug, marker::PhantomData, num::ParseIntError, str::FromStr};
5959
use nom::{IResult, Parser};
6060

6161
const ESC: char = '\u{1B}';
@@ -119,25 +119,15 @@ type TextOpResult<'a> = IResult<&'a str, TextOp>;
119119

120120
trait StrParseFnMut<'a, O> = FnMut(&'a str) -> IResult<&'a str, O>;
121121

122-
fn start_with_char<'a, O, P: StrParser<'a, O>>(
123-
start: char,
124-
mut parser: P,
125-
) -> impl StrParseFnMut<'a, O> {
126-
move |input: &'a str| {
127-
nom::sequence::preceded(nom::character::streaming::char(start), |x: &'a str| {
128-
parser.parse(x)
129-
})
130-
.parse(input)
131-
}
122+
fn start_with_char<'a, O, P: StrParser<'a, O>>(start: char, parser: P) -> impl StrParser<'a, O> {
123+
nom::sequence::preceded(nom::character::streaming::char(start), parser)
132124
}
133125

134126
/// Recognize ESC, and then parses via the P parser. If P fails, this parser will return
135127
/// the Failure variant (by using nom `cut`). If the this parser does not recognize ESC
136128
/// it will return with the nom Error variant.
137-
fn start_with_esc<'a, O, P: StrParser<'a, O>>(mut parser: P) -> impl StrParseFnMut<'a, O> {
138-
move |input: &'a str| {
139-
start_with_char(ESC, nom::combinator::cut(|x: &'a str| parser.parse(x)))(input)
140-
}
129+
fn start_with_esc<'a, O, P: StrParser<'a, O>>(parser: P) -> impl StrParser<'a, O> {
130+
start_with_char(ESC, nom::combinator::cut(parser))
141131
}
142132

143133
// This will parse "...P... <ending>" for some char ending and parsed sequence P
@@ -495,10 +485,10 @@ fn parse4<'a>(input: &'a str) -> OpResult {
495485
nom::combinator::map(Chars { req, rest }, f)
496486
}
497487

498-
parse! {
499-
[ESC, ']', 'H'] => Op::MoveCursorAbs
500-
[ESC, ']', (a,b) @ params::<(usize,usize)>, 'H'] => |a, b| Op::MoveCursorAbs
501-
}
488+
// parse! {
489+
// [ESC, ']', 'H'] => Op::MoveCursorAbs
490+
// [ESC, ']', (a,b) @ params::<(usize,usize)>, 'H'] => |a, b| Op::MoveCursorAbs
491+
// }
502492

503493
fn seqz<'a, O>(
504494
(s, p): (&'a [char], impl StrParser<'a, O>),
@@ -526,27 +516,34 @@ fn parse4<'a>(input: &'a str) -> OpResult {
526516
}
527517
}
528518

529-
trait Params<'a> {
519+
trait Params<'a>: Sized {
530520
type O;
531-
fn parse(input: &'a str) -> IResult<&'a str, Self::O>;
532-
fn map(o: Self::O) -> Self;
521+
type Err;
522+
fn recognize(input: &'a str) -> IResult<&'a str, Self::O>;
523+
fn map(o: Self::O) -> Result<Self, Self::Err>;
533524
}
534525
impl<'a> Params<'a> for (usize, usize) {
535526
type O = (&'a str, &'a str);
536-
fn parse(input: &'a str) -> IResult<&'a str, (&'a str, &'a str)> {
537-
todo!()
527+
type Err = ParseIntError;
528+
529+
fn recognize(input: &'a str) -> IResult<&'a str, (&'a str, &'a str)> {
530+
nom::sequence::separated_pair(
531+
nom::character::streaming::digit1,
532+
nom::character::streaming::char(';'),
533+
nom::character::streaming::digit1,
534+
)(input)
538535
}
539536

540-
fn map(o: (&'a str, &'a str)) -> Self {
541-
todo!()
537+
fn map((a, b): (&'a str, &'a str)) -> Result<Self, ParseIntError> {
538+
Ok((usize::from_str(a)?, usize::from_str(b)?))
542539
}
543540
}
544541
// impl<'a> Params<'a> for isize {
545542

546543
// }
547544

548545
fn param<'a, P: Params<'a>, Any>(tail: impl StrParser<'a, Any>) -> impl StrParser<'a, P> {
549-
nom::sequence::terminated(nom::combinator::map(P::parse, P::map), tail)
546+
nom::sequence::terminated(nom::combinator::map_res(P::recognize, P::map), tail)
550547
}
551548

552549
fn opt_param<'a, P: Params<'a>, Any>(
@@ -590,20 +587,19 @@ fn parse4<'a>(input: &'a str) -> OpResult {
590587
Err(nom::Err::Incomplete(nom::Needed::Unknown))
591588
}
592589

590+
// fn parse7(input: &str) -> OpResult {
591+
// static SEQUENCES = [
592+
// "ESC [ <n> ; <n> ? H",
593+
// ];
593594

594-
fn parse7(input: &str) -> OpResult {
595-
static SEQUENCES = [
596-
"ESC [ <n> ; <n> ? H",
597-
];
598-
599-
fn make_parser(seq: &[&str]) -> impl FnMut() -> GenericSequence {
595+
// fn make_parser(seq: &[&str]) -> impl FnMut() -> GenericSequence {
600596

601-
}
597+
// }
602598

603-
// SEQUENCES
604-
}
599+
// // SEQUENCES
600+
// }
605601

606-
fn parse6(input: &str) -> OpResult {
602+
pub fn parse6(input: &str) -> Result<Op, String> {
607603
// ESC [ <n>;<n>? H
608604

609605
// "ESC 7" -> Op::SaveCursorPos,
@@ -612,44 +608,160 @@ fn parse6(input: &str) -> OpResult {
612608

613609
// generic parser:
614610
// s => ESC [ `[4, 6]` H
611+
// enum GenSeq<'a> {
612+
// Lit(char)
613+
// Param()
614+
// }
615+
// let foo = [""; 6];
616+
617+
// let gen_parse = |input| start_with_esc(nom::multi::fold_many_m_n(0, 6, parse, init, fold));
618+
619+
fn gen_parse<'a, 'str, const M: usize>(
620+
input: &'str str,
621+
q: &'a mut [&'str str; M],
622+
) -> IResult<&'str str, &'a [&'str str]> {
623+
let (input, start) = nom::combinator::cut(nom::combinator::recognize(
624+
nom::character::streaming::one_of("\u{1b}\u{9b}"),
625+
))
626+
.parse(input)?;
627+
628+
q[0] = start;
629+
// c0
630+
match nom::combinator::cond(
631+
start == "\x1b",
632+
nom::sequence::tuple((
633+
nom::combinator::opt(nom::sequence::tuple((
634+
nom::combinator::recognize(nom::character::streaming::char('\x21')),
635+
nom::combinator::recognize(nom::character::streaming::char('\x40')),
636+
))),
637+
nom::combinator::recognize(nom::character::streaming::satisfy(|ch| {
638+
'\x00' < ch && ch < '\x1f'
639+
// TODO: what set do these belong to ? any?
640+
|| ch == '7' || ch == '8'
641+
})),
642+
)),
643+
)
644+
.parse(input)
645+
{
646+
// collapse the two intro sequences to one
647+
Ok((rest, Some((Some(_), n)))) | Ok((rest, Some((None, n)))) => {
648+
q[1] = n;
649+
return Ok((rest, &q[..=1]));
650+
}
651+
Err(err @ nom::Err::Failure(_)) | Err(err @ nom::Err::Incomplete(_)) => {
652+
return Err(err)
653+
}
654+
// We didn't match a c0 sequence, nothing to return yet
655+
Err(nom::Err::Error(_)) | Ok((_, None)) => {}
656+
};
657+
658+
// TODO: c1 set
659+
660+
// control sequences
661+
let input = if start == "\x1b" {
662+
let (input, _) = nom::character::streaming::char('[').parse(input)?;
663+
// map everything to this particular CSI
664+
q[0] = "\u{9b}";
665+
input
666+
} else {
667+
input
668+
};
669+
670+
// CSI P ... P I ... I F
671+
//
672+
// where
673+
// P ... P are Parameter Bytes, which, if present, consist of bit combinations from 03/00 (\x30) to 03/15 (\x3f)
674+
// I ... I are Intermediate Bytes, which, if present, consist of bit combinations from 02/00 (\x20) to 02/15 (\x2f)
675+
// F is the Final Byte; it consists of a bit combination from 04/00 (\x40) to 07/14 (\x7e)
676+
//
677+
// NB: the ECMA-43/48 standards use `nibble/nibble`, in decimal, to represent a 7- or 8-bit number.
678+
// For example, `01/02` can be either 7- or 8-bit in their notation, and is equivalent to a more
679+
// familiar hex notation `0x12`. Similarly, `15/15` (which is necessarily 8-bit) is equivalent to `0xff`.
680+
//
681+
// cf. https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf#page=24
682+
// and https://www.ecma-international.org/wp-content/uploads/ECMA-43_3rd_edition_december_1991.pdf#page=14
683+
684+
let params = nom::branch::alt((
685+
nom::bytes::streaming::is_a("0123456789:;<=>?"),
686+
nom::combinator::success(""),
687+
));
688+
let intermediate = nom::branch::alt((
689+
nom::bytes::streaming::is_a(concat!(" ", "!\"#$%&'()*+,/")),
690+
nom::combinator::success(""),
691+
));
692+
let fin = nom::combinator::recognize(nom::character::streaming::satisfy(|ch| {
693+
'\x40' < ch && ch < '\x7e'
694+
}));
695+
696+
let (rest, ((params, intermediate), fin)) =
697+
params.and(intermediate).and(fin).parse(input)?;
615698

616-
let q = match todo!() {
617-
[ESC, '7'] => Op::SaveCursorPos,
618-
[ESC, '8'] => Op::RestoreCursorPos,
699+
q[1] = params;
700+
q[2] = intermediate;
701+
q[3] = fin;
619702

620-
[ESC, '[', params, 'H'] => match params {
621-
[] => Op::MoveCursorAbs { x: 0, y: 0 },
622-
[a, b] => Op::MoveCursorAbs {
623-
x: usize::from(b)?.saturating_sub(1),
624-
y: usize::from(a)?.saturating_sub(1),
703+
Ok((rest, &q[..=3]))
704+
}
705+
706+
// TODO: other kinds of non-digit-y things?
707+
fn sep<'a, 'str, const M: usize>(
708+
input: &'str str,
709+
q: &'a mut [&'str str; M],
710+
) -> Result<&'a [&'str str], nom::Err<nom::error::Error<&'str str>>> {
711+
let (_, i) = nom::combinator::all_consuming(nom::multi::fold_many_m_n(
712+
0,
713+
M,
714+
nom::sequence::terminated(
715+
nom::bytes::complete::take_while1(nom::AsChar::is_dec_digit),
716+
// TODO: this is wrong: it's not optional, unless it's in the last position
717+
nom::combinator::opt(nom::character::complete::char(';')),
718+
),
719+
|| 0,
720+
|i, p| {
721+
q[i] = p;
722+
i + 1
625723
},
626-
_ => {
627-
return Err(alloc::format!(
628-
"Bad number of params got {:?} wanted 0 or 2",
629-
params
630-
))
631-
}
632-
},
633-
};
724+
))
725+
.parse(input)?;
726+
727+
Ok(&q[..i])
728+
}
729+
730+
const ESC: &str = "\u{1b}";
731+
const CSI: &str = "\u{9b}";
634732

635-
let q = match todo!() {
636-
[ESC, '7'] => Op::SaveCursorPos,
637-
[ESC, '8'] => Op::RestoreCursorPos,
638-
639-
[ESC, '[', [], 'H'] => Op::MoveCursorAbs { x: 0, y: 0 },
640-
[ESC, '[', [a, b], 'H'] => Op::MoveCursorAbs {
641-
x: usize::from(b)?.saturating_sub(1),
642-
y: usize::from(a)?.saturating_sub(1),
643-
},
644-
[ESC, '[', params, 'H'] => {
645-
return Err(alloc::format!(
646-
"Bad number of params got {:?} wanted 0 or 2",
647-
params
648-
))
733+
let z = match *gen_parse(input, &mut [""; 4])
734+
.map_err(|e| alloc::format!("{:?}", e))?
735+
.1
736+
{
737+
[ESC, "7"] => Op::SaveCursorPos,
738+
[ESC, "8"] => Op::RestoreCursorPos,
739+
740+
[CSI, params, "", "H"] | [CSI, params, "", "f"] => {
741+
esp_println::println!("{params:?}");
742+
match *sep(params, &mut [""; 2]).map_err(|e| alloc::format!("{:?}", e))? {
743+
[] => Op::MoveCursorAbs { x: 0, y: 0 },
744+
[a, b] => Op::MoveCursorAbs {
745+
x: usize::from_str(b)
746+
.map_err(|e| alloc::format!("{:?}", e))?
747+
.saturating_sub(1),
748+
y: usize::from_str(a)
749+
.map_err(|e| alloc::format!("{:?}", e))?
750+
.saturating_sub(1),
751+
},
752+
_ => {
753+
return Err(alloc::format!(
754+
"Bad number of params got {:?} wanted 0 or 2",
755+
params
756+
))
757+
}
758+
}
649759
}
760+
761+
_ => todo!(),
650762
};
651763

652-
Ok(q)
764+
Ok(z)
653765
}
654766

655767
fn parse3(input: &str) -> OpResult {
@@ -659,8 +771,10 @@ fn parse3(input: &str) -> OpResult {
659771
use nom::combinator::map;
660772

661773
alt((
662-
esc(map(ch('7'), |_| Op::SaveCursorPos)),
663-
esc(map(ch('8'), |_| Op::RestoreCursorPos)),
774+
alt((
775+
esc(map(ch('7'), |_| Op::SaveCursorPos)),
776+
esc(map(ch('8'), |_| Op::RestoreCursorPos)),
777+
)),
664778
esc(nom::sequence::preceded(
665779
ch('['),
666780
map(ch('H'), |_| Op::MoveCursorAbs { x: 0, y: 0 }),
@@ -1052,7 +1166,12 @@ fn parse_all<'a>(input: &'a str) -> OpResult {
10521166
nom::sequence::terminated(
10531167
nom::multi::separated_list0(
10541168
nom::character::streaming::char(';'),
1055-
any_text_mode,
1169+
nom::branch::alt((
1170+
set_basic_color_atom,
1171+
set_bg_256_color_atom,
1172+
set_fg_256_color_atom,
1173+
set_text_mode_atom,
1174+
)),
10561175
),
10571176
nom::character::streaming::char('m'),
10581177
)
@@ -1127,7 +1246,8 @@ fn parse(input: &str) -> OpResult {
11271246
reset_private_sequence,
11281247
)),
11291248
),
1130-
)))(input)
1249+
)))
1250+
.parse(input)
11311251
}
11321252

11331253
pub enum OpChar {

0 commit comments

Comments
 (0)