From 2591aef6d4c4425c7c933deafa7dad7df8b2cc74 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Mon, 1 Jan 2018 03:10:32 -0800 Subject: [PATCH] Simplified the screen buffer writing. Turns out the main reason it was so slow was because stdout isn't buffered in Rust by default. That actually makes a lot of sense, but I'd forgotten. Wrapping it in a BufWriter solves the performance issues much more gracefully. --- src/term_ui/screen.rs | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/term_ui/screen.rs b/src/term_ui/screen.rs index 0477025..b4e212b 100644 --- a/src/term_ui/screen.rs +++ b/src/term_ui/screen.rs @@ -1,7 +1,7 @@ use std; use std::cell::RefCell; use std::io; -use std::io::Write; +use std::io::{BufWriter, Write}; use super::smallstring::SmallString; use unicode_width::UnicodeWidthStr; @@ -12,7 +12,7 @@ use termion::color; use termion::raw::{IntoRawMode, RawTerminal}; pub(crate) struct Screen { - out: RefCell>>, + out: RefCell>>>, buf: RefCell>>, w: usize, h: usize, @@ -25,7 +25,11 @@ impl Screen { .take(w as usize * h as usize) .collect(); Screen { - out: RefCell::new(AlternateScreen::from(io::stdout().into_raw_mode().unwrap())), + out: RefCell::new(AlternateScreen::from( + BufWriter::with_capacity(1 << 14, io::stdout()) + .into_raw_mode() + .unwrap(), + )), buf: RefCell::new(buf), w: w as usize, h: h as usize, @@ -56,39 +60,31 @@ impl Screen { } pub(crate) fn present(&self) { + let mut out = self.out.borrow_mut(); let buf = self.buf.borrow(); - // Double the minimum needed space, because of formatting characters and such. - let mut tmp_string = String::with_capacity(self.w * self.h * 2); - tmp_string.push_str(&format!("{}", termion::cursor::Goto(1, 1))); + let mut last_style = Style(Color::Black, Color::Black); + write!(out, "{}", last_style).unwrap(); // Write everything to the tmp_string first. for y in 0..self.h { let mut x = 0; - let mut last_style = Style(Color::Black, Color::Black); - tmp_string.push_str(&format!("{}", last_style)); + write!(out, "{}", termion::cursor::Goto(1, y as u16 + 2)).unwrap(); while x < self.w { if let Some((style, ref text)) = buf[y * self.w + x] { if style != last_style { - tmp_string.push_str(&format!("{}", style)); + write!(out, "{}", style).unwrap(); last_style = style; } - tmp_string.push_str(text); + write!(out, "{}", text).unwrap(); x += 1; } else { x += 1; } } - tmp_string.push_str(&format!("{}", termion::cursor::Goto(1, y as u16 + 2))); } - // Write tmp_string to the screen all at once. - write!( - self.out.borrow_mut(), - "{}{}", - termion::cursor::Goto(0, 0), - tmp_string, - ).unwrap(); + // Make sure everything is written out self.out.borrow_mut().flush().unwrap(); }