From db570abd96ad3ee52156895645957af0357bab8d Mon Sep 17 00:00:00 2001 From: Andreas Tsouchlos Date: Mon, 29 Dec 2025 23:03:37 +0200 Subject: [PATCH] Implement proper title wrapping --- src/ui.rs | 140 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 105 insertions(+), 35 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index 4f22d96..bea73bd 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,5 +1,3 @@ -use std::fmt::format; - use crate::{ app::{ActivePane, App}, snowballing::Publication, @@ -7,14 +5,9 @@ use crate::{ use ratatui::{ Frame, layout::{Constraint, Direction, Layout, Rect}, - style::{ - Color, Modifier, Style, Stylize, palette::material::AccentedPalette, - }, + style::{Color, Modifier, Style, Stylize}, text::{Line, Span}, - widgets::{ - Block, Borders, List, ListItem, Scrollbar, ScrollbarOrientation, - ScrollbarState, - }, + widgets::{Block, Borders, List, ListItem}, }; pub fn draw(f: &mut Frame, app: &mut App) { @@ -27,6 +20,91 @@ pub fn draw(f: &mut Frame, app: &mut App) { draw_right_pane(f, app, chunks[1]); } +fn format_title<'a>( + idx: usize, + title: &Option, + year: &Option, + available_width: usize, + is_selected: bool, +) -> Vec> { + let idx_text = format!("[{}]", idx + 1); + let title_text = + title.clone().unwrap_or("[No title available]".to_string()); + let year_text = year + .map(|val| format!("({})", val)) + .unwrap_or("[unknown]".to_string()); + + let wrapped = textwrap::fill( + &format!("{} {} {}", idx_text, title_text, year_text), + available_width, + ); + + let lines: Vec<&str> = wrapped.lines().collect(); + + let mut result = Vec::::new(); + + let (border_char, border_style) = if is_selected { + ( + "┃ ", + Style::default() + .fg(Color::Gray) + .add_modifier(Modifier::BOLD), + ) + } else { + (" ", Style::default()) + }; + + if lines.len() == 1 { + let line = lines[0]; + + result.push(Line::from(vec![ + Span::styled(border_char, border_style), + Span::styled( + line[0..idx_text.len()].to_string(), + Style::default().fg(Color::DarkGray), + ), + Span::raw( + line[idx_text.len()..line.len() - year_text.len()].to_string(), + ), + Span::styled( + line[line.len() - year_text.len()..].to_string(), + Style::default().fg(Color::Yellow), + ), + ])); + } else { + let first_line = lines[0]; + let middle_lines = &lines[1..lines.len() - 1]; + let last_line = lines[lines.len() - 1]; + + result.push(Line::from(vec![ + Span::styled(border_char, border_style), + Span::styled( + first_line[0..idx_text.len()].to_string(), + Style::default().fg(Color::DarkGray), + ), + Span::raw(first_line[idx_text.len()..].to_string()), + ])); + for line in middle_lines { + result.push(Line::from(vec![ + Span::styled(border_char, border_style), + Span::raw(line.to_string()), + ])); + } + result.push(Line::from(vec![ + Span::styled(border_char, border_style), + Span::raw( + last_line[..last_line.len() - year_text.len()].to_string(), + ), + Span::styled( + last_line[last_line.len() - year_text.len()..].to_string(), + Style::default().fg(Color::Yellow), + ), + ])); + } + + result +} + fn create_publication_item_list( publications: &Vec, selected_idx: Option, @@ -50,31 +128,23 @@ fn create_publication_item_list( (" ", Style::default()) }; - let mut lines = vec![ - Line::from(vec![ - Span::styled(border_char, border_style), - Span::raw(format!("[{}] ", idx + 1)), - Span::raw( - publ.get_title() - .unwrap_or("[No title available]".to_string()), - ), - Span::styled( - format!( - " ({})", - publ.publication_year - .map_or("".to_string(), |val| val.to_string()) - ), - Style::default().fg(Color::Yellow), - ), - ]), - Line::from(vec![ - Span::styled(border_char, border_style), - Span::styled( - publ.get_author_text(), - Style::default().fg(Color::Blue), - ), - ]), - ]; + let mut lines = Vec::::new(); + + lines.append(&mut format_title( + idx, + &publ.get_title(), + &publ.get_year(), + available_width, + is_selected, + )); + + lines.push(Line::from(vec![ + Span::styled(border_char, border_style), + Span::styled( + publ.get_author_text(), + Style::default().fg(Color::Blue), + ), + ])); if show_abstract { let wrapped = textwrap::fill( @@ -151,7 +221,7 @@ fn draw_left_pane(frame: &mut Frame, app: &mut App, area: Rect) { Span::raw("Step: "), Span::styled( app.snowballing_step.to_string(), - Style::default().fg(Color::Yellow), + Style::default().fg(Color::Cyan), ), ]), ];