From 415bc2044d30d44bf2fe7c8b6350b26656bd3604 Mon Sep 17 00:00:00 2001 From: filipriec Date: Tue, 15 Apr 2025 23:07:55 +0200 Subject: [PATCH] highlight through many lines working --- client/config.toml | 1 + client/src/components/handlers/canvas.rs | 104 ++++++++++++++++------- 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/client/config.toml b/client/config.toml index a2433d8..3edda0c 100644 --- a/client/config.toml +++ b/client/config.toml @@ -56,6 +56,7 @@ enter_highlight_mode = ["v"] exit_highlight_mode = ["esc"] [keybindings.edit] +# BIG CHANGES NOW EXIT HANDLES EITHER IF THOSE # exit_edit_mode = ["esc","ctrl+e"] # exit_suggestion_mode = ["esc"] exit = ["esc", "ctrl+e"] diff --git a/client/src/components/handlers/canvas.rs b/client/src/components/handlers/canvas.rs index 23d1cd4..89b210e 100644 --- a/client/src/components/handlers/canvas.rs +++ b/client/src/components/handlers/canvas.rs @@ -9,13 +9,14 @@ use ratatui::{ }; use crate::config::colors::themes::Theme; use crate::state::pages::canvas_state::CanvasState; +use std::cmp::{min, max}; // Import min and max pub fn render_canvas( f: &mut Frame, area: Rect, form_state: &impl CanvasState, fields: &[&str], - current_field: &usize, + current_field_idx: &usize, // Renamed for clarity inputs: &[&String], theme: &Theme, is_edit_mode: bool, @@ -76,45 +77,83 @@ pub fn render_canvas( // Render inputs and cursor for (i, input) in inputs.iter().enumerate() { - let is_active = i == *current_field; + let is_active = i == *current_field_idx; let current_cursor_pos = form_state.current_cursor_pos(); + let text = input.as_str(); + let text_len = text.chars().count(); - let line = if is_highlight_mode && highlight_anchor.is_some() { + let line: Line; // Determine the line content with spans + + if is_highlight_mode && highlight_anchor.is_some() { let (anchor_field, anchor_char) = highlight_anchor.unwrap(); - if i == anchor_field && i == *current_field { // Highlight within the same field - let start = anchor_char.min(current_cursor_pos); - let end = anchor_char.max(current_cursor_pos); - let text = input.as_str(); - let len = text.chars().count(); + // Determine the actual start and end fields/chars for rendering + let start_field = min(anchor_field, *current_field_idx); + let end_field = max(anchor_field, *current_field_idx); - // Ensure start and end are within bounds - let safe_start = start.min(len); - let safe_end = end.min(len); - - let before: String = text.chars().take(safe_start).collect(); - let highlighted: String = text.chars().skip(safe_start).take(safe_end - safe_start).collect(); - let after: String = text.chars().skip(safe_end).collect(); - - Line::from(vec![ - Span::styled(before, Style::default().fg(theme.fg)), - Span::styled( - highlighted, - Style::default().fg(theme.highlight).bg(theme.highlight_bg).add_modifier(Modifier::BOLD) - ), - Span::styled(after, Style::default().fg(theme.fg)), - ]) + let (start_char, end_char) = if anchor_field == *current_field_idx { + // Single line selection + (min(anchor_char, current_cursor_pos), max(anchor_char, current_cursor_pos)) + } else if anchor_field < *current_field_idx { + // Anchor is above cursor + (anchor_char, current_cursor_pos) } else { - // Field is not the anchor or not the current field during highlight - // Render normally for now (could extend to multi-line later) - Line::from(Span::styled(input.as_str(), Style::default().fg(theme.fg))) + // Anchor is below cursor + (current_cursor_pos, anchor_char) + }; + + // Style for highlighted text + let highlight_style = Style::default().fg(theme.highlight).bg(theme.highlight_bg).add_modifier(Modifier::BOLD); + // Style for normal text within the highlight range (active field color) + let normal_style_in_highlight = Style::default().fg(theme.highlight); + // Style for normal text outside highlight range (inactive field color) + let normal_style_outside = Style::default().fg(theme.fg); + + if i >= start_field && i <= end_field { + // This line is within the highlight range + + if start_field == end_field { // Case 1: Single Line Highlight + let safe_start = start_char.min(text_len); + let safe_end = end_char.min(text_len); + let before: String = text.chars().take(safe_start).collect(); + let highlighted: String = text.chars().skip(safe_start).take(safe_end - safe_start).collect(); + let after: String = text.chars().skip(safe_end).collect(); + line = Line::from(vec![ + Span::styled(before, normal_style_in_highlight), + Span::styled(highlighted, highlight_style), + Span::styled(after, normal_style_in_highlight), + ]); + } else if i == start_field { // Case 2: Multi-Line Highlight - Start Line + let safe_start = start_char.min(text_len); + let before: String = text.chars().take(safe_start).collect(); + let highlighted: String = text.chars().skip(safe_start).collect(); + line = Line::from(vec![ + Span::styled(before, normal_style_in_highlight), // Use active color before highlight starts + Span::styled(highlighted, highlight_style), + ]); + } else if i == end_field { // Case 4: Multi-Line Highlight - End Line + let safe_end = end_char.min(text_len); + let highlighted: String = text.chars().take(safe_end).collect(); + let after: String = text.chars().skip(safe_end).collect(); + line = Line::from(vec![ + Span::styled(highlighted, highlight_style), + Span::styled(after, normal_style_in_highlight), // Use active color after highlight ends + ]); + } else { // Case 3: Multi-Line Highlight - Middle Line + line = Line::from(Span::styled(text, highlight_style)); // Highlight whole line + } + } else { // Case 5: Line Outside Highlight Range + line = Line::from(Span::styled( + text, + if is_active { normal_style_in_highlight } else { normal_style_outside } + )); } } else { // Not in highlight mode, render normally - Line::from(Span::styled( - input.as_str(), + line = Line::from(Span::styled( + text, if is_active { Style::default().fg(theme.highlight) } else { Style::default().fg(theme.fg) } - )) + )); }; let input_display = Paragraph::new(line) @@ -123,8 +162,8 @@ pub fn render_canvas( if is_active { active_field_input_rect = Some(input_rows[i]); - // Cursor position calculation remains the same - let cursor_x = input_rows[i].x + current_cursor_pos as u16; + // Set cursor position (using current_field_idx directly) + let cursor_x = input_rows[i].x + form_state.current_cursor_pos() as u16; let cursor_y = input_rows[i].y; f.set_cursor_position((cursor_x, cursor_y)); } @@ -132,3 +171,4 @@ pub fn render_canvas( active_field_input_rect } +