diff --git a/src/terminal/cells.rs b/src/terminal/cells.rs index ccdbca4fe..82814d2bb 100644 --- a/src/terminal/cells.rs +++ b/src/terminal/cells.rs @@ -29,6 +29,8 @@ use crate::state::Context; use melib::text_processing::wcwidth; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use smallvec::SmallVec; +use std::collections::{HashMap, HashSet}; use std::convert::From; use std::fmt; use std::ops::{Deref, DerefMut, Index, IndexMut}; @@ -63,6 +65,8 @@ pub struct CellBuffer { pub ascii_drawing: bool, /// If printing to this buffer and we run out of space, expand it. growable: bool, + tag_table: HashMap, + tag_associations: SmallVec<[(u64, (usize, usize)); 128]>, } impl fmt::Debug for CellBuffer { @@ -97,6 +101,8 @@ impl CellBuffer { buf: vec![cell; cols * rows], growable: false, ascii_drawing: false, + tag_table: Default::default(), + tag_associations: SmallVec::new(), } } @@ -107,6 +113,8 @@ impl CellBuffer { buf: vec![cell; cols * rows], growable: false, ascii_drawing: context.settings.terminal.ascii_drawing, + tag_table: Default::default(), + tag_associations: SmallVec::new(), } } @@ -371,6 +379,50 @@ impl CellBuffer { RowIterator { row, col: 0..0 } } } + + pub fn tag_associations(&self) -> SmallVec<[(usize, u64, bool); 128]> { + let mut ret: SmallVec<[(usize, u64, bool); 128]> = self.tag_associations.iter().fold( + SmallVec::new(), + |mut acc, (tag_hash, (start, end))| { + acc.push((*start, *tag_hash, true)); + acc.push((*end, *tag_hash, false)); + acc + }, + ); + ret.sort_by_key(|el| el.0); + ret + } + + pub fn tag_table(&self) -> &HashMap { + &self.tag_table + } + + pub fn tag_table_mut(&mut self) -> &mut HashMap { + &mut self.tag_table + } + + pub fn insert_tag(&mut self, tag: FormatTag) -> u64 { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + let mut hasher = DefaultHasher::new(); + tag.hash(&mut hasher); + let hash = hasher.finish(); + self.tag_table.insert(hash, tag); + hash + } + + pub fn set_tag(&mut self, tag: u64, start: (usize, usize), end: (usize, usize)) { + let start = self + .pos_to_index(start.0, start.1) + .unwrap_or(self.buf.len().saturating_sub(1)); + let end = self + .pos_to_index(end.0, end.1) + .unwrap_or(self.buf.len().saturating_sub(1)); + if start != end { + self.tag_associations.push((tag, (start, end))); + } + } } impl Deref for CellBuffer { @@ -662,7 +714,7 @@ impl Default for Cell { /// // Basic colors are also 8-bit colors (but not vice-versa). /// assert_eq!(red.as_byte(), fancy.as_byte()) /// ``` -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq)] pub enum Color { Black, Red, @@ -1647,9 +1699,27 @@ pub fn copy_area(grid_dest: &mut CellBuffer, grid_src: &CellBuffer, dest: Area, return upper_left!(dest); } + let tag_associations = grid_src.tag_associations(); + let start_idx = grid_src.pos_to_index(src_x, src_y).unwrap(); + let mut tag_offset: usize = tag_associations + .binary_search_by(|probe| probe.0.cmp(&start_idx)) + .unwrap_or_else(|i| i); + let mut stack: HashSet = HashSet::default(); for y in get_y(upper_left!(dest))..=get_y(bottom_right!(dest)) { 'for_x: for x in get_x(upper_left!(dest))..=get_x(bottom_right!(dest)) { + let idx = grid_src.pos_to_index(src_x, src_y).unwrap(); + while tag_offset < tag_associations.len() && tag_associations[tag_offset].0 <= idx { + if tag_associations[tag_offset].2 { + stack.insert(tag_associations[tag_offset].1); + } else { + stack.remove(&tag_associations[tag_offset].1); + } + tag_offset += 1; + } grid_dest[(x, y)] = grid_src[(src_x, src_y)]; + for t in &stack { + grid_dest[(x, y)].attrs |= grid_src.tag_table()[&t].attrs; + } if src_x >= get_x(bottom_right!(src)) { break 'for_x; } @@ -2204,6 +2274,8 @@ pub mod ansi { cols: max_cols, growable: false, ascii_drawing: false, + tag_table: Default::default(), + tag_associations: smallvec::SmallVec::new(), }) } } @@ -2717,3 +2789,11 @@ fn test_cellbuffer_search() { println!(""); } } + +#[derive(Debug, Default, Copy, Hash, Clone, PartialEq, Eq)] +pub struct FormatTag { + pub fg: Color, + pub bg: Color, + pub attrs: Attr, + pub priority: u8, +}