From 85bd76e17d1aed323ca7af5a829a56802dfaa63e Mon Sep 17 00:00:00 2001 From: Florian Dehau Date: Wed, 26 Oct 2016 19:19:46 +0200 Subject: [PATCH] Small improvements --- examples/prototype.rs | 2 +- src/buffer.rs | 22 ++++++------ src/style.rs | 80 ++++++++++++++++++++++++----------------- src/terminal.rs | 82 +++++++++++++++++++++++++++---------------- 4 files changed, 111 insertions(+), 75 deletions(-) diff --git a/examples/prototype.rs b/examples/prototype.rs index 9e6f23f..c4065d7 100644 --- a/examples/prototype.rs +++ b/examples/prototype.rs @@ -168,7 +168,7 @@ fn main() { let tx = tx.clone(); loop { tx.send(Event::Tick).unwrap(); - thread::sleep(time::Duration::from_millis(100)); + thread::sleep(time::Duration::from_millis(1000)); } }); diff --git a/src/buffer.rs b/src/buffer.rs index b097dbf..0426abd 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -8,14 +8,15 @@ use style::Color; #[derive(Debug, Clone, PartialEq)] pub struct Cell { - pub symbol: String, pub fg: Color, pub bg: Color, + pub symbol: String, } impl Cell { pub fn reset(&mut self) { - self.symbol = " ".into(); + self.symbol.clear(); + self.symbol.push(' '); self.fg = Color::Reset; self.bg = Color::Reset; } @@ -93,11 +94,10 @@ impl Buffer { self.content[i] = cell; } - pub fn set_symbol(&mut self, x: u16, y: u16, symbol: S) - where S: Into - { + pub fn set_symbol(&mut self, x: u16, y: u16, symbol: &str) { let i = self.index_of(x, y); - self.content[i].symbol = symbol.into(); + self.content[i].symbol.clear(); + self.content[i].symbol.push_str(symbol); } pub fn set_fg(&mut self, x: u16, y: u16, color: Color) { @@ -124,7 +124,8 @@ impl Buffer { let graphemes = UnicodeSegmentation::graphemes(string, true).collect::>(); let max_index = min((self.area.width - x) as usize, limit); for s in graphemes.into_iter().take(max_index) { - self.content[index].symbol = s.into(); + self.content[index].symbol.clear(); + self.content[index].symbol.push_str(s); self.content[index].fg = fg; self.content[index].bg = bg; index += 1; @@ -138,11 +139,10 @@ impl Buffer { self.content[i].bg = bg; } - pub fn update_cell(&mut self, x: u16, y: u16, symbol: S, fg: Color, bg: Color) - where S: Into - { + pub fn update_cell(&mut self, x: u16, y: u16, symbol: &str, fg: Color, bg: Color) { let i = self.index_of(x, y); - self.content[i].symbol = symbol.into(); + self.content[i].symbol.clear(); + self.content[i].symbol.push_str(symbol); self.content[i].fg = fg; self.content[i].bg = bg; } diff --git a/src/style.rs b/src/style.rs index db502ae..3efe778 100644 --- a/src/style.rs +++ b/src/style.rs @@ -20,45 +20,61 @@ pub enum Color { Rgb(u8, u8, u8), } +macro_rules! termion_fg { + ($color:ident) => (format!("{}", termion::color::Fg(termion::color::$color))); +} + +macro_rules! termion_fg_rgb { + ($r:expr, $g:expr, $b:expr) => (format!("{}", termion::color::Fg(termion::color::Rgb($r, $g, $b)))); +} + +macro_rules! termion_bg { + ($color:ident) => (format!("{}", termion::color::Bg(termion::color::$color))); +} + +macro_rules! termion_bg_rgb { + ($r:expr, $g:expr, $b:expr) => (format!("{}", termion::color::Bg(termion::color::Rgb($r, $g, $b)))); +} + impl Color { pub fn fg(&self) -> String { match *self { - Color::Reset => format!("{}", termion::color::Fg(termion::color::Reset)), - Color::Black => format!("{}", termion::color::Fg(termion::color::Black)), - Color::Red => format!("{}", termion::color::Fg(termion::color::Red)), - Color::Green => format!("{}", termion::color::Fg(termion::color::Green)), - Color::Yellow => format!("{}", termion::color::Fg(termion::color::Yellow)), - Color::Magenta => format!("{}", termion::color::Fg(termion::color::Magenta)), - Color::Cyan => format!("{}", termion::color::Fg(termion::color::Cyan)), - Color::Gray => format!("{}", termion::color::Fg(termion::color::Rgb(146, 131, 116))), - Color::DarkGray => format!("{}", termion::color::Fg(termion::color::Rgb(80, 73, 69))), - Color::LightRed => format!("{}", termion::color::Fg(termion::color::LightRed)), - Color::LightGreen => format!("{}", termion::color::Fg(termion::color::LightGreen)), - Color::LightYellow => format!("{}", termion::color::Fg(termion::color::LightYellow)), - Color::LightMagenta => format!("{}", termion::color::Fg(termion::color::LightMagenta)), - Color::LightCyan => format!("{}", termion::color::Fg(termion::color::LightCyan)), - Color::White => format!("{}", termion::color::Fg(termion::color::White)), - Color::Rgb(r, g, b) => format!("{}", termion::color::Fg(termion::color::Rgb(r, g, b))), + Color::Reset => termion_fg!(Reset), + Color::Black => termion_fg!(Black), + Color::Red => termion_fg!(Red), + Color::Green => termion_fg!(Green), + Color::Yellow => termion_fg!(Yellow), + Color::Magenta => termion_fg!(Magenta), + Color::Cyan => termion_fg!(Cyan), + Color::Gray => termion_fg_rgb!(146, 131, 116), + Color::DarkGray => termion_fg_rgb!(80, 73, 69), + Color::LightRed => termion_fg!(LightRed), + Color::LightGreen => termion_fg!(LightGreen), + Color::LightYellow => termion_fg!(LightYellow), + Color::LightMagenta => termion_fg!(LightMagenta), + Color::LightCyan => termion_fg!(LightCyan), + Color::White => termion_fg!(White), + Color::Rgb(r, g, b) => termion_fg_rgb!(r, g, b), } } pub fn bg(&self) -> String { match *self { - Color::Reset => format!("{}", termion::color::Bg(termion::color::Reset)), - Color::Black => format!("{}", termion::color::Bg(termion::color::Black)), - Color::Red => format!("{}", termion::color::Bg(termion::color::Red)), - Color::Green => format!("{}", termion::color::Bg(termion::color::Green)), - Color::Yellow => format!("{}", termion::color::Bg(termion::color::Yellow)), - Color::Magenta => format!("{}", termion::color::Bg(termion::color::Magenta)), - Color::Cyan => format!("{}", termion::color::Bg(termion::color::Cyan)), - Color::Gray => format!("{}", termion::color::Bg(termion::color::Rgb(146, 131, 116))), - Color::DarkGray => format!("{}", termion::color::Bg(termion::color::Rgb(80, 73, 69))), - Color::LightRed => format!("{}", termion::color::Bg(termion::color::LightRed)), - Color::LightGreen => format!("{}", termion::color::Bg(termion::color::LightGreen)), - Color::LightYellow => format!("{}", termion::color::Bg(termion::color::LightYellow)), - Color::LightMagenta => format!("{}", termion::color::Bg(termion::color::LightMagenta)), - Color::LightCyan => format!("{}", termion::color::Bg(termion::color::LightCyan)), - Color::White => format!("{}", termion::color::Bg(termion::color::White)), - Color::Rgb(r, g, b) => format!("{}", termion::color::Bg(termion::color::Rgb(r, g, b))), + Color::Reset => termion_bg!(Reset), + Color::Black => termion_bg!(Black), + Color::Red => termion_bg!(Red), + Color::Green => termion_bg!(Green), + Color::Yellow => termion_bg!(Yellow), + Color::Magenta => termion_bg!(Magenta), + Color::Cyan => termion_bg!(Cyan), + Color::Gray => termion_bg_rgb!(146, 131, 116), + Color::DarkGray => termion_bg_rgb!(80, 73, 69), + Color::LightRed => termion_bg!(LightRed), + Color::LightGreen => termion_bg!(LightGreen), + Color::LightYellow => termion_bg!(LightYellow), + Color::LightMagenta => termion_bg!(LightMagenta), + Color::LightCyan => termion_bg!(LightCyan), + Color::White => termion_bg!(White), + Color::Rgb(r, g, b) => termion_bg_rgb!(r, g, b), } } } diff --git a/src/terminal.rs b/src/terminal.rs index 7d7c93a..09d3525 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -11,12 +11,16 @@ use widgets::Widget; use style::Color; use util::hash; +pub struct LayoutEntry { + chunks: Vec, + hot: bool, +} + pub struct Terminal { stdout: RawTerminal, - layout_cache: HashMap>, - layout_queue: Vec<(u64, Vec)>, - previous: Buffer, - current: Buffer, + layout_cache: HashMap, + buffers: [Buffer; 2], + current: usize, } impl Terminal { @@ -26,9 +30,8 @@ impl Terminal { Ok(Terminal { stdout: stdout, layout_cache: HashMap::new(), - layout_queue: Vec::new(), - previous: Buffer::empty(size), - current: Buffer::empty(size), + buffers: [Buffer::empty(size), Buffer::empty(size)], + current: 0, }) } @@ -44,23 +47,30 @@ impl Terminal { pub fn compute_layout(&mut self, group: &Group, area: &Rect) -> Vec { let hash = hash(group, area); - let chunks = match self.layout_cache.get(&hash) { - Some(chunks) => chunks.clone(), - None => split(area, &group.direction, group.margin, &group.sizes), - }; - self.layout_queue.push((hash, chunks.clone())); - chunks + let entry = self.layout_cache + .entry(hash) + .or_insert({ + let chunks = split(area, &group.direction, group.margin, &group.sizes); + LayoutEntry { + chunks: chunks, + hot: true, + } + }); + entry.hot = true; + entry.chunks.clone() } pub fn draw(&mut self) { - let width = self.current.area.width; - let mut string = String::with_capacity(self.current.content.len()); + let width = self.buffers[self.current].area.width; + let mut string = String::with_capacity(self.buffers[self.current].content.len()); let mut fg = Color::Reset; let mut bg = Color::Reset; - let content = self.current + let mut last_y = 0; + let mut last_x = 0; + let content = self.buffers[self.current] .content .iter() - .zip(self.previous.content.iter()) + .zip(self.buffers[1 - self.current].content.iter()) .enumerate() .filter_map(|(i, (c, p))| if c != p { let i = i as u16; @@ -70,33 +80,42 @@ impl Terminal { } else { None }); + let mut inst = 0; for (x, y, cell) in content { - string.push_str(&format!("{}", termion::cursor::Goto(x + 1, y + 1))); + if y != last_y || x != last_x + 1 { + string.push_str(&format!("{}", termion::cursor::Goto(x + 1, y + 1))); + inst += 1; + } + last_x = x; + last_y = y; if cell.fg != fg { string.push_str(&cell.fg.fg()); fg = cell.fg; + inst += 1; } if cell.bg != bg { string.push_str(&cell.bg.bg()); bg = cell.bg; + inst += 1; } string.push_str(&format!("{}", cell.symbol)); + inst += 1; } string.push_str(&format!("{}{}", Color::Reset.fg(), Color::Reset.bg())); - info!("{}", string.len()); + info!("{}", inst); write!(self.stdout, "{}", string).unwrap(); } pub fn render(&mut self, widget: &W, area: &Rect) where W: Widget { - widget.buffer(area, &mut self.current); + widget.buffer(area, &mut self.buffers[self.current]); } pub fn resize(&mut self, area: Rect) { - self.current.resize(area); - self.previous.resize(area); - self.previous.reset(); + self.buffers[self.current].resize(area); + self.buffers[1 - self.current].resize(area); + self.buffers[1 - self.current].reset(); self.clear(); } @@ -105,17 +124,18 @@ impl Terminal { // Draw to stdout self.draw(); - // Update layout cache - self.layout_cache.clear(); - for (hash, chunks) in self.layout_queue.drain(..) { - self.layout_cache.insert(hash, chunks); + // Clean layout cache + let to_remove = self.layout_cache + .iter() + .filter_map(|(h, e)| if !e.hot { Some(*h) } else { None }) + .collect::>(); + for h in to_remove { + self.layout_cache.remove(&h); } // Swap buffers - for (i, c) in self.current.content.iter().enumerate() { - self.previous.content[i] = c.clone(); - } - self.current.reset(); + self.buffers[1 - self.current].reset(); + self.current = 1 - self.current; // Flush self.stdout.flush().unwrap();