Fix contrast in terminals with a light theme

This commit is contained in:
mo8it 2024-11-11 14:34:33 +01:00
parent 2a725fb137
commit 46ad25f925
2 changed files with 33 additions and 18 deletions

View file

@ -1,7 +1,9 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use crossterm::{ use crossterm::{
cursor::{MoveTo, MoveToNextLine}, cursor::{MoveTo, MoveToNextLine},
style::{Attribute, Color, ResetColor, SetAttribute, SetBackgroundColor, SetForegroundColor}, style::{
Attribute, Attributes, Color, ResetColor, SetAttribute, SetAttributes, SetForegroundColor,
},
terminal::{self, BeginSynchronizedUpdate, Clear, ClearType, EndSynchronizedUpdate}, terminal::{self, BeginSynchronizedUpdate, Clear, ClearType, EndSynchronizedUpdate},
QueueableCommand, QueueableCommand,
}; };
@ -19,6 +21,9 @@ use crate::{
use super::scroll_state::ScrollState; use super::scroll_state::ScrollState;
const COL_SPACING: usize = 2; const COL_SPACING: usize = 2;
const SELECTED_ROW_ATTRIBUTES: Attributes = Attributes::none()
.with(Attribute::Reverse)
.with(Attribute::Bold);
fn next_ln(stdout: &mut StdoutLock) -> io::Result<()> { fn next_ln(stdout: &mut StdoutLock) -> io::Result<()> {
stdout stdout
@ -41,6 +46,7 @@ pub struct ListState<'a> {
app_state: &'a mut AppState, app_state: &'a mut AppState,
scroll_state: ScrollState, scroll_state: ScrollState,
name_col_padding: Vec<u8>, name_col_padding: Vec<u8>,
path_col_padding: Vec<u8>,
filter: Filter, filter: Filter,
term_width: u16, term_width: u16,
term_height: u16, term_height: u16,
@ -52,13 +58,18 @@ impl<'a> ListState<'a> {
stdout.queue(Clear(ClearType::All))?; stdout.queue(Clear(ClearType::All))?;
let name_col_title_len = 4; let name_col_title_len = 4;
let name_col_width = app_state let path_col_title_len = 4;
.exercises() let (name_col_width, path_col_width) = app_state.exercises().iter().fold(
.iter() (name_col_title_len, path_col_title_len),
.map(|exercise| exercise.name.len()) |(name_col_width, path_col_width), exercise| {
.max() (
.map_or(name_col_title_len, |max| max.max(name_col_title_len)); name_col_width.max(exercise.name.len()),
path_col_width.max(exercise.path.len()),
)
},
);
let name_col_padding = vec![b' '; name_col_width + COL_SPACING]; let name_col_padding = vec![b' '; name_col_width + COL_SPACING];
let path_col_padding = vec![b' '; path_col_width];
let filter = Filter::None; let filter = Filter::None;
let n_rows_with_filter = app_state.exercises().len(); let n_rows_with_filter = app_state.exercises().len();
@ -73,6 +84,7 @@ impl<'a> ListState<'a> {
app_state, app_state,
scroll_state, scroll_state,
name_col_padding, name_col_padding,
path_col_padding,
filter, filter,
// Set by `set_term_size` // Set by `set_term_size`
term_width: 0, term_width: 0,
@ -119,7 +131,7 @@ impl<'a> ListState<'a> {
writer.write_str(pre_highlight)?; writer.write_str(pre_highlight)?;
writer.stdout.queue(SetForegroundColor(Color::Magenta))?; writer.stdout.queue(SetForegroundColor(Color::Magenta))?;
writer.write_str(highlight)?; writer.write_str(highlight)?;
writer.stdout.queue(ResetColor)?; writer.stdout.queue(SetForegroundColor(Color::Reset))?;
return writer.write_str(post_highlight); return writer.write_str(post_highlight);
} }
} }
@ -143,14 +155,12 @@ impl<'a> ListState<'a> {
let mut writer = MaxLenWriter::new(stdout, self.term_width as usize); let mut writer = MaxLenWriter::new(stdout, self.term_width as usize);
if self.scroll_state.selected() == Some(row_offset + n_displayed_rows) { if self.scroll_state.selected() == Some(row_offset + n_displayed_rows) {
writer.stdout.queue(SetBackgroundColor(Color::Rgb {
r: 40,
g: 40,
b: 40,
}))?;
// The crab emoji has the width of two ascii chars. // The crab emoji has the width of two ascii chars.
writer.add_to_len(2); writer.add_to_len(2);
writer.stdout.write_all("🦀".as_bytes())?; writer.stdout.write_all("🦀".as_bytes())?;
writer
.stdout
.queue(SetAttributes(SELECTED_ROW_ATTRIBUTES))?;
} else { } else {
writer.write_ascii(b" ")?; writer.write_ascii(b" ")?;
} }
@ -164,12 +174,13 @@ impl<'a> ListState<'a> {
if exercise.done { if exercise.done {
writer.stdout.queue(SetForegroundColor(Color::Green))?; writer.stdout.queue(SetForegroundColor(Color::Green))?;
writer.write_ascii(b"DONE ")?; writer.write_ascii(b"DONE ")?;
} else { } else {
writer.stdout.queue(SetForegroundColor(Color::Yellow))?; writer.stdout.queue(SetForegroundColor(Color::Yellow))?;
writer.write_ascii(b"PENDING ")?; writer.write_ascii(b"PENDING")?;
} }
writer.stdout.queue(SetForegroundColor(Color::Reset))?; writer.stdout.queue(SetForegroundColor(Color::Reset))?;
writer.write_ascii(b" ")?;
self.draw_exericse_name(&mut writer, exercise)?; self.draw_exericse_name(&mut writer, exercise)?;
@ -183,6 +194,8 @@ impl<'a> ListState<'a> {
exercise.terminal_file_link(&mut writer)?; exercise.terminal_file_link(&mut writer)?;
} }
writer.write_ascii(&self.path_col_padding[exercise.path.len()..])?;
next_ln(stdout)?; next_ln(stdout)?;
stdout.queue(ResetColor)?; stdout.queue(ResetColor)?;
n_displayed_rows += 1; n_displayed_rows += 1;

View file

@ -20,6 +20,10 @@ use crate::{
use super::{terminal_event::terminal_event_handler, InputPauseGuard, WatchEvent}; use super::{terminal_event::terminal_event_handler, InputPauseGuard, WatchEvent};
const HEADING_ATTRIBUTES: Attributes = Attributes::none()
.with(Attribute::Bold)
.with(Attribute::Underlined);
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
enum DoneStatus { enum DoneStatus {
DoneWithSolution(String), DoneWithSolution(String),
@ -209,9 +213,7 @@ impl<'a> WatchState<'a> {
if self.show_hint { if self.show_hint {
stdout stdout
.queue(SetAttributes( .queue(SetAttributes(HEADING_ATTRIBUTES))?
Attributes::from(Attribute::Bold).with(Attribute::Underlined),
))?
.queue(SetForegroundColor(Color::Cyan))?; .queue(SetForegroundColor(Color::Cyan))?;
stdout.write_all(b"Hint")?; stdout.write_all(b"Hint")?;
stdout.queue(ResetColor)?; stdout.queue(ResetColor)?;