Skip to content

Commit 756e410

Browse files
committed
ansi: refactor OSC/DCS parsing, unify core loop
1 parent 3d4526a commit 756e410

1 file changed

Lines changed: 74 additions & 36 deletions

File tree

src/ansi.rs

Lines changed: 74 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,61 +6,89 @@ use core::{
66
str::CharIndices,
77
};
88

9-
fn consume_osc_end_exclusive(it: &mut Peekable<CharIndices<'_>>, start: usize) -> usize {
10-
let mut end = start + 1;
11-
let Some((idx, ']')) = it.next() else {
12-
return end;
13-
};
14-
end = idx + 1;
9+
enum EscStep {
10+
Continue,
11+
End,
12+
ConsumeNext,
13+
}
1514

16-
while let Some((idx, c)) = it.next() {
17-
end = idx + c.len_utf8();
18-
match c {
19-
'\u{07}' | '\u{9c}' => return end,
20-
'\u{1b}' => {
21-
if let Some((next_idx, '\\')) = it.peek() {
22-
end = *next_idx + 1;
23-
it.next();
24-
return end;
25-
}
26-
}
27-
_ => {}
15+
trait EscSequence {
16+
const START_CHAR: char;
17+
fn on_char(c: char) -> EscStep;
18+
fn on_escape(next: Option<char>) -> EscStep;
19+
}
20+
21+
#[derive(Clone, Copy, Debug)]
22+
struct OscSequence;
23+
24+
impl EscSequence for OscSequence {
25+
const START_CHAR: char = ']';
26+
27+
fn on_char(c: char) -> EscStep {
28+
if c == '\u{07}' {
29+
EscStep::End
30+
} else {
31+
EscStep::Continue
2832
}
2933
}
3034

31-
end
35+
fn on_escape(next: Option<char>) -> EscStep {
36+
if matches!(next, Some('\\')) {
37+
EscStep::End
38+
} else {
39+
EscStep::Continue
40+
}
41+
}
42+
}
43+
44+
#[derive(Clone, Copy, Debug)]
45+
struct DcsSequence;
46+
47+
impl EscSequence for DcsSequence {
48+
const START_CHAR: char = 'P';
49+
50+
fn on_char(_c: char) -> EscStep {
51+
EscStep::Continue
52+
}
53+
54+
fn on_escape(next: Option<char>) -> EscStep {
55+
match next {
56+
Some('\\') | None => EscStep::End,
57+
Some('\u{1b}') => EscStep::ConsumeNext,
58+
_ => EscStep::Continue,
59+
}
60+
}
3261
}
3362

34-
fn consume_dcs_end_exclusive(it: &mut Peekable<CharIndices<'_>>, start: usize) -> usize {
63+
fn consume_exclusive<S: EscSequence>(it: &mut Peekable<CharIndices<'_>>, start: usize) -> usize {
3564
let mut end = start + 1;
36-
let Some((idx, 'P')) = it.next() else {
65+
let Some((idx, start_char)) = it.next() else {
3766
return end;
3867
};
68+
if start_char != S::START_CHAR {
69+
return end;
70+
}
3971
end = idx + 1;
4072

4173
while let Some((idx, c)) = it.next() {
4274
end = idx + c.len_utf8();
4375
match c {
4476
'\u{9c}' => return end,
45-
'\u{1b}' => {
46-
let Some((next_idx, next)) = it.peek() else {
47-
return end;
48-
};
49-
match next {
50-
'\u{1b}' => {
51-
end = *next_idx + 1;
52-
it.next();
53-
}
54-
'\\' => {
77+
'\u{1b}' => match S::on_escape(it.peek().map(|(_, next)| *next)) {
78+
EscStep::End => return end,
79+
EscStep::ConsumeNext => {
80+
if let Some((next_idx, _)) = it.peek() {
5581
end = *next_idx + 1;
5682
it.next();
57-
return end;
5883
}
59-
_ => {}
6084
}
61-
}
85+
EscStep::Continue => {}
86+
},
6287
_ => {}
6388
}
89+
if matches!(S::on_char(c), EscStep::End) {
90+
return end;
91+
}
6492
}
6593

6694
end
@@ -231,8 +259,18 @@ fn find_ansi_code_exclusive(it: &mut Peekable<CharIndices>) -> Option<(usize, us
231259
'\u{1b}' => {
232260
it.next();
233261
match it.peek() {
234-
Some((_, ']')) => return Some((start, consume_osc_end_exclusive(it, start))),
235-
Some((_, 'P')) => return Some((start, consume_dcs_end_exclusive(it, start))),
262+
Some((_, ']')) => {
263+
return Some((
264+
start,
265+
consume_exclusive::<OscSequence>(it, start),
266+
))
267+
}
268+
Some((_, 'P')) => {
269+
return Some((
270+
start,
271+
consume_exclusive::<DcsSequence>(it, start),
272+
))
273+
}
236274
_ => {
237275
if let Some(end) = find_dfa_end_exclusive_after_entry(it) {
238276
return Some((start, end));

0 commit comments

Comments
 (0)