From 66a80baeed5ad02cfde0091031ab6b6d76944d46 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Sun, 31 Dec 2017 18:51:02 -0800 Subject: [PATCH] Doing screen buffering to eliminate flicker. At the moment, it's brain-dead and really slow. --- src/term_ui/mod.rs | 1 + src/term_ui/screen.rs | 90 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/term_ui/mod.rs b/src/term_ui/mod.rs index d74c1d7..7a988a7 100644 --- a/src/term_ui/mod.rs +++ b/src/term_ui/mod.rs @@ -52,6 +52,7 @@ macro_rules! ui_loop { $term_ui.width = w as usize; $term_ui.height = h as usize; $term_ui.editor.update_dim($term_ui.height - 1, $term_ui.width); + $term_ui.screen.resize(w as usize, h as usize); } if stop || $term_ui.quit { diff --git a/src/term_ui/screen.rs b/src/term_ui/screen.rs index 0d36b6e..c4ccf62 100644 --- a/src/term_ui/screen.rs +++ b/src/term_ui/screen.rs @@ -1,7 +1,10 @@ +use std; use std::cell::RefCell; use std::io; use std::io::Write; +use unicode_width::UnicodeWidthStr; +use unicode_segmentation::UnicodeSegmentation; use termion; use termion::screen::AlternateScreen; use termion::color; @@ -9,29 +12,81 @@ use termion::raw::{IntoRawMode, RawTerminal}; pub(crate) struct Screen { out: RefCell>>, + buf: RefCell>>, + w: usize, + h: usize, } impl Screen { pub(crate) fn new() -> Self { + let (w, h) = termion::terminal_size().unwrap(); + let buf = std::iter::repeat(Some(format!( + "{}{} ", + color::Fg(color::Black), + color::Bg(color::Black) + ))).take(w as usize * h as usize) + .collect(); Screen { out: RefCell::new(AlternateScreen::from(io::stdout().into_raw_mode().unwrap())), + buf: RefCell::new(buf), + w: w as usize, + h: h as usize, } } pub(crate) fn clear(&self) { - write!( - self.out.borrow_mut(), - "{}{}", - color::Bg(color::Black), - termion::clear::All - ).unwrap(); + for cell in self.buf.borrow_mut().iter_mut() { + match *cell { + Some(ref mut text) => { + text.clear(); + text.push_str(&format!( + "{}{} ", + color::Fg(color::Black), + color::Bg(color::Black) + )); + } + _ => { + *cell = Some(format!( + "{}{} ", + color::Fg(color::Black), + color::Bg(color::Black) + )); + } + } + } + } + + pub(crate) fn resize(&mut self, w: usize, h: usize) { + self.w = w; + self.h = h; + self.buf.borrow_mut().resize( + w * h, + Some(format!( + "{}{} ", + color::Fg(color::Black), + color::Bg(color::Black) + )), + ); } pub(crate) fn present(&self) { + let buf = self.buf.borrow(); + for y in 0..self.h { + for x in 0..self.w { + if let Some(ref cell) = buf[y * self.w + x] { + write!( + self.out.borrow_mut(), + "{}{}", + termion::cursor::Goto((x + 1) as u16, (y + 1) as u16), + cell + ).unwrap(); + } + } + } self.out.borrow_mut().flush().unwrap(); } - pub(crate) fn draw( + pub(crate) fn draw( &self, x: usize, y: usize, @@ -39,14 +94,19 @@ impl Screen { fg: C1, bg: C2, ) { - write!( - self.out.borrow_mut(), - "{}{}{}{}", - termion::cursor::Goto((x + 1) as u16, (y + 1) as u16), - color::Fg(fg), - color::Bg(bg), - text - ).unwrap(); + let mut buf = self.buf.borrow_mut(); + let mut x = x; + for g in UnicodeSegmentation::graphemes(text, true) { + let width = UnicodeWidthStr::width(g); + if width > 0 { + buf[y * self.w + x] = Some(format!("{}{}{}", color::Fg(fg), color::Bg(bg), g)); + x += 1; + for _ in 0..(width - 1) { + buf[y * self.w + x] = None; + x += 1; + } + } + } } pub(crate) fn hide_cursor(&self) {