From e811dd15b56d839b0e43e51eeaea1a2a700c0ebb Mon Sep 17 00:00:00 2001 From: mo8it Date: Mon, 26 Aug 2024 04:29:58 +0200 Subject: Fix list on terminals that don't disable line wrapping --- src/list/state.rs | 109 +++++++++++++++++++++++++----------------------------- 1 file changed, 51 insertions(+), 58 deletions(-) (limited to 'src/list/state.rs') diff --git a/src/list/state.rs b/src/list/state.rs index cc56346..3876884 100644 --- a/src/list/state.rs +++ b/src/list/state.rs @@ -13,7 +13,7 @@ use std::{ use crate::{ app_state::AppState, exercise::Exercise, - term::{progress_bar, terminal_file_link}, + term::{progress_bar, terminal_file_link, CountedWrite, MaxLenWriter}, MAX_EXERCISE_NAME_LEN, }; @@ -28,14 +28,6 @@ fn next_ln(stdout: &mut StdoutLock) -> io::Result<()> { Ok(()) } -// Avoids having the last written char as the last displayed one when the -// written width is higher than the terminal width. -// Happens on the Gnome terminal for example. -fn next_ln_overwrite(stdout: &mut StdoutLock) -> io::Result<()> { - stdout.write_all(b" ")?; - next_ln(stdout) -} - #[derive(Copy, Clone, PartialEq, Eq)] pub enum Filter { Done, @@ -164,40 +156,44 @@ impl<'a> ListState<'a> { .skip(self.row_offset) .take(self.max_n_rows_to_display) { + let mut writer = MaxLenWriter::new(stdout, self.term_width as usize); + if self.selected_row == Some(self.row_offset + n_displayed_rows) { - stdout.queue(SetBackgroundColor(Color::Rgb { + writer.stdout.queue(SetBackgroundColor(Color::Rgb { r: 40, g: 40, b: 40, }))?; - stdout.write_all("🦀".as_bytes())?; + // The crab emoji has the width of two ascii chars. + writer.add_to_len(2); + writer.stdout.write_all("🦀".as_bytes())?; } else { - stdout.write_all(b" ")?; + writer.write_ascii(b" ")?; } if exercise_ind == current_exercise_ind { - stdout.queue(SetForegroundColor(Color::Red))?; - stdout.write_all(b">>>>>>> ")?; + writer.stdout.queue(SetForegroundColor(Color::Red))?; + writer.write_ascii(b">>>>>>> ")?; } else { - stdout.write_all(b" ")?; + writer.write_ascii(b" ")?; } if exercise.done { - stdout.queue(SetForegroundColor(Color::Green))?; - stdout.write_all(b"DONE ")?; + writer.stdout.queue(SetForegroundColor(Color::Green))?; + writer.write_ascii(b"DONE ")?; } else { - stdout.queue(SetForegroundColor(Color::Yellow))?; - stdout.write_all(b"PENDING ")?; + writer.stdout.queue(SetForegroundColor(Color::Yellow))?; + writer.write_ascii(b"PENDING ")?; } - stdout.queue(SetForegroundColor(Color::Reset))?; + writer.stdout.queue(SetForegroundColor(Color::Reset))?; - stdout.write_all(exercise.name.as_bytes())?; - stdout.write_all(&SPACE[..self.name_col_width + 2 - exercise.name.len()])?; + writer.write_str(exercise.name)?; + writer.write_ascii(&SPACE[..self.name_col_width + 2 - exercise.name.len()])?; - terminal_file_link(stdout, exercise.path, Color::Blue)?; + terminal_file_link(&mut writer, exercise.path, Color::Blue)?; - next_ln_overwrite(stdout)?; + next_ln(stdout)?; stdout.queue(ResetColor)?; n_displayed_rows += 1; } @@ -213,10 +209,11 @@ impl<'a> ListState<'a> { stdout.queue(BeginSynchronizedUpdate)?.queue(MoveTo(0, 0))?; // Header - stdout.write_all(b" Current State Name")?; - stdout.write_all(&SPACE[..self.name_col_width - 2])?; - stdout.write_all(b"Path")?; - next_ln_overwrite(stdout)?; + let mut writer = MaxLenWriter::new(stdout, self.term_width as usize); + writer.write_ascii(b" Current State Name")?; + writer.write_ascii(&SPACE[..self.name_col_width - 2])?; + writer.write_ascii(b"Path")?; + next_ln(stdout)?; // Rows let iter = self.app_state.exercises().iter().enumerate(); @@ -237,7 +234,7 @@ impl<'a> ListState<'a> { next_ln(stdout)?; progress_bar( - stdout, + &mut MaxLenWriter::new(stdout, self.term_width as usize), self.app_state.n_done(), self.app_state.exercises().len() as u16, self.term_width, @@ -247,59 +244,55 @@ impl<'a> ListState<'a> { stdout.write_all(&self.separator_line)?; next_ln(stdout)?; + let mut writer = MaxLenWriter::new(stdout, self.term_width as usize); if self.message.is_empty() { // Help footer message if self.selected_row.is_some() { - stdout.write_all( - "↓/j ↑/k home/g end/G | ontinue at | eset exercise".as_bytes(), - )?; + writer.write_str("↓/j ↑/k home/g end/G | ontinue at | eset exercise")?; if self.narrow_term { - next_ln_overwrite(stdout)?; - stdout.write_all(b"filter ")?; + next_ln(stdout)?; + writer = MaxLenWriter::new(stdout, self.term_width as usize); + + writer.write_ascii(b"filter ")?; } else { - stdout.write_all(b" | filter ")?; + writer.write_ascii(b" | filter ")?; } } else { // Nothing selected (and nothing shown), so only display filter and quit. - stdout.write_all(b"filter ")?; + writer.write_ascii(b"filter ")?; } match self.filter { Filter::Done => { - stdout + writer + .stdout .queue(SetForegroundColor(Color::Magenta))? .queue(SetAttribute(Attribute::Underlined))?; - stdout.write_all(b"one")?; - stdout.queue(ResetColor)?; - stdout.write_all(b"/

ending")?; + writer.write_ascii(b"one")?; + writer.stdout.queue(ResetColor)?; + writer.write_ascii(b"/

ending")?; } Filter::Pending => { - stdout.write_all(b"one/")?; - stdout + writer.write_ascii(b"one/")?; + writer + .stdout .queue(SetForegroundColor(Color::Magenta))? .queue(SetAttribute(Attribute::Underlined))?; - stdout.write_all(b"

ending")?; - stdout.queue(ResetColor)?; + writer.write_ascii(b"

ending")?; + writer.stdout.queue(ResetColor)?; } - Filter::None => stdout.write_all(b"one/

ending")?, + Filter::None => writer.write_ascii(b"one/

ending")?, } - stdout.write_all(b" | uit list")?; - - if self.narrow_term { - next_ln_overwrite(stdout)?; - } else { - next_ln(stdout)?; - } + writer.write_ascii(b" | uit list")?; } else { - stdout.queue(SetForegroundColor(Color::Magenta))?; - stdout.write_all(self.message.as_bytes())?; + writer.stdout.queue(SetForegroundColor(Color::Magenta))?; + writer.write_str(&self.message)?; stdout.queue(ResetColor)?; - next_ln_overwrite(stdout)?; - if self.narrow_term { - next_ln(stdout)?; - } + next_ln(stdout)?; } + + next_ln(stdout)?; } stdout.queue(EndSynchronizedUpdate)?.flush() -- cgit v1.2.3