fix: keep a space between overview words that span a line break

The collapsed one-line overview on the Lidarr artist, Sonarr series, and Readarr author details views replaced every line break and tab with an empty string. Words on either side of a paragraph break fused together, rendering as "20th century.She was born in Ohio".

Collapse each run of whitespace to a single space instead, and trim the result. Handling a whole run at a time keeps a Windows line ending, an indented paragraph, or a space that already precedes a line break from producing two spaces.

The overview popups are unaffected: they receive the raw text and keep their paragraph breaks.
This commit is contained in:
Dark-Alex-17 committed 2026-09-10 13:27:02 -06:00
1 parent caafe1602e
commit 243b22a426
12 files changed
+92 -44

No files matched your search

@@ -269,7 +269,7 @@ impl ReadarrData<'_> {
overview: Some(
"some interesting description of the author\r\n\
\r\n\
He was born in Madison, Wisconsin: a city he has never really left.\r\n\
\tHe was born in Madison, Wisconsin: a city he has never really left. \r\n\
\r\n\
His first novel took him seven years to finish.\r\n"
.to_owned(),
@@ -97,7 +97,7 @@ mod tests {
"artistName": "Alex",
"foreignArtistId": "test-foreign-id",
"status": "continuing",
"overview": "some interesting description of the artist\r\n\r\nShe was born in Madison, Wisconsin: a city she has never really left.\r\n\r\nHer first album took her seven years to finish.\r\n",
"overview": "some interesting description of the artist\r\n\r\n\tShe was born in Madison, Wisconsin: a city she has never really left. \r\n\r\nHer first album took her seven years to finish.\r\n",
"artistType": "Person",
"disambiguation": "American pianist",
"path": "/nfs/music/test-artist",
@@ -136,7 +136,7 @@ mod tests {
"artistName": "Alex",
"foreignArtistId": "test-foreign-id",
"status": "continuing",
"overview": "some interesting description of the artist\r\n\r\nShe was born in Madison, Wisconsin: a city she has never really left.\r\n\r\nHer first album took her seven years to finish.\r\n",
"overview": "some interesting description of the artist\r\n\r\n\tShe was born in Madison, Wisconsin: a city she has never really left. \r\n\r\nHer first album took her seven years to finish.\r\n",
"artistType": "Person",
"disambiguation": "American pianist",
"path": "/nfs/music/test-artist",
@@ -248,7 +248,7 @@ mod tests {
"artistName": "Alex",
"foreignArtistId": "test-foreign-id",
"status": "continuing",
"overview": "some interesting description of the artist\r\n\r\nShe was born in Madison, Wisconsin: a city she has never really left.\r\n\r\nHer first album took her seven years to finish.\r\n",
"overview": "some interesting description of the artist\r\n\r\n\tShe was born in Madison, Wisconsin: a city she has never really left. \r\n\r\nHer first album took her seven years to finish.\r\n",
"artistType": "Person",
"disambiguation": "American pianist",
"path": "/nfs/music/test-artist",
@@ -286,7 +286,7 @@ mod tests {
"artistName": "Alex",
"foreignArtistId": "test-foreign-id",
"status": "continuing",
"overview": "some interesting description of the artist\r\n\r\nShe was born in Madison, Wisconsin: a city she has never really left.\r\n\r\nHer first album took her seven years to finish.\r\n",
"overview": "some interesting description of the artist\r\n\r\n\tShe was born in Madison, Wisconsin: a city she has never really left. \r\n\r\nHer first album took her seven years to finish.\r\n",
"artistType": "Person",
"disambiguation": "American pianist",
"path": "/nfs/music/test-artist",
@@ -113,7 +113,7 @@ pub mod test_utils {
overview: Some(
"some interesting description of the artist\r\n\
\r\n\
She was born in Madison, Wisconsin: a city she has never really left.\r\n\
\tShe was born in Madison, Wisconsin: a city she has never really left. \r\n\
\r\n\
Her first album took her seven years to finish.\r\n"
.to_owned(),
@@ -19,7 +19,7 @@ pub mod test_utils {
"title": "Test",
"status": "continuing",
"ended": false,
"overview": "Blah blah blah\r\n\r\nIt was filmed in Madison, Wisconsin: a city the crew never really left.\r\n\r\nThe first season took seven years to finish.\r\n",
"overview": "Blah blah blah\r\n\r\n\tIt was filmed in Madison, Wisconsin: a city the crew never really left. \r\n\r\nThe first season took seven years to finish.\r\n",
"network": "HBO",
"seasons": [
{
@@ -322,7 +322,7 @@ pub mod test_utils {
overview: Some(
"Blah blah blah\r\n\
\r\n\
It was filmed in Madison, Wisconsin: a city the crew never really left.\r\n\
\tIt was filmed in Madison, Wisconsin: a city the crew never really left. \r\n\
\r\n\
The first season took seven years to finish.\r\n"
.to_owned(),
+4 -10
View File
@@ -5,7 +5,6 @@ use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
use regex::Regex;
use crate::app::App;
use crate::models::Route;
@@ -18,7 +17,8 @@ use crate::ui::lidarr_ui::lidarr_ui_utils::create_history_event_details;
use crate::ui::styles::{ManagarrStyle, secondary_style};
use crate::ui::utils::decorate_peer_style;
use crate::ui::utils::{
borderless_block, get_width_from_percentage, layout_block_top_border, title_block,
borderless_block, collapse_whitespace, get_width_from_percentage, layout_block_top_border,
title_block,
};
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::loading_block::LoadingBlock;
@@ -153,18 +153,12 @@ fn draw_artist_description(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.get_by_left(&current_selection.metadata_profile_id)
.cloned()
.unwrap_or_default();
let overview = Regex::new(r"[\r\n\t]")
.unwrap()
.replace_all(
&deunicode(
let overview = collapse_whitespace(&deunicode(
current_selection
.overview
.as_ref()
.unwrap_or(&String::new()),
),
"",
)
.to_string();
));
let mut artist_description = vec![
Line::from(vec![
+4 -10
View File
@@ -5,7 +5,6 @@ use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
use regex::Regex;
use crate::app::App;
use crate::models::Route;
@@ -20,7 +19,8 @@ use crate::ui::readarr_ui::readarr_ui_utils::create_history_event_details;
use crate::ui::styles::{ManagarrStyle, secondary_style};
use crate::ui::utils::decorate_peer_style;
use crate::ui::utils::{
borderless_block, get_width_from_percentage, layout_block_top_border, title_block,
borderless_block, collapse_whitespace, get_width_from_percentage, layout_block_top_border,
title_block,
};
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::loading_block::LoadingBlock;
@@ -165,18 +165,12 @@ fn draw_author_description(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.get_by_left(&current_selection.metadata_profile_id)
.cloned()
.unwrap_or_default();
let overview = Regex::new(r"[\r\n\t]")
.unwrap()
.replace_all(
&deunicode(
let overview = collapse_whitespace(&deunicode(
current_selection
.overview
.as_ref()
.unwrap_or(&String::new()),
),
"",
)
.to_string();
));
let mut author_description = vec![
Line::from(vec![
@@ -14,7 +14,7 @@ expression: output
│Quality Pro│He was born in Madison, Wisconsin: a city he has never really left. │ │
│Metadata Pr│ │ │
│Monitored: │His first novel took him seven years to finish. │ │
│Overview: s│ │took him │
│Overview: s│ │l took him │
│seven years│ │ │
│ │ │ │
│ │ │ │
@@ -14,7 +14,7 @@ expression: output
│Qual│ │ │
│Meta│ │ │
│Moni│ │ │
│Over│ │im │
│Over│ │ him │
│seve│ │ │
│ │ │ │
│ │ │ │
@@ -14,7 +14,7 @@ expression: output
│Quality Profile: St│ │ │
│Metadata Profile: C│ │ │
│Monitored: Yes │ │ │
│Overview: some inte│ │st novel took him │
│Overview: some inte│ │irst novel took him │
│seven years to fini│ │ │
│ │ │ │
│ │ ╭───╮ │ │
+4 -10
View File
@@ -6,7 +6,6 @@ use ratatui::layout::{Alignment, Constraint, Layout, Rect};
use ratatui::style::Stylize;
use ratatui::text::{Line, Text};
use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
use regex::Regex;
use crate::app::App;
use crate::models::Route;
@@ -18,7 +17,8 @@ use crate::ui::sonarr_ui::library::series_overview_ui::SeriesOverviewUi;
use crate::ui::sonarr_ui::sonarr_ui_utils::create_history_event_details;
use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{
borderless_block, get_width_from_percentage, layout_block_top_border, title_block,
borderless_block, collapse_whitespace, get_width_from_percentage, layout_block_top_border,
title_block,
};
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::loading_block::LoadingBlock;
@@ -138,18 +138,12 @@ fn draw_series_description(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.get_by_left(&current_selection.language_profile_id)
.unwrap()
.to_owned();
let overview = Regex::new(r"[\r\n\t]")
.unwrap()
.replace_all(
&deunicode(
let overview = collapse_whitespace(&deunicode(
current_selection
.overview
.as_ref()
.unwrap_or(&String::new()),
),
"",
)
.to_string();
));
let mut series_description = vec![
Line::from(vec![
+10
View File
@@ -9,8 +9,10 @@ use ratatui::layout::{Alignment, Constraint, Layout, Rect};
use ratatui::style::{Style, Stylize};
use ratatui::text::{Line, Span, Text};
use ratatui::widgets::{Block, BorderType, Borders, LineGauge, ListItem, Paragraph, Wrap};
use regex::Regex;
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use std::sync::OnceLock;
#[cfg(test)]
#[path = "utils_tests.rs"]
@@ -184,6 +186,14 @@ pub(super) fn decorate_peer_style(seeders: u64, leechers: u64, text: Text<'_>) -
}
}
static WHITESPACE_RE: OnceLock<Regex> = OnceLock::new();
pub(super) fn collapse_whitespace(text: &str) -> String {
let re = WHITESPACE_RE.get_or_init(|| Regex::new(r"\s+").unwrap());
re.replace_all(text.trim(), " ").to_string()
}
pub(super) fn extract_monitored_root_folders(
app: &App<'_>,
root_folders: Vec<RootFolder>,
+59 -3
View File
@@ -4,9 +4,9 @@ mod test {
use crate::models::servarr_models::{DiskSpace, RootFolder};
use crate::ui::styles::{ManagarrStyle, default_style, failure_style, secondary_style};
use crate::ui::utils::{
borderless_block, centered_rect, convert_to_minutes_hours_days, decorate_peer_style,
extract_monitored_disk_space_vec, extract_monitored_root_folders, get_width_from_percentage,
layout_block, layout_block_bottom_border, layout_block_top_border,
borderless_block, centered_rect, collapse_whitespace, convert_to_minutes_hours_days,
decorate_peer_style, extract_monitored_disk_space_vec, extract_monitored_root_folders,
get_width_from_percentage, layout_block, layout_block_bottom_border, layout_block_top_border,
layout_block_top_border_with_title, layout_block_with_title, logo_block, style_block_highlight,
style_log_list_item, title_block, title_block_centered, title_style, unstyled_title_block,
};
@@ -254,6 +254,62 @@ mod test {
assert_str_eq!(convert_to_minutes_hours_days(2880), "2 days");
}
#[test]
fn test_collapse_whitespace_replaces_a_line_break_with_a_single_space() {
assert_str_eq!(
collapse_whitespace("the 20th century.\nShe was born in Ohio"),
"the 20th century. She was born in Ohio"
);
}
#[test]
fn test_collapse_whitespace_collapses_a_carriage_return_line_feed_to_a_single_space() {
assert_str_eq!(
collapse_whitespace("the 20th century.\r\nShe was born in Ohio"),
"the 20th century. She was born in Ohio"
);
}
#[test]
fn test_collapse_whitespace_collapses_a_blank_line_and_indentation_to_a_single_space() {
assert_str_eq!(
collapse_whitespace("the 20th century.\r\n\r\n\tShe was born in Ohio"),
"the 20th century. She was born in Ohio"
);
}
#[test]
fn test_collapse_whitespace_does_not_double_a_space_that_precedes_a_line_break() {
assert_str_eq!(
collapse_whitespace("the 20th century. \r\nShe was born in Ohio"),
"the 20th century. She was born in Ohio"
);
}
#[test]
fn test_collapse_whitespace_replaces_a_tab_with_a_single_space() {
assert_str_eq!(
collapse_whitespace("the 20th century.\tShe was born in Ohio"),
"the 20th century. She was born in Ohio"
);
}
#[test]
fn test_collapse_whitespace_trims_surrounding_whitespace() {
assert_str_eq!(
collapse_whitespace("\r\n the 20th century.\r\n"),
"the 20th century."
);
}
#[test]
fn test_collapse_whitespace_leaves_single_spaced_text_unchanged() {
assert_str_eq!(
collapse_whitespace("the 20th century. She was born in Ohio"),
"the 20th century. She was born in Ohio"
);
}
#[rstest]
#[case(0, 0, PeerStyle::Failure)]
#[case(1, 2, PeerStyle::Warning)]