From 89d1c026904dc9dde4c1caffc34d155166a65ebf Mon Sep 17 00:00:00 2001 From: Ian Keane Date: Tue, 25 Nov 2025 20:21:08 -0500 Subject: [PATCH] Fix border wrapping issue --- src/app.rs | 10 +++++----- src/ui.rs | 47 +++++++++++++++++++++++++---------------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/app.rs b/src/app.rs index 07f1804..bab4b65 100644 --- a/src/app.rs +++ b/src/app.rs @@ -86,8 +86,8 @@ impl App { } match self.log_view_grouping { - LogViewGrouping::ByProject => line.starts_with("\t\t"), - LogViewGrouping::ByDate => line.starts_with('\t') && !line.starts_with("\t\t"), + LogViewGrouping::ByProject => line.starts_with(" "), + LogViewGrouping::ByDate => line.starts_with(" ") && !line.starts_with(" "), } } @@ -637,7 +637,7 @@ impl App { if let Some(prev) = prev_stop { let gap = start_local.signed_duration_since(prev); if gap.num_minutes() >= 5 { - lines.push("\t ---".to_string()); + lines.push(" ---".to_string()); // Note: don't add to frame_indices - separator is not an entry } } @@ -663,7 +663,7 @@ impl App { }; let line_text = format!( - "\t{} to {} {:>9} {}", + " {} to {} {:>9} {}", start_time, stop_time, duration_str, display_text ); @@ -763,7 +763,7 @@ impl App { }; lines.push(format!( - "\t\t{} to {} {:>9}{}", + " {} to {} {:>9}{}", start_time, stop_time, duration_str, tags_str )); frame_indices.push(*idx); diff --git a/src/ui.rs b/src/ui.rs index 65065af..d2a1a1f 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -2,7 +2,7 @@ use ratatui::{ layout::{Alignment, Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style}, text::{Line, Span}, - widgets::{Block, Borders, Clear, List, ListItem, Paragraph, Row, Table, TableState}, + widgets::{Block, Borders, Clear, Paragraph, Row, Table, TableState}, Frame, }; @@ -698,8 +698,8 @@ fn render_log_view(frame: &mut Frame, app: &App) { .borders(Borders::ALL) .style(Style::default().fg(ACTIVE_COLOR)); - // Build list items with selection highlighting based on selection level - let items: Vec = { + // Build text lines with selection highlighting based on selection level + let text_lines: Vec = { // Pre-calculate which line indices should be highlighted let mut selected_date = String::new(); let mut selected_project = String::new(); @@ -715,17 +715,17 @@ fn render_log_view(frame: &mut Frame, app: &App) { let is_by_project = matches!(app.log_view_grouping, LogViewGrouping::ByProject); for (_idx, line) in app.log_view_content.iter().enumerate() { - if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { + if !line.starts_with(" ") && !line.is_empty() && !line.starts_with(" ") { current_date = line.clone(); - } else if line.starts_with(" ") && !line.starts_with("\t") { + } else if line.starts_with(" ") && !line.starts_with(" ") { current_project = line.clone(); } // Only count actual entries (not all tab-indented lines) let is_entry = if is_by_project { - line.starts_with("\t\t") // Double tab for ByProject + line.starts_with(" ") // 8 spaces for ByProject } else { - line.starts_with('\t') && !line.starts_with("\t\t") // Single tab for ByDate + line.starts_with(" ") && !line.starts_with(" ") // 4 spaces for ByDate }; if is_entry { @@ -746,9 +746,9 @@ fn render_log_view(frame: &mut Frame, app: &App) { for (idx, line) in app.log_view_content.iter().enumerate() { // Use is_entry_line logic which excludes separator lines let is_entry = if is_by_project { - line.starts_with("\t\t") + line.starts_with(" ") } else { - line.starts_with('\t') && !line.starts_with("\t\t") && line.trim() != "---" + line.starts_with(" ") && !line.starts_with(" ") && line.trim() != "---" }; if is_entry { @@ -767,19 +767,19 @@ fn render_log_view(frame: &mut Frame, app: &App) { current_date = String::new(); for (idx, line) in app.log_view_content.iter().enumerate() { - if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { + if !line.starts_with(" ") && !line.is_empty() && !line.starts_with(" ") { current_date = line.clone(); if in_target_project { break; // End of project group } - } else if line.starts_with(" ") && !line.starts_with("\t") { + } else if line.starts_with(" ") && !line.starts_with(" ") { if current_date == selected_date && line == &selected_project { selected_line_start = idx; in_target_project = true; } else if in_target_project { break; // Different project } - } else if in_target_project && line.starts_with('\t') { + } else if in_target_project && line.starts_with(" ") { selected_line_end = idx; } } @@ -789,7 +789,7 @@ fn render_log_view(frame: &mut Frame, app: &App) { let mut in_target_day = false; for (idx, line) in app.log_view_content.iter().enumerate() { - if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { + if !line.starts_with(" ") && !line.is_empty() && !line.starts_with(" ") { if line == &selected_date { selected_line_start = idx; in_target_day = true; @@ -820,17 +820,17 @@ fn render_log_view(frame: &mut Frame, app: &App) { for (line_idx, line) in app.log_view_content.iter().enumerate() { // New day header - if !line.starts_with('\t') && !line.is_empty() && !line.starts_with(" ") { + if !line.starts_with(" ") && !line.is_empty() && !line.starts_with(" ") { current_day_start_entry = app.log_view_content[..line_idx] .iter() - .filter(|l| l.starts_with('\t') && !l.is_empty() && l.trim() != "---") + .filter(|l| l.starts_with(" ") && !l.is_empty() && l.trim() != "---") .count(); in_day = true; - } else if in_day && line.starts_with('\t') && !line.is_empty() && line.trim() != "---" { + } else if in_day && line.starts_with(" ") && !line.is_empty() && line.trim() != "---" { // This is an entry line let entry_idx = app.log_view_content[..=line_idx] .iter() - .filter(|l| l.starts_with('\t') && !l.is_empty() && l.trim() != "---") + .filter(|l| l.starts_with(" ") && !l.is_empty() && l.trim() != "---") .count() .saturating_sub(1); @@ -868,12 +868,12 @@ fn render_log_view(frame: &mut Frame, app: &App) { let is_separator = line.trim() == "---"; // Check if this line corresponds to an overlapping entry - let has_overlap = if !is_separator && is_by_date && line.starts_with('\t') && !line.is_empty() { + let has_overlap = if !is_separator && is_by_date && line.starts_with(" ") && !line.is_empty() { // Count which entry this is (0-based in display order) // Only count actual entry lines, not separator lines let entry_idx = app.log_view_content[..=idx] .iter() - .filter(|l| l.starts_with('\t') && !l.is_empty() && l.trim() != "---") + .filter(|l| l.starts_with(" ") && !l.is_empty() && l.trim() != "---") .count() .saturating_sub(1); @@ -894,13 +894,16 @@ fn render_log_view(frame: &mut Frame, app: &App) { Style::default().fg(Color::White) }; - ListItem::new(Line::from(vec![Span::styled(line.clone(), style)])) + Line::from(vec![Span::styled(line.clone(), style)]) }) .collect() }; - let list = List::new(items).block(block); - frame.render_widget(list, chunks[0]); + let paragraph = Paragraph::new(text_lines) + .block(block) + .wrap(ratatui::widgets::Wrap { trim: false }); + + frame.render_widget(paragraph, chunks[0]); // Render help hint at bottom if enabled if app.config.show_help_hint {