Skip to content

Commit f9edb16

Browse files
committed
Don't depend on ansi parser types in the core
1 parent 0fb9d66 commit f9edb16

File tree

3 files changed

+65
-56
lines changed

3 files changed

+65
-56
lines changed

src/parser/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
//! tokens
1717
//! );
1818
//! ```
19-
use ansi_parser::AnsiSequence;
2019
use core::{marker::PhantomData, str::Chars};
2120
use embedded_graphics::{prelude::PixelColor, text::DecorationColor};
2221

@@ -69,8 +68,13 @@ where
6968
/// Change of text style.
7069
ChangeTextStyle(ChangeTextStyle<C>),
7170

72-
/// An ANSI escape sequence
73-
EscapeSequence(AnsiSequence),
71+
/// Move the cursor by a number of characters.
72+
MoveCursor {
73+
/// Number of characters to move.
74+
chars: i32,
75+
/// True to draw over the area of movement with the background color.
76+
draw_background: bool,
77+
},
7478
}
7579

7680
/// Text parser. Turns a string into a stream of [`Token`] objects.

src/plugin/ansi/mod.rs

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
//! Ansi sequence support plugin
22
3-
use embedded_graphics::prelude::PixelColor;
3+
use ansi_parser::AnsiSequence;
4+
use embedded_graphics::{pixelcolor::Rgb888, prelude::PixelColor};
45

5-
use crate::{plugin::Plugin, Token};
6+
use crate::{
7+
plugin::{ansi::utils::try_parse_sgr, Plugin},
8+
Token,
9+
};
610

711
pub mod utils;
812

@@ -20,7 +24,7 @@ impl<C: PixelColor> Ansi<'_, C> {
2024
}
2125
}
2226

23-
impl<'a, C: PixelColor> Plugin<'a, C> for Ansi<'a, C> {
27+
impl<'a, C: PixelColor + From<Rgb888>> Plugin<'a, C> for Ansi<'a, C> {
2428
fn next_token(
2529
&mut self,
2630
mut next_token: impl FnMut() -> Option<crate::Token<'a, C>>,
@@ -38,7 +42,23 @@ impl<'a, C: PixelColor> Plugin<'a, C> for Ansi<'a, C> {
3842
Some((0, _)) => match ansi_parser::parse_escape(text) {
3943
Ok((string, output)) => {
4044
self.carry = Some(Token::Word(string));
41-
Some(Token::EscapeSequence(output))
45+
let new_token = match output {
46+
AnsiSequence::CursorForward(chars) => Token::MoveCursor {
47+
chars: chars as i32,
48+
draw_background: true,
49+
},
50+
AnsiSequence::CursorBackward(chars) => Token::MoveCursor {
51+
chars: -(chars as i32),
52+
draw_background: true,
53+
},
54+
AnsiSequence::SetGraphicsMode(sgr) => try_parse_sgr(&sgr)
55+
.map(|sgr| Token::ChangeTextStyle(sgr.into()))
56+
.or_else(|| self.next_token(next_token))?,
57+
58+
_ => self.next_token(next_token)?,
59+
};
60+
61+
Some(new_token)
4262
}
4363
Err(_) => {
4464
self.carry = Some(Token::Word(chars.as_str()));

src/rendering/line_iter.rs

+34-49
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ use crate::{
1212
use az::{SaturatingAs, SaturatingCast};
1313
use embedded_graphics::{pixelcolor::Rgb888, prelude::PixelColor};
1414

15-
use crate::plugin::ansi::utils::try_parse_sgr;
16-
use ansi_parser::AnsiSequence;
17-
use as_slice::AsSlice;
18-
1915
/// Parser to break down a line into primitive elements used by measurement and rendering.
2016
#[derive(Debug)]
2117
#[must_use]
@@ -120,7 +116,7 @@ where
120116
break 'lookahead;
121117
}
122118

123-
Some(Token::EscapeSequence(_)) => {}
119+
Some(Token::ChangeTextStyle(_)) | Some(Token::MoveCursor { .. }) => {}
124120

125121
_ => break 'lookahead,
126122
}
@@ -184,15 +180,11 @@ where
184180
Some(Token::Whitespace(n, _)) => spaces.consume(n).saturating_as(),
185181
Some(Token::Tab) => cursor.next_tab_width().saturating_as(),
186182

187-
Some(Token::EscapeSequence(AnsiSequence::CursorForward(by))) => {
188-
(by * handler.measure(" ")).saturating_as()
189-
}
190-
191-
Some(Token::EscapeSequence(AnsiSequence::CursorBackward(by))) => {
192-
-(by * handler.measure(" ")).saturating_as::<i32>()
183+
Some(Token::MoveCursor { chars, .. }) => {
184+
chars * handler.measure(" ").saturating_as::<i32>()
193185
}
194186

195-
Some(Token::EscapeSequence(_)) => 0,
187+
Some(Token::ChangeTextStyle(_)) => 0,
196188

197189
_ => return false,
198190
};
@@ -374,46 +366,39 @@ where
374366
}
375367
}
376368

377-
Token::EscapeSequence(seq) => {
378-
match seq {
379-
AnsiSequence::SetGraphicsMode(vec) => {
380-
if let Some(sgr) = try_parse_sgr(vec.as_slice()) {
381-
handler.change_text_style(sgr.into())?;
382-
}
383-
}
384-
385-
AnsiSequence::CursorForward(n) => {
386-
// Cursor movement can't rely on the text, as it's permitted
387-
// to move the cursor outside of the current line.
388-
// Example:
389-
// (| denotes the cursor, [ and ] are the limits of the line):
390-
// [Some text| ]
391-
// Cursor forward 2 characters
392-
// [Some text | ]
393-
let delta = (n * handler.measure(" ")).saturating_as();
394-
match self.move_cursor(delta) {
395-
Ok(delta) | Err(delta) => {
396-
handler.whitespace("", 1, delta.saturating_as())?;
397-
}
398-
}
399-
}
400-
401-
AnsiSequence::CursorBackward(n) => {
402-
// The above poses an issue with variable-width fonts.
403-
// If cursor movement ignores the variable width, the cursor
404-
// will be placed in positions other than glyph boundaries.
405-
let delta = -(n * handler.measure(" ")).saturating_as::<i32>();
406-
match self.move_cursor(delta) {
407-
Ok(delta) | Err(delta) => {
408-
handler.move_cursor(delta)?;
409-
handler.whitespace("", 1, delta.abs().saturating_as())?;
410-
handler.move_cursor(delta)?;
411-
}
369+
// Cursor movement can't rely on the text, as it's permitted
370+
// to move the cursor outside of the current line.
371+
// Example:
372+
// (| denotes the cursor, [ and ] are the limits of the line):
373+
// [Some text| ]
374+
// Cursor forward 2 characters
375+
// [Some text | ]
376+
Token::MoveCursor {
377+
chars,
378+
draw_background: true,
379+
} => {
380+
let delta = chars * handler.measure(" ").saturating_as::<i32>();
381+
match self.move_cursor(delta) {
382+
Ok(delta) | Err(delta) => {
383+
if chars > 0 {
384+
handler.whitespace("", 1, delta.saturating_as())?;
385+
} else {
386+
handler.move_cursor(delta)?;
387+
handler.whitespace("", 1, delta.abs().saturating_as())?;
388+
handler.move_cursor(delta)?;
412389
}
413390
}
391+
}
392+
}
414393

415-
_ => {
416-
// ignore for now
394+
Token::MoveCursor {
395+
chars,
396+
draw_background: false,
397+
} => {
398+
let delta = chars * handler.measure(" ").saturating_as::<i32>();
399+
match self.move_cursor(delta) {
400+
Ok(delta) | Err(delta) => {
401+
handler.move_cursor(delta)?;
417402
}
418403
}
419404
}

0 commit comments

Comments
 (0)