diff --git a/src/backend/blt.rs b/src/backend/blt.rs index 88bd573..1651155 100644 --- a/src/backend/blt.rs +++ b/src/backend/blt.rs @@ -17,6 +17,7 @@ use crate::backend; use crate::event::{Event, Key, MouseButton, MouseEvent}; use crate::theme::{BaseColor, Color, ColorPair, Effect}; use crate::vec::Vec2; +use unicode_width::UnicodeWidthStr; enum ColorRole { Foreground, diff --git a/src/backend/curses/n.rs b/src/backend/curses/n.rs index 9575c0d..4209e5e 100644 --- a/src/backend/curses/n.rs +++ b/src/backend/curses/n.rs @@ -373,6 +373,17 @@ impl backend::Backend for Backend { fn print_at(&self, pos: Vec2, text: &str) { ncurses::mvaddstr(pos.y as i32, pos.x as i32, text); } + + fn print_at_rep(&self, pos: Vec2, repetitions: usize, text: &str) { + if repetitions > 0 { + ncurses::mvaddstr(pos.y as i32, pos.x as i32, text); + let mut dupes_left = repetitions - 1; + while dupes_left > 0 { + ncurses::addstr(text); + dupes_left -= 1; + } + } + } } /// Returns the Key enum corresponding to the given ncurses event. diff --git a/src/backend/curses/pan.rs b/src/backend/curses/pan.rs index 620af0f..c045d55 100644 --- a/src/backend/curses/pan.rs +++ b/src/backend/curses/pan.rs @@ -417,6 +417,17 @@ impl backend::Backend for Backend { self.window.mvaddstr(pos.y as i32, pos.x as i32, text); } + fn print_at_rep(&self, pos: Vec2, repetitions: usize, text: &str) { + if repetitions > 0 { + self.window.mvaddstr(pos.y as i32, pos.x as i32, text); + let mut dupes_left = repetitions - 1; + while dupes_left > 0 { + self.window.addstr(text); + dupes_left -= 1; + } + } + } + fn poll_event(&mut self) -> Option { self.parse_next() } diff --git a/src/backend/dummy.rs b/src/backend/dummy.rs index da6bf95..bbc25f6 100644 --- a/src/backend/dummy.rs +++ b/src/backend/dummy.rs @@ -38,6 +38,8 @@ impl backend::Backend for Backend { fn print_at(&self, _: Vec2, _: &str) {} + fn print_at_rep(&self, _pos: Vec2, _repetitions: usize, _text: &str) {} + fn clear(&self, _: theme::Color) {} // This sets the Colours and returns the previous colours diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 52d2689..6ccba32 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -10,6 +10,7 @@ use crate::event::Event; use crate::theme; use crate::vec::Vec2; +use unicode_width::UnicodeWidthStr; #[cfg(unix)] mod resize; @@ -63,6 +64,24 @@ pub trait Backend { /// Main method used for printing fn print_at(&self, pos: Vec2, text: &str); + + /// First positions the cursor, similar to `print_at`, and then prints the given number of + /// `repetitions` of `text`. + fn print_at_rep(&self, pos: Vec2, repetitions: usize, text: &str) { + if repetitions > 0 { + self.print_at(pos, text); + + let width = text.width(); + let mut pos = pos; + let mut dupes_left = repetitions - 1; + + while dupes_left > 0 { + pos = pos.saturating_add((width, 0)); + self.print_at(pos, text); + dupes_left -= 1; + } + } + } /// Clears the screen with the given color. fn clear(&self, color: theme::Color); diff --git a/src/backend/termion.rs b/src/backend/termion.rs index 2a890f2..7b70f3e 100644 --- a/src/backend/termion.rs +++ b/src/backend/termion.rs @@ -268,6 +268,24 @@ impl backend::Backend for Backend { .unwrap(); } + fn print_at_rep(&self, pos: Vec2, repetitions: usize, text: &str) { + if repetitions > 0 { + let mut out = self.terminal.borrow_mut(); + write!( + out, + "{}{}", + termion::cursor::Goto(1 + pos.x as u16, 1 + pos.y as u16), + text + ).unwrap(); + + let mut dupes_left = repetitions - 1; + while dupes_left > 0 { + write!(out, "{}", text).unwrap(); + dupes_left -= 1; + } + } + } + fn poll_event(&mut self) -> Option { let event = select! { recv(self.input_receiver) -> event => event.ok(), diff --git a/src/printer.rs b/src/printer.rs index 4dc8f82..204af5d 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -255,13 +255,10 @@ impl<'a, 'b> Printer<'a, 'b> { let start = start - self.content_offset; // Don't write too much if we're close to the end - let width = min(width, (self.output_size.x - start.x) / c.width()); - - // Could we avoid allocating? - let text: String = ::std::iter::repeat(c).take(width).collect(); + let repetitions = min(width, self.output_size.x - start.x) / c.width(); let start = start + self.offset; - self.backend.print_at(start, &text); + self.backend.print_at_rep(start, repetitions, c); } /// Call the given closure with a colored printer,