its now using enum fully for the highlight mode

This commit is contained in:
filipriec
2025-04-16 00:11:41 +02:00
parent af4567aa3d
commit b6c4d3308d
11 changed files with 103 additions and 95 deletions

View File

@@ -12,6 +12,7 @@ use ratatui::{
widgets::{Block, BorderType, Borders, Paragraph}, widgets::{Block, BorderType, Borders, Paragraph},
Frame, Frame,
}; };
use crate::state::app::highlight::HighlightState;
pub fn render_login( pub fn render_login(
f: &mut Frame, f: &mut Frame,
@@ -20,9 +21,7 @@ pub fn render_login(
login_state: &LoginState, login_state: &LoginState,
app_state: &AppState, app_state: &AppState,
is_edit_mode: bool, is_edit_mode: bool,
is_highlight_mode: bool, highlight_state: &HighlightState,
is_linewise_highlight: bool,
highlight_anchor: Option<(usize, usize)>,
) { ) {
// Main container // Main container
let block = Block::default() let block = Block::default()
@@ -59,9 +58,7 @@ pub fn render_login(
&[&login_state.username, &login_state.password], &[&login_state.username, &login_state.password],
theme, theme,
is_edit_mode, is_edit_mode,
is_highlight_mode, highlight_state,
is_linewise_highlight,
highlight_anchor,
); );
// --- ERROR MESSAGE --- // --- ERROR MESSAGE ---

View File

@@ -14,6 +14,7 @@ use ratatui::{
widgets::{Block, BorderType, Borders, Paragraph}, widgets::{Block, BorderType, Borders, Paragraph},
Frame, Frame,
}; };
use crate::state::app::highlight::HighlightState;
pub fn render_register( pub fn render_register(
f: &mut Frame, f: &mut Frame,
@@ -22,9 +23,7 @@ pub fn render_register(
state: &RegisterState, // Use RegisterState state: &RegisterState, // Use RegisterState
app_state: &AppState, app_state: &AppState,
is_edit_mode: bool, is_edit_mode: bool,
is_highlight_mode: bool, highlight_state: &HighlightState,
is_linewise_highlight: bool,
highlight_anchor: Option<(usize, usize)>,
) { ) {
let block = Block::default() let block = Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
@@ -67,9 +66,7 @@ pub fn render_register(
&state.inputs().iter().map(|s| *s).collect::<Vec<&String>>(), // Pass inputs directly &state.inputs().iter().map(|s| *s).collect::<Vec<&String>>(), // Pass inputs directly
theme, theme,
is_edit_mode, is_edit_mode,
is_highlight_mode, highlight_state,
is_linewise_highlight,
highlight_anchor,
); );
// --- HELP TEXT --- // --- HELP TEXT ---

View File

@@ -7,6 +7,7 @@ use ratatui::{
}; };
use crate::config::colors::themes::Theme; use crate::config::colors::themes::Theme;
use crate::state::pages::canvas_state::CanvasState; use crate::state::pages::canvas_state::CanvasState;
use crate::state::app::highlight::HighlightState;
use crate::components::handlers::canvas::render_canvas; use crate::components::handlers::canvas::render_canvas;
pub fn render_form( pub fn render_form(
@@ -18,9 +19,7 @@ pub fn render_form(
inputs: &[&String], inputs: &[&String],
theme: &Theme, theme: &Theme,
is_edit_mode: bool, is_edit_mode: bool,
is_highlight_mode: bool, highlight_state: &HighlightState,
is_linewise_highlight: bool,
highlight_anchor: Option<(usize, usize)>,
total_count: u64, total_count: u64,
current_position: u64, current_position: u64,
) { ) {
@@ -65,8 +64,6 @@ pub fn render_form(
inputs, inputs,
theme, theme,
is_edit_mode, is_edit_mode,
is_highlight_mode, highlight_state,
is_linewise_highlight,
highlight_anchor,
); );
} }

View File

@@ -9,6 +9,7 @@ use ratatui::{
}; };
use crate::config::colors::themes::Theme; use crate::config::colors::themes::Theme;
use crate::state::pages::canvas_state::CanvasState; use crate::state::pages::canvas_state::CanvasState;
use crate::state::app::highlight::HighlightState; // Ensure correct import path
use std::cmp::{min, max}; use std::cmp::{min, max};
pub fn render_canvas( pub fn render_canvas(
@@ -20,10 +21,9 @@ pub fn render_canvas(
inputs: &[&String], inputs: &[&String],
theme: &Theme, theme: &Theme,
is_edit_mode: bool, is_edit_mode: bool,
is_highlight_mode: bool, highlight_state: &HighlightState, // Using the enum state
is_linewise_highlight: bool,
highlight_anchor: Option<(usize, usize)>,
) -> Option<Rect> { ) -> Option<Rect> {
// ... (column split, container styling, block dimensions - unchanged) ...
let columns = Layout::default() let columns = Layout::default()
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
.constraints([Constraint::Percentage(30), Constraint::Percentage(70)]) .constraints([Constraint::Percentage(30), Constraint::Percentage(70)])
@@ -72,6 +72,7 @@ pub fn render_canvas(
}); });
} }
// Render inputs and cursor // Render inputs and cursor
for (i, input) in inputs.iter().enumerate() { for (i, input) in inputs.iter().enumerate() {
let is_active = i == *current_field_idx; let is_active = i == *current_field_idx;
@@ -81,28 +82,20 @@ pub fn render_canvas(
let line: Line; let line: Line;
if is_highlight_mode && highlight_anchor.is_some() { // --- Use match on the highlight_state enum ---
let (anchor_field, anchor_char) = highlight_anchor.unwrap(); match highlight_state {
let start_field = min(anchor_field, *current_field_idx); HighlightState::Off => {
let end_field = max(anchor_field, *current_field_idx); // Not in highlight mode, render normally
line = Line::from(Span::styled(
let highlight_style = Style::default() text,
.fg(theme.highlight) if is_active { Style::default().fg(theme.highlight) } else { Style::default().fg(theme.fg) }
.bg(theme.highlight_bg) ));
.add_modifier(Modifier::BOLD); }
let normal_style_in_highlight = Style::default().fg(theme.highlight); HighlightState::Characterwise { anchor } => {
let normal_style_outside = Style::default().fg(theme.fg); // --- Character-wise Highlight Logic ---
let (anchor_field, anchor_char) = *anchor; // Dereference the tuple from the enum
if is_linewise_highlight { let start_field = min(anchor_field, *current_field_idx);
if i >= start_field && i <= end_field { let end_field = max(anchor_field, *current_field_idx);
line = Line::from(Span::styled(text, highlight_style));
} else {
line = Line::from(Span::styled(
text,
if is_active { normal_style_in_highlight } else { normal_style_outside }
));
}
} else {
let (start_char, end_char) = if anchor_field == *current_field_idx { let (start_char, end_char) = if anchor_field == *current_field_idx {
(min(anchor_char, current_cursor_pos), max(anchor_char, current_cursor_pos)) (min(anchor_char, current_cursor_pos), max(anchor_char, current_cursor_pos))
} else if anchor_field < *current_field_idx { } else if anchor_field < *current_field_idx {
@@ -111,8 +104,13 @@ pub fn render_canvas(
(current_cursor_pos, anchor_char) (current_cursor_pos, anchor_char)
}; };
let highlight_style = Style::default().fg(theme.highlight).bg(theme.highlight_bg).add_modifier(Modifier::BOLD);
let normal_style_in_highlight = Style::default().fg(theme.highlight);
let normal_style_outside = Style::default().fg(theme.fg);
if i >= start_field && i <= end_field { if i >= start_field && i <= end_field {
if start_field == end_field { // This line is within the character-wise highlight range
if start_field == end_field { // Case 1: Single Line Highlight
let safe_start = start_char.min(text_len); let safe_start = start_char.min(text_len);
let safe_end = end_char.min(text_len); let safe_end = end_char.min(text_len);
let before: String = text.chars().take(safe_start).collect(); let before: String = text.chars().take(safe_start).collect();
@@ -123,7 +121,7 @@ pub fn render_canvas(
Span::styled(highlighted, highlight_style), Span::styled(highlighted, highlight_style),
Span::styled(after, normal_style_in_highlight), Span::styled(after, normal_style_in_highlight),
]); ]);
} else if i == start_field { } else if i == start_field { // Case 2: Multi-Line Highlight - Start Line
let safe_start = start_char.min(text_len); let safe_start = start_char.min(text_len);
let before: String = text.chars().take(safe_start).collect(); let before: String = text.chars().take(safe_start).collect();
let highlighted: String = text.chars().skip(safe_start).collect(); let highlighted: String = text.chars().skip(safe_start).collect();
@@ -131,7 +129,7 @@ pub fn render_canvas(
Span::styled(before, normal_style_in_highlight), Span::styled(before, normal_style_in_highlight),
Span::styled(highlighted, highlight_style), Span::styled(highlighted, highlight_style),
]); ]);
} else if i == end_field { } else if i == end_field { // Case 4: Multi-Line Highlight - End Line
let safe_end = end_char.min(text_len); let safe_end = end_char.min(text_len);
let highlighted: String = text.chars().take(safe_end).collect(); let highlighted: String = text.chars().take(safe_end).collect();
let after: String = text.chars().skip(safe_end).collect(); let after: String = text.chars().skip(safe_end).collect();
@@ -139,22 +137,37 @@ pub fn render_canvas(
Span::styled(highlighted, highlight_style), Span::styled(highlighted, highlight_style),
Span::styled(after, normal_style_in_highlight), Span::styled(after, normal_style_in_highlight),
]); ]);
} else { } else { // Case 3: Multi-Line Highlight - Middle Line
line = Line::from(Span::styled(text, highlight_style)); line = Line::from(Span::styled(text, highlight_style)); // Highlight whole line
} }
} else { } else { // Case 5: Line Outside Character-wise Highlight Range
line = Line::from(Span::styled( line = Line::from(Span::styled(
text, text,
if is_active { normal_style_in_highlight } else { normal_style_outside } if is_active { normal_style_in_highlight } else { normal_style_outside }
)); ));
} }
} }
} else { HighlightState::Linewise { anchor_line } => {
line = Line::from(Span::styled( // --- Linewise Highlight Logic ---
text, let start_field = min(*anchor_line, *current_field_idx); // Dereference anchor_line
if is_active { Style::default().fg(theme.highlight) } else { Style::default().fg(theme.fg) } let end_field = max(*anchor_line, *current_field_idx); // Dereference anchor_line
)); let highlight_style = Style::default().fg(theme.highlight).bg(theme.highlight_bg).add_modifier(Modifier::BOLD);
}; let normal_style_in_highlight = Style::default().fg(theme.highlight);
let normal_style_outside = Style::default().fg(theme.fg);
if i >= start_field && i <= end_field {
// Highlight the entire line
line = Line::from(Span::styled(text, highlight_style));
} else {
// Line outside linewise highlight range
line = Line::from(Span::styled(
text,
// Use normal styling (active or inactive)
if is_active { normal_style_in_highlight } else { normal_style_outside }
));
}
}
} // End match highlight_state
let input_display = Paragraph::new(line).alignment(Alignment::Left); let input_display = Paragraph::new(line).alignment(Alignment::Left);
f.render_widget(input_display, input_rows[i]); f.render_widget(input_display, input_rows[i]);
@@ -169,3 +182,4 @@ pub fn render_canvas(
active_field_input_rect active_field_input_rect
} }

View File

@@ -20,6 +20,7 @@ use crate::tui::{
}; };
use crate::state::{ use crate::state::{
app::{ app::{
highlight::HighlightState,
state::AppState, state::AppState,
buffer::{AppView, BufferState}, buffer::{AppView, BufferState},
}, },
@@ -53,9 +54,7 @@ pub struct EventHandler {
pub command_input: String, pub command_input: String,
pub command_message: String, pub command_message: String,
pub is_edit_mode: bool, pub is_edit_mode: bool,
pub is_highlight_mode: bool, pub highlight_state: HighlightState,
pub is_linewise_highlight: bool,
pub highlight_anchor: Option<(usize, usize)>,
pub edit_mode_cooldown: bool, pub edit_mode_cooldown: bool,
pub ideal_cursor_column: usize, pub ideal_cursor_column: usize,
pub key_sequence_tracker: KeySequenceTracker, pub key_sequence_tracker: KeySequenceTracker,
@@ -69,9 +68,7 @@ impl EventHandler {
command_input: String::new(), command_input: String::new(),
command_message: String::new(), command_message: String::new(),
is_edit_mode: false, is_edit_mode: false,
is_highlight_mode: false, highlight_state: HighlightState::Off,
is_linewise_highlight: false,
highlight_anchor: None,
edit_mode_cooldown: false, edit_mode_cooldown: false,
ideal_cursor_column: 0, ideal_cursor_column: 0,
key_sequence_tracker: KeySequenceTracker::new(800), key_sequence_tracker: KeySequenceTracker::new(800),
@@ -220,29 +217,27 @@ impl EventHandler {
AppMode::ReadOnly => { AppMode::ReadOnly => {
// Check for Linewise highlight first // Check for Linewise highlight first
if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise") if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise")
&& ModeManager::can_enter_highlight_mode(current_mode) { && ModeManager::can_enter_highlight_mode(current_mode)
self.is_highlight_mode = true; {
self.is_linewise_highlight = true; // Set linewise flag
let current_field_index = if app_state.ui.show_login { login_state.current_field() } let current_field_index = if app_state.ui.show_login { login_state.current_field() }
else if app_state.ui.show_register { register_state.current_field() } else if app_state.ui.show_register { register_state.current_field() }
else { form_state.current_field() }; else { form_state.current_field() };
// For linewise, anchor char doesn't matter, use 0 self.highlight_state = HighlightState::Linewise { anchor_line: current_field_index };
self.highlight_anchor = Some((current_field_index, 0));
self.command_message = "-- LINE HIGHLIGHT --".to_string(); self.command_message = "-- LINE HIGHLIGHT --".to_string();
return Ok(EventOutcome::Ok(self.command_message.clone())); return Ok(EventOutcome::Ok(self.command_message.clone()));
} }
// Check for Character-wise highlight // Check for Character-wise highlight
else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode") else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode")
&& ModeManager::can_enter_highlight_mode(current_mode) { && ModeManager::can_enter_highlight_mode(current_mode)
self.is_highlight_mode = true; {
self.is_linewise_highlight = false; // Ensure linewise is false
let current_field_index = if app_state.ui.show_login { login_state.current_field() } let current_field_index = if app_state.ui.show_login { login_state.current_field() }
else if app_state.ui.show_register { register_state.current_field() } else if app_state.ui.show_register { register_state.current_field() }
else { form_state.current_field() }; else { form_state.current_field() };
let current_cursor_pos = if app_state.ui.show_login { login_state.current_cursor_pos() } let current_cursor_pos = if app_state.ui.show_login { login_state.current_cursor_pos() }
else if app_state.ui.show_register { register_state.current_cursor_pos() } else if app_state.ui.show_register { register_state.current_cursor_pos() }
else { form_state.current_cursor_pos() }; else { form_state.current_cursor_pos() };
self.highlight_anchor = Some((current_field_index, current_cursor_pos)); let anchor = (current_field_index, current_cursor_pos);
self.highlight_state = HighlightState::Characterwise { anchor };
self.command_message = "-- HIGHLIGHT --".to_string(); self.command_message = "-- HIGHLIGHT --".to_string();
return Ok(EventOutcome::Ok(self.command_message.clone())); return Ok(EventOutcome::Ok(self.command_message.clone()));
} }
@@ -337,9 +332,7 @@ impl EventHandler {
AppMode::Highlight => { AppMode::Highlight => {
if config.get_highlight_action_for_key(key_code, modifiers) == Some("exit_highlight_mode") { if config.get_highlight_action_for_key(key_code, modifiers) == Some("exit_highlight_mode") {
self.is_highlight_mode = false; self.highlight_state = HighlightState::Off;
self.highlight_anchor = None;
self.command_message = "Exited highlight mode".to_string();
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
return Ok(EventOutcome::Ok(self.command_message.clone())); return Ok(EventOutcome::Ok(self.command_message.clone()));
} }

View File

@@ -1,6 +1,7 @@
// src/modes/handlers/mode_manager.rs // src/modes/handlers/mode_manager.rs
use crate::state::app::state::AppState; use crate::state::app::state::AppState;
use crate::modes::handlers::event::EventHandler; use crate::modes::handlers::event::EventHandler;
use crate::state::app::highlight::HighlightState;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AppMode { pub enum AppMode {
@@ -20,7 +21,7 @@ impl ModeManager {
return AppMode::Command; return AppMode::Command;
} }
if event_handler.is_highlight_mode { if !matches!(event_handler.highlight_state, HighlightState::Off) {
return AppMode::Highlight; return AppMode::Highlight;
} }

View File

@@ -2,3 +2,4 @@
pub mod state; pub mod state;
pub mod buffer; pub mod buffer;
pub mod highlight;

View File

@@ -0,0 +1,20 @@
// src/state/app/highlight.rs
/// Represents the different states of text highlighting.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HighlightState {
/// Highlighting is inactive.
Off,
/// Highlighting character by character. Stores the anchor point (line index, char index).
Characterwise { anchor: (usize, usize) },
/// Highlighting line by line. Stores the anchor line index.
Linewise { anchor_line: usize },
}
impl Default for HighlightState {
/// The default state is no highlighting.
fn default() -> Self {
HighlightState::Off
}
}

View File

@@ -2,6 +2,7 @@
use crate::config::colors::themes::Theme; use crate::config::colors::themes::Theme;
use ratatui::layout::Rect; use ratatui::layout::Rect;
use ratatui::Frame; use ratatui::Frame;
use crate::state::app::highlight::HighlightState;
use crate::state::pages::canvas_state::CanvasState; use crate::state::pages::canvas_state::CanvasState;
pub struct FormState { pub struct FormState {
@@ -33,9 +34,7 @@ impl FormState {
area: Rect, area: Rect,
theme: &Theme, theme: &Theme,
is_edit_mode: bool, is_edit_mode: bool,
is_highlight_mode: bool, highlight_state: &HighlightState,
is_linewise_highlight: bool,
highlight_anchor: Option<(usize, usize)>,
total_count: u64, total_count: u64,
current_position: u64, current_position: u64,
) { ) {
@@ -51,9 +50,7 @@ impl FormState {
&values, &values,
theme, theme,
is_edit_mode, is_edit_mode,
is_highlight_mode, highlight_state,
is_linewise_highlight,
highlight_anchor,
total_count, total_count,
current_position, current_position,
); );

View File

@@ -21,6 +21,7 @@ use crate::state::pages::intro::IntroState;
use crate::state::app::buffer::BufferState; use crate::state::app::buffer::BufferState;
use crate::state::app::state::AppState; use crate::state::app::state::AppState;
use crate::state::pages::admin::AdminState; use crate::state::pages::admin::AdminState;
use crate::state::app::highlight::HighlightState;
pub fn render_ui( pub fn render_ui(
f: &mut Frame, f: &mut Frame,
@@ -33,9 +34,7 @@ pub fn render_ui(
buffer_state: &BufferState, buffer_state: &BufferState,
theme: &Theme, theme: &Theme,
is_edit_mode: bool, is_edit_mode: bool,
is_highlight_mode: bool, highlight_state: &HighlightState,
is_linewise_highlight: bool,
highlight_anchor: Option<(usize, usize)>,
total_count: u64, total_count: u64,
current_position: u64, current_position: u64,
current_dir: &str, current_dir: &str,
@@ -95,9 +94,7 @@ pub fn render_ui(
register_state, register_state,
app_state, app_state,
register_state.current_field < 4, register_state.current_field < 4,
is_highlight_mode, highlight_state,
is_linewise_highlight,
highlight_anchor,
); );
} else if app_state.ui.show_login { } else if app_state.ui.show_login {
render_login( render_login(
@@ -107,9 +104,7 @@ pub fn render_ui(
login_state, login_state,
app_state, app_state,
login_state.current_field < 2, login_state.current_field < 2,
is_highlight_mode, highlight_state,
is_linewise_highlight,
highlight_anchor,
); );
} else if app_state.ui.show_admin { } else if app_state.ui.show_admin {
crate::components::admin::admin_panel::render_admin_panel( crate::components::admin::admin_panel::render_admin_panel(
@@ -174,9 +169,7 @@ pub fn render_ui(
&values, &values,
theme, theme,
is_edit_mode, is_edit_mode,
is_highlight_mode, highlight_state,
is_linewise_highlight,
highlight_anchor,
total_count, total_count,
current_position, current_position,
); );

View File

@@ -91,9 +91,7 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
&buffer_state, &buffer_state,
&theme, &theme,
is_edit_mode, is_edit_mode,
event_handler.is_highlight_mode, &event_handler.highlight_state,
event_handler.is_linewise_highlight,
event_handler.highlight_anchor,
app_state.total_count, app_state.total_count,
app_state.current_position, app_state.current_position,
&app_state.current_dir, &app_state.current_dir,