Make width measuring optional and disabled by default
This commit is contained in:
parent
33264b4aec
commit
333cf74fba
5 changed files with 47 additions and 27 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use crossterm::event::Event;
|
||||
use crossterm::style::{ContentStyle, Stylize};
|
||||
use toss::frame::{Frame, Pos};
|
||||
use toss::terminal::{Redraw, Terminal};
|
||||
use toss::terminal::Terminal;
|
||||
|
||||
fn draw(f: &mut Frame) {
|
||||
f.write(
|
||||
|
|
@ -24,8 +24,11 @@ fn render_frame(term: &mut Terminal) {
|
|||
term.autoresize().unwrap();
|
||||
|
||||
draw(term.frame());
|
||||
term.present().unwrap();
|
||||
|
||||
if term.present().unwrap() == Redraw::NotRequired {
|
||||
if term.measuring_required() {
|
||||
term.measure_widths().unwrap();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +37,7 @@ fn render_frame(term: &mut Terminal) {
|
|||
fn main() {
|
||||
// Automatically enters alternate screen and enables raw mode
|
||||
let mut term = Terminal::new().unwrap();
|
||||
term.set_measuring(true);
|
||||
|
||||
loop {
|
||||
// Render and display a frame. A full frame is displayed on the terminal
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crossterm::event::Event;
|
||||
use crossterm::style::{ContentStyle, Stylize};
|
||||
use toss::frame::{Frame, Pos};
|
||||
use toss::terminal::{Redraw, Terminal};
|
||||
use toss::terminal::Terminal;
|
||||
|
||||
fn draw(f: &mut Frame) {
|
||||
f.write(
|
||||
|
|
@ -65,7 +65,9 @@ fn render_frame(term: &mut Terminal) {
|
|||
|
||||
draw(term.frame());
|
||||
|
||||
if term.present().unwrap() == Redraw::NotRequired {
|
||||
if term.measuring_required() {
|
||||
term.measure_widths().unwrap();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -74,6 +76,7 @@ fn render_frame(term: &mut Terminal) {
|
|||
fn main() {
|
||||
// Automatically enters alternate screen and enables raw mode
|
||||
let mut term = Terminal::new().unwrap();
|
||||
term.set_measuring(true);
|
||||
|
||||
loop {
|
||||
// Render and display a frame. A full frame is displayed on the terminal
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crossterm::event::Event;
|
||||
use crossterm::style::ContentStyle;
|
||||
use toss::frame::{Frame, Pos};
|
||||
use toss::terminal::{Redraw, Terminal};
|
||||
use toss::terminal::Terminal;
|
||||
|
||||
fn draw(f: &mut Frame) {
|
||||
let text = concat!(
|
||||
|
|
@ -36,7 +36,9 @@ fn render_frame(term: &mut Terminal) {
|
|||
|
||||
draw(term.frame());
|
||||
|
||||
if term.present().unwrap() == Redraw::NotRequired {
|
||||
if term.measuring_required() {
|
||||
term.measure_widths().unwrap();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +47,7 @@ fn render_frame(term: &mut Terminal) {
|
|||
fn main() {
|
||||
// Automatically enters alternate screen and enables raw mode
|
||||
let mut term = Terminal::new().unwrap();
|
||||
term.set_measuring(true);
|
||||
|
||||
loop {
|
||||
// Render and display a frame. A full frame is displayed on the terminal
|
||||
|
|
|
|||
|
|
@ -11,12 +11,6 @@ use crossterm::{ExecutableCommand, QueueableCommand};
|
|||
use crate::buffer::{Buffer, Size};
|
||||
use crate::frame::Frame;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Redraw {
|
||||
Required,
|
||||
NotRequired,
|
||||
}
|
||||
|
||||
pub struct Terminal {
|
||||
/// Render target.
|
||||
out: Box<dyn Write>,
|
||||
|
|
@ -54,6 +48,24 @@ impl Terminal {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn set_measuring(&mut self, active: bool) {
|
||||
self.frame.widthdb.active = active;
|
||||
}
|
||||
|
||||
pub fn measuring(&self) -> bool {
|
||||
self.frame.widthdb.active
|
||||
}
|
||||
|
||||
pub fn measuring_required(&self) -> bool {
|
||||
self.frame.widthdb.measuring_required()
|
||||
}
|
||||
|
||||
pub fn measure_widths(&mut self) -> io::Result<()> {
|
||||
self.frame.widthdb.measure_widths(&mut self.out)?;
|
||||
self.full_redraw = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Resize the frame and other internal buffers if the terminal size has
|
||||
/// changed.
|
||||
pub fn autoresize(&mut self) -> io::Result<()> {
|
||||
|
|
@ -77,19 +89,7 @@ impl Terminal {
|
|||
///
|
||||
/// After calling this function, the frame returned by [`Self::frame`] will
|
||||
/// be empty again and have no cursor position.
|
||||
pub fn present(&mut self) -> io::Result<Redraw> {
|
||||
if self.frame.widthdb.measuring_required() {
|
||||
self.frame.widthdb.measure_widths(&mut self.out)?;
|
||||
// Since we messed up the screen by measuring widths, we'll need to
|
||||
// do a full redraw the next time around.
|
||||
self.full_redraw = true;
|
||||
// Throwing away the current frame because its content were rendered
|
||||
// with unconfirmed width data. Also, this function guarantees that
|
||||
// after it is called, the frame is empty.
|
||||
self.frame.reset();
|
||||
return Ok(Redraw::Required);
|
||||
}
|
||||
|
||||
pub fn present(&mut self) -> io::Result<()> {
|
||||
if self.full_redraw {
|
||||
io::stdout().queue(Clear(ClearType::All))?;
|
||||
self.prev_frame_buffer.reset(); // Because the screen is now empty
|
||||
|
|
@ -103,7 +103,7 @@ impl Terminal {
|
|||
mem::swap(&mut self.prev_frame_buffer, &mut self.frame.buffer);
|
||||
self.frame.reset();
|
||||
|
||||
Ok(Redraw::NotRequired)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_differences(&mut self) -> io::Result<()> {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use unicode_width::UnicodeWidthStr;
|
|||
/// Measures and stores the with (in terminal coordinates) of graphemes.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct WidthDB {
|
||||
pub active: bool,
|
||||
known: HashMap<String, u8>,
|
||||
requested: HashSet<String>,
|
||||
}
|
||||
|
|
@ -22,6 +23,9 @@ impl WidthDB {
|
|||
/// Unicode Standard Annex #11.
|
||||
pub fn grapheme_width(&mut self, grapheme: &str) -> u8 {
|
||||
assert_eq!(Some(grapheme), grapheme.graphemes(true).next());
|
||||
if !self.active {
|
||||
return grapheme.width() as u8;
|
||||
}
|
||||
if let Some(width) = self.known.get(grapheme) {
|
||||
*width
|
||||
} else {
|
||||
|
|
@ -35,6 +39,9 @@ impl WidthDB {
|
|||
/// If the width of a grapheme has not been measured yet, it is estimated
|
||||
/// using the Unicode Standard Annex #11.
|
||||
pub fn width(&mut self, s: &str) -> usize {
|
||||
if !self.active {
|
||||
return s.width();
|
||||
}
|
||||
let mut total: usize = 0;
|
||||
for grapheme in s.graphemes(true) {
|
||||
total += if let Some(width) = self.known.get(grapheme) {
|
||||
|
|
@ -50,7 +57,7 @@ impl WidthDB {
|
|||
/// Whether any new graphemes have been seen since the last time
|
||||
/// [`Self::measure_widths`] was called.
|
||||
pub fn measuring_required(&self) -> bool {
|
||||
!self.requested.is_empty()
|
||||
self.active && !self.requested.is_empty()
|
||||
}
|
||||
|
||||
/// Measure the width of all new graphemes that have been seen since the
|
||||
|
|
@ -60,6 +67,9 @@ impl WidthDB {
|
|||
/// the terminal. After it finishes, the terminal's contents should be
|
||||
/// assumed to be garbage and a full redraw should be performed.
|
||||
pub fn measure_widths(&mut self, out: &mut impl Write) -> io::Result<()> {
|
||||
if !self.active {
|
||||
return Ok(());
|
||||
}
|
||||
for grapheme in self.requested.drain() {
|
||||
out.queue(Clear(ClearType::All))?
|
||||
.queue(MoveTo(0, 0))?
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue