diff --git a/src/terminal/cells.rs b/src/terminal/cells.rs index 98a3e51f..1d7ef503 100644 --- a/src/terminal/cells.rs +++ b/src/terminal/cells.rs @@ -1229,380 +1229,6 @@ pub fn clear_area(grid: &mut CellBuffer, area: Area, attributes: crate::conf::Th } } -pub mod ansi { - //! Create a `CellBuffer` from a string slice containing ANSI escape codes. - use super::{Attr, Cell, CellBuffer, Color}; - /// Create a `CellBuffer` from a string slice containing ANSI escape codes. - pub fn ansi_to_cellbuffer(s: &str) -> Option { - let mut bufs: Vec> = Vec::with_capacity(2048); - let mut row: Vec = Vec::with_capacity(2048); - - enum State { - Start, - Csi, - SetFg, - SetBg, - } - use State::*; - - let mut rows = 0; - let mut max_cols = 0; - let mut current_fg = Color::Default; - let mut current_bg = Color::Default; - let mut current_attrs = Attr::DEFAULT; - let mut cur_cell; - let mut state: State; - for l in s.lines() { - cur_cell = Cell::default(); - state = State::Start; - let mut chars = l.chars().peekable(); - if rows > 0 { - max_cols = std::cmp::max(row.len(), max_cols); - bufs.push(row); - row = Vec::with_capacity(2048); - } - rows += 1; - 'line_loop: loop { - let c = chars.next(); - if c.is_none() { - break 'line_loop; - } - match (&state, c.unwrap()) { - (Start, '\x1b') => { - if chars.next() != Some('[') { - return None; - } - state = Csi; - } - (Start, c) => { - cur_cell.set_ch(c); - cur_cell.set_fg(current_fg); - cur_cell.set_bg(current_bg); - cur_cell.set_attrs(current_attrs); - row.push(cur_cell); - cur_cell = Cell::default(); - } - (Csi, 'm') => { - /* Reset styles */ - current_fg = Color::Default; - current_bg = Color::Default; - current_attrs = Attr::DEFAULT; - state = Start; - } - (Csi, '0') if chars.peek() == Some(&'0') => { - current_attrs = Attr::DEFAULT; - chars.next(); - let next = chars.next(); - if next == Some('m') { - state = Start; - } else if next != Some(';') { - return None; - } - } - (Csi, c @ '0'..='8') if chars.peek() == Some(&'m') => { - chars.next(); - state = Start; - match c { - '0' => { - //Reset all attributes - current_fg = Color::Default; - current_bg = Color::Default; - current_attrs = Attr::DEFAULT; - } - '1' => { - current_attrs.set(Attr::BOLD, true); - } - '2' => { - current_attrs.set(Attr::DIM, true); - } - '3' => { - current_attrs.set(Attr::ITALICS, true); - } - '4' => { - current_attrs.set(Attr::UNDERLINE, true); - } - '5' => { - current_attrs.set(Attr::BLINK, true); - } - '7' => { - current_attrs.set(Attr::REVERSE, true); - } - '8' => { - current_attrs.set(Attr::HIDDEN, true); - } - _ => return None, - } - } - (Csi, '0') => { - continue; - } - (Csi, '2') => { - match (chars.next(), chars.next()) { - (Some('2'), Some('m')) => { - current_attrs.set(Attr::BOLD, false); - current_attrs.set(Attr::DIM, false); - } - (Some('3'), Some('m')) => { - current_attrs.set(Attr::ITALICS, false); - } - (Some('4'), Some('m')) => { - current_attrs.set(Attr::UNDERLINE, false); - } - (Some('5'), Some('m')) => { - current_attrs.set(Attr::BLINK, false); - } - (Some('7'), Some('m')) => { - current_attrs.set(Attr::REVERSE, false); - } - (Some('8'), Some('m')) => { - current_attrs.set(Attr::HIDDEN, false); - } - (Some('9'), Some('m')) => { /* Not crossed out */ } - _ => return None, - } - } - (Csi, '3') => { - match chars.next() { - Some('8') => { - /* Set foreground color */ - if chars.next() == Some(';') { - state = SetFg; - /* Next arguments are 5;n or 2;r;g;b */ - continue; - } - chars.next(); - return None; - } - Some('9') => { - current_fg = Color::Default; - /* default foreground color */ - let next = chars.next(); - if next == Some('m') { - state = Start; - } else if next != Some(';') { - return None; - } - continue; - } - Some(c) if c >= '0' && c < '8' => { - current_fg = Color::from_byte(c as u8 - 0x30); - if chars.next() != Some('m') { - return None; - } - state = Start; - } - _ => return None, - } - } - (Csi, '4') => { - match chars.next() { - Some('8') => { - /* Set background color */ - if chars.next() == Some(';') { - state = SetBg; - /* Next arguments are 5;n or 2;r;g;b */ - continue; - } - return None; - } - Some('9') => { - /* default background color */ - current_bg = Color::Default; - let next = chars.next(); - if next == Some('m') { - state = Start; - } else if next != Some(';') { - return None; - } - continue; - } - Some(c) if c >= '0' && c < '8' => { - current_bg = Color::from_byte(c as u8 - 0x30); - if chars.next() != Some('m') { - return None; - } - state = Start; - } - _ => return None, - } - } - (Csi, '9') => { - match chars.next() { - Some('0') => current_fg = Color::Black, - Some('1') => current_fg = Color::Red, - Some('2') => current_fg = Color::Green, - Some('3') => current_fg = Color::Yellow, - Some('4') => current_fg = Color::Blue, - Some('5') => current_fg = Color::Magenta, - Some('6') => current_fg = Color::Cyan, - Some('7') => current_fg = Color::White, - _ => {} - } - let next = chars.next(); - if next != Some('m') { - //debug!(next); - } - state = Start; - } - (Csi, '1') if chars.peek() == Some(&'0') => { - chars.next(); - match chars.next() { - Some('0') => current_bg = Color::Black, - Some('1') => current_bg = Color::Red, - Some('2') => current_bg = Color::Green, - Some('3') => current_bg = Color::Yellow, - Some('4') => current_bg = Color::Blue, - Some('5') => current_bg = Color::Magenta, - Some('6') => current_bg = Color::Cyan, - Some('7') => current_bg = Color::White, - _ => {} - } - let next = chars.next(); - if next != Some('m') { - //debug!(next); - } - - state = Start; - } - (SetFg, '5') => { - if chars.next() != Some(';') { - return None; - } - let mut accum = 0; - while chars.peek().is_some() && chars.peek() != Some(&'m') { - let c = chars.next().unwrap(); - accum *= 10; - accum += c as u8 - 0x30; - } - if chars.next() != Some('m') { - return None; - } - current_fg = Color::from_byte(accum); - state = Start; - } - (SetFg, '2') => { - if chars.next() != Some(';') { - return None; - } - let mut rgb_color = Color::Rgb(0, 0, 0); - if let Color::Rgb(ref mut r, ref mut g, ref mut b) = rgb_color { - 'rgb_fg: for val in &mut [r, g, b] { - let mut accum = 0; - while chars.peek().is_some() - && chars.peek() != Some(&';') - && chars.peek() != Some(&'m') - { - let c = chars.next().unwrap(); - accum *= 10; - accum += c as u8 - 0x30; - } - **val = accum; - match chars.peek() { - Some(&'m') => { - break 'rgb_fg; - } - Some(&';') => { - chars.next(); - } - _ => return None, - } - } - } - if chars.next() != Some('m') { - return None; - } - current_fg = rgb_color; - state = Start; - } - (SetBg, '5') => { - if chars.next() != Some(';') { - return None; - } - let mut accum = 0; - while chars.peek().is_some() && chars.peek() != Some(&'m') { - let c = chars.next().unwrap(); - accum *= 10; - accum += c as u8 - 0x30; - } - if chars.next() != Some('m') { - return None; - } - current_bg = Color::from_byte(accum); - state = Start; - } - (SetBg, '2') => { - if chars.next() != Some(';') { - return None; - } - let mut rgb_color = Color::Rgb(0, 0, 0); - if let Color::Rgb(ref mut r, ref mut g, ref mut b) = rgb_color { - 'rgb_bg: for val in &mut [r, g, b] { - let mut accum = 0; - while chars.peek().is_some() - && chars.peek() != Some(&';') - && chars.peek() != Some(&'m') - { - let c = chars.next().unwrap(); - accum *= 10; - accum += c as u8 - 0x30; - } - **val = accum; - match chars.peek() { - Some(&'m') => { - break 'rgb_bg; - } - Some(&';') => { - chars.next(); - } - _ => return None, - } - } - } - if chars.next() != Some('m') { - return None; - } - current_bg = rgb_color; - state = Start; - } - _ => unreachable!(), - } - } - } - max_cols = std::cmp::max(row.len(), max_cols); - bufs.push(row); - let mut buf: Vec = Vec::with_capacity(max_cols * bufs.len()); - for l in bufs { - let row_len = l.len(); - buf.extend(l.into_iter()); - if row_len < max_cols { - for _ in row_len..max_cols { - buf.push(Cell::default()); - } - } - } - - if buf.len() != rows * max_cols { - debug!( - "BUG: rows: {} cols: {} = {}, but buf.len() = {}", - rows, - max_cols, - rows * max_cols, - buf.len() - ); - } - Some(CellBuffer { - buf, - rows, - cols: max_cols, - default_cell: Cell::default(), - growable: false, - ascii_drawing: false, - tag_table: Default::default(), - tag_associations: smallvec::SmallVec::new(), - }) - } -} - /// Use `RowIterator` to iterate the cells of a row without the need to do any bounds checking; /// the iterator will simply return `None` when it reaches the end of the row. /// `RowIterator` can be created via the `CellBuffer::row_iter` method and can be returned by