diff options
author | Maxim Zhiburt <zhiburt@gmail.com> | 2022-09-15 07:54:35 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-15 00:54:35 -0400 |
commit | 1193d54d5c90ab3a45048de3fd1e95c7c2580014 (patch) | |
tree | 8bc101a046c0b8f8b0a4c45a99e9426d62be4b2d /src | |
parent | 4e05ee5ef44361371bc7ef0882c52fabb62e68e7 (diff) |
Refactoring ansi/iterator (#1191)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/ansi/iterator.rs | 128 |
1 files changed, 63 insertions, 65 deletions
diff --git a/src/ansi/iterator.rs b/src/ansi/iterator.rs index f9952162..6318fd51 100644 --- a/src/ansi/iterator.rs +++ b/src/ansi/iterator.rs @@ -24,6 +24,7 @@ pub struct AnsiElementIterator<'a> { pos: usize, } +#[derive(Default)] struct Performer { // Becomes non-None when the parser finishes parsing an ANSI sequence. // This is never Element::Text. @@ -42,6 +43,21 @@ pub enum Element { Text(usize, usize), } +impl Element { + fn set_range(&mut self, start: usize, end: usize) { + let (from, to) = match self { + Element::Sgr(_, from, to) => (from, to), + Element::Csi(from, to) => (from, to), + Element::Esc(from, to) => (from, to), + Element::Osc(from, to) => (from, to), + Element::Text(from, to) => (from, to), + }; + + *from = start; + *to = end; + } +} + impl<'a> AnsiElementIterator<'a> { pub fn new(s: &'a str) -> Self { Self { @@ -54,17 +70,12 @@ impl<'a> AnsiElementIterator<'a> { } } - #[allow(dead_code)] - pub fn dbg(s: &str) { - for el in AnsiElementIterator::new(s) { - match el { - Element::Sgr(_, i, j) => println!("SGR({}, {}, {:?})", i, j, &s[i..j]), - Element::Csi(i, j) => println!("CSI({}, {}, {:?})", i, j, &s[i..j]), - Element::Esc(i, j) => println!("ESC({}, {}, {:?})", i, j, &s[i..j]), - Element::Osc(i, j) => println!("OSC({}, {}, {:?})", i, j, &s[i..j]), - Element::Text(i, j) => println!("Text({}, {}, {:?})", i, j, &s[i..j]), - } - } + fn advance_vte(&mut self, byte: u8) { + let mut performer = Performer::default(); + self.machine.advance(&mut performer, byte); + self.element = performer.element; + self.text_length += performer.text_length; + self.pos += 1; } } @@ -72,53 +83,39 @@ impl<'a> Iterator for AnsiElementIterator<'a> { type Item = Element; fn next(&mut self) -> Option<Element> { - loop { - // If the last element emitted was text, then there may be a non-text element waiting - // to be emitted. In that case we do not consume a new byte. - let byte = if self.element.is_some() { - None - } else { - self.bytes.next() - }; - if byte.is_some() || self.element.is_some() { - if let Some(byte) = byte { - let mut performer = Performer { - element: None, - text_length: 0, - }; - self.machine.advance(&mut performer, byte); - self.element = performer.element; - self.text_length += performer.text_length; - self.pos += 1; - } - if self.element.is_some() { - // There is a non-text element waiting to be emitted, but it may have preceding - // text, which must be emitted first. - if self.text_length > 0 { - let start = self.start; - self.start += self.text_length; - self.text_length = 0; - return Some(Element::Text(start, self.start)); - } - let start = self.start; - self.start = self.pos; - let element = match self.element.as_ref().unwrap() { - Element::Sgr(style, _, _) => Element::Sgr(*style, start, self.pos), - Element::Csi(_, _) => Element::Csi(start, self.pos), - Element::Esc(_, _) => Element::Esc(start, self.pos), - Element::Osc(_, _) => Element::Osc(start, self.pos), - Element::Text(_, _) => unreachable!(), - }; - self.element = None; - return Some(element); - } - } else if self.text_length > 0 { + // If the last element emitted was text, then there may be a non-text element waiting + // to be emitted. In that case we do not consume a new byte. + while self.element.is_none() { + match self.bytes.next() { + Some(b) => self.advance_vte(b), + None => break, + } + } + + if let Some(mut element) = self.element.take() { + // There is a non-text element waiting to be emitted, but it may have preceding + // text, which must be emitted first. + if self.text_length > 0 { + let start = self.start; + self.start += self.text_length; self.text_length = 0; - return Some(Element::Text(self.start, self.pos)); - } else { - return None; + self.element = Some(element); + return Some(Element::Text(start, self.start)); } + + let start = self.start; + self.start = self.pos; + element.set_range(start, self.pos); + + return Some(element); } + + if self.text_length > 0 { + self.text_length = 0; + return Some(Element::Text(self.start, self.pos)); + } + + None } } @@ -129,20 +126,21 @@ impl vte::Perform for Performer { return; } - if let ('m', None) = (c, intermediates.first()) { + let is_sgr = c == 'm' && intermediates.first().is_none(); + let element = if is_sgr { if params.is_empty() { // Attr::Reset // Probably doesn't need to be handled: https://github.com/dandavison/delta/pull/431#discussion_r536883568 + None } else { - self.element = Some(Element::Sgr( - ansi_term_style_from_sgr_parameters(&mut params.iter()), - 0, - 0, - )); + let style = ansi_term_style_from_sgr_parameters(&mut params.iter()); + Some(Element::Sgr(style, 0, 0)) } } else { - self.element = Some(Element::Csi(0, 0)); - } + Some(Element::Csi(0, 0)) + }; + + self.element = element; } fn print(&mut self, c: char) { @@ -311,7 +309,7 @@ mod tests { style, style::Style::from_git_str(git_style_string).ansi_term_style )), - _ => assert!(false), + _ => unreachable!(), } // Second element should be text: "+" @@ -331,7 +329,7 @@ mod tests { style, style::Style::from_git_str(git_style_string).ansi_term_style )), - _ => assert!(false), + _ => unreachable!(), } // Fifth element should be text: "text" |