Skip to content

Commit 07d3b28

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

1 file changed

Lines changed: 90 additions & 33 deletions

File tree

src/ansi.rs

Lines changed: 90 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,61 +6,114 @@ 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+
struct EscAction {
10+
consume_next: bool,
11+
end: bool,
12+
}
1513

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-
}
14+
trait EscSequence {
15+
const START_CHAR: char;
16+
fn on_char(c: char) -> EscAction;
17+
fn on_escape(next: Option<char>) -> EscAction;
18+
}
19+
20+
#[derive(Clone, Copy, Debug)]
21+
struct OscSequence;
22+
23+
impl EscSequence for OscSequence {
24+
const START_CHAR: char = ']';
25+
26+
fn on_char(c: char) -> EscAction {
27+
EscAction {
28+
consume_next: false,
29+
end: c == '\u{07}',
30+
}
31+
}
32+
33+
fn on_escape(next: Option<char>) -> EscAction {
34+
if matches!(next, Some('\\')) {
35+
EscAction {
36+
consume_next: true,
37+
end: true,
38+
}
39+
} else {
40+
EscAction {
41+
consume_next: false,
42+
end: false,
2643
}
27-
_ => {}
2844
}
2945
}
46+
}
3047

31-
end
48+
#[derive(Clone, Copy, Debug)]
49+
struct DcsSequence;
50+
51+
impl EscSequence for DcsSequence {
52+
const START_CHAR: char = 'P';
53+
54+
fn on_char(_c: char) -> EscAction {
55+
EscAction {
56+
consume_next: false,
57+
end: false,
58+
}
59+
}
60+
61+
fn on_escape(next: Option<char>) -> EscAction {
62+
match next {
63+
Some('\\') => EscAction {
64+
consume_next: true,
65+
end: true,
66+
},
67+
None => EscAction {
68+
consume_next: false,
69+
end: true,
70+
},
71+
Some('\u{1b}') => EscAction {
72+
consume_next: true,
73+
end: false,
74+
},
75+
_ => EscAction {
76+
consume_next: false,
77+
end: false,
78+
},
79+
}
80+
}
3281
}
3382

34-
fn consume_dcs_end_exclusive(it: &mut Peekable<CharIndices<'_>>, start: usize) -> usize {
83+
fn consume_end_exclusive<S: EscSequence>(
84+
it: &mut Peekable<CharIndices<'_>>,
85+
start: usize,
86+
) -> usize {
3587
let mut end = start + 1;
36-
let Some((idx, 'P')) = it.next() else {
88+
let Some((idx, start_char)) = it.next() else {
3789
return end;
3890
};
91+
if start_char != S::START_CHAR {
92+
return end;
93+
}
3994
end = idx + 1;
4095

4196
while let Some((idx, c)) = it.next() {
4297
end = idx + c.len_utf8();
4398
match c {
4499
'\u{9c}' => return end,
45100
'\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-
'\\' => {
101+
let action = S::on_escape(it.peek().map(|(_, next)| *next));
102+
if action.consume_next {
103+
if let Some((next_idx, _)) = it.peek() {
55104
end = *next_idx + 1;
56105
it.next();
57-
return end;
58106
}
59-
_ => {}
107+
}
108+
if action.end {
109+
return end;
60110
}
61111
}
62112
_ => {}
63113
}
114+
if S::on_char(c).end {
115+
return end;
116+
}
64117
}
65118

66119
end
@@ -231,8 +284,12 @@ fn find_ansi_code_exclusive(it: &mut Peekable<CharIndices>) -> Option<(usize, us
231284
'\u{1b}' => {
232285
it.next();
233286
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))),
287+
Some((_, OscSequence::START_CHAR)) => {
288+
return Some((start, consume_end_exclusive::<OscSequence>(it, start)))
289+
}
290+
Some((_, DcsSequence::START_CHAR)) => {
291+
return Some((start, consume_end_exclusive::<DcsSequence>(it, start)))
292+
}
236293
_ => {
237294
if let Some(end) = find_dfa_end_exclusive_after_entry(it) {
238295
return Some((start, end));

0 commit comments

Comments
 (0)