use ratatui::style::Modifier;
use ratatui::style::Style;
use ratatui::symbols::cursor;
use crate::settings::Settings;
use crate::settings::adapters::editor;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CursorStyle {
Block,
Underline,
Beam,
}
impl CursorStyle {
pub fn from_str(s: &str) -> Self {
match s.to_lowercase().as_str() {
"underline" => Self::Underline,
"beam" => Self::Beam,
_ => Self::Block,
}
}
pub fn to_ratatui_style(&self) -> Style {
match self {
Self::Block => Style::default().add_modifier(Modifier::Reverse),
Self::Underline => Style::default().add_modifier(Modifier::Underlined),
Self::Beam => Style::default().add_modifier(Modifier::RapidBlink),
}
}
pub fn to_symbol(&self) -> &str {
match self {
Self::Block => cursor::BLOCK,
Self::Underline => cursor::UNDERLINE,
Self::Beam => cursor::BLANK,
}
}
}
pub fn get_cursor_style(settings: &Settings) -> CursorStyle {
let style_str = editor::cursor_style(settings);
CursorStyle::from_str(style_str)
}
pub fn should_cursor_blink(settings: &Settings) -> bool {
*editor::cursor_blink(settings)
}
pub fn should_reduce_motion(settings: &Settings) -> bool {
if *editor::reduced_motion(settings) {
return true;
}
if let Ok(env) = std::env::var("REDUCED_MOTION") {
return env == "1" || env.to_lowercase() == "true";
}
false
}
pub fn is_high_contrast_mode(settings: &Settings) -> bool {
*editor::high_contrast(settings)
}
pub fn should_dim_non_focused(settings: &Settings) -> bool {
*editor::dim_non_focused(settings)
}
pub fn get_line_spacing(settings: &Settings) -> f64 {
*editor::line_spacing(settings)
}
pub struct AccessibilityColors {
pub cursor_fg: ratatui::style::Color,
pub cursor_bg: ratatui::style::Color,
pub selection_bg: ratatui::style::Color,
pub selection_fg: ratatui::style::Color,
pub search_bg: ratatui::style::Color,
pub search_current_bg: ratatui::style::Color,
}
impl AccessibilityColors {
pub fn standard(
selection_bg: ratatui::style::Color,
selection_fg: ratatui::style::Color,
) -> Self {
Self {
cursor_fg: ratatui::style::Color::Reset,
cursor_bg: ratatui::style::Color::LightYellow,
selection_bg,
selection_fg,
search_bg: ratatui::style::Color::Rgb(100, 80, 0),
search_current_bg: ratatui::style::Color::Rgb(230, 160, 0),
}
}
pub fn high_contrast() -> Self {
Self {
cursor_fg: ratatui::style::Color::Black,
cursor_bg: ratatui::style::Color::Yellow,
selection_bg: ratatui::style::Color::Black,
selection_fg: ratatui::style::Color::White,
search_bg: ratatui::style::Color::Cyan,
search_current_bg: ratatui::style::Color::Green,
}
}
}
pub fn get_accessibility_colors(
settings: &Settings,
theme: &crate::theme::Theme,
) -> AccessibilityColors {
if is_high_contrast_mode(settings) {
AccessibilityColors::high_contrast()
} else {
AccessibilityColors::standard(theme.selection_bg(), theme.selection_fg())
}
}
pub fn apply_accessibility_modifiers(
style: Style,
settings: &Settings,
) -> Style {
let mut result = style;
if should_reduce_motion(settings) {
result = result.remove_modifier(Modifier::Blinking);
result = result.remove_modifier(Modifier::RapidBlink);
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cursor_style_from_str() {
assert_eq!(CursorStyle::from_str("block"), CursorStyle::Block);
assert_eq!(CursorStyle::from_str("underline"), CursorStyle::Underline);
assert_eq!(CursorStyle::from_str("beam"), CursorStyle::Beam);
assert_eq!(CursorStyle::from_str("unknown"), CursorStyle::Block);
}
#[test]
fn accessibility_colors() {
let colors = AccessibilityColors::high_contrast();
assert_eq!(colors.cursor_fg, ratatui::style::Color::Black);
assert_eq!(colors.cursor_bg, ratatui::style::Color::Yellow);
}
}