fix insert_history modifier handling (#1774)

This fixes a bug in insert_history_lines where writing
`Line::From(vec!["A".bold(), "B".into()])` would write "B" as bold,
because "B" didn't explicitly subtract bold.
This commit is contained in:
Jeremy Rose
2025-08-01 10:37:43 -07:00
committed by GitHub
parent f918198bbb
commit 8360c6a3ec
2 changed files with 52 additions and 25 deletions

View File

@@ -545,24 +545,17 @@ impl HistoryCell {
} else { } else {
for (idx, PlanItemArg { step, status }) in plan.into_iter().enumerate() { for (idx, PlanItemArg { step, status }) in plan.into_iter().enumerate() {
let num = idx + 1; let num = idx + 1;
let (icon, style): (&str, Style) = match status { let icon_span: Span = match status {
StepStatus::Completed => ("", Style::default().fg(Color::Green)), StepStatus::Completed => Span::from("").fg(Color::Green),
StepStatus::InProgress => ( StepStatus::InProgress => Span::from("").fg(Color::Yellow).bold(),
"", StepStatus::Pending => Span::from("").fg(Color::Gray),
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD),
),
StepStatus::Pending => ("", Style::default().fg(Color::Gray)),
}; };
let prefix = vec![ lines.push(Line::from(vec![
Span::raw(format!("{num:>2}. [")), format!("{num:>2}. [").into(),
Span::styled(icon.to_string(), style), icon_span,
Span::raw("] "), "] ".into(),
]; step.into(),
let mut spans = prefix; ]));
spans.push(Span::raw(step));
lines.push(Line::from(spans));
} }
} }

View File

@@ -216,18 +216,18 @@ where
{ {
let mut fg = Color::Reset; let mut fg = Color::Reset;
let mut bg = Color::Reset; let mut bg = Color::Reset;
let mut modifier = Modifier::empty(); let mut last_modifier = Modifier::empty();
for span in content { for span in content {
let mut next_modifier = modifier; let mut modifier = Modifier::empty();
next_modifier.insert(span.style.add_modifier); modifier.insert(span.style.add_modifier);
next_modifier.remove(span.style.sub_modifier); modifier.remove(span.style.sub_modifier);
if next_modifier != modifier { if modifier != last_modifier {
let diff = ModifierDiff { let diff = ModifierDiff {
from: modifier, from: last_modifier,
to: next_modifier, to: modifier,
}; };
diff.queue(&mut writer)?; diff.queue(&mut writer)?;
modifier = next_modifier; last_modifier = modifier;
} }
let next_fg = span.style.fg.unwrap_or(Color::Reset); let next_fg = span.style.fg.unwrap_or(Color::Reset);
let next_bg = span.style.bg.unwrap_or(Color::Reset); let next_bg = span.style.bg.unwrap_or(Color::Reset);
@@ -250,3 +250,37 @@ where
SetAttribute(crossterm::style::Attribute::Reset), SetAttribute(crossterm::style::Attribute::Reset),
) )
} }
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
#[test]
fn writes_bold_then_regular_spans() {
use ratatui::style::Stylize;
let spans = ["A".bold(), "B".into()];
let mut actual: Vec<u8> = Vec::new();
write_spans(&mut actual, spans.iter()).unwrap();
let mut expected: Vec<u8> = Vec::new();
queue!(
expected,
SetAttribute(crossterm::style::Attribute::Bold),
Print("A"),
SetAttribute(crossterm::style::Attribute::NormalIntensity),
Print("B"),
SetForegroundColor(CColor::Reset),
SetBackgroundColor(CColor::Reset),
SetAttribute(crossterm::style::Attribute::Reset),
)
.unwrap();
assert_eq!(
String::from_utf8(actual).unwrap(),
String::from_utf8(expected).unwrap()
);
}
}