Skip to content

Commit 9b65729

Browse files
authored
fix(tui): highlight session config values only (#484)
## Summary 🤖 Generated with [Nori](https://noriagentic.com/) - Render ACP session-config history assignments as `Name=` plus a separately highlighted value span. - Covers startup, update, and option-set history cells so `Mode=Default` and `Model=...` leave the name/separator plain. - Remove the earlier unrelated MCP argument styling change from this PR. ## Test Plan - [x] `RUSTC_WRAPPER= cargo test -p nori-tui nori::session_config_history::tests::history_cells_highlight_values_not_names` - [x] `RUSTC_WRAPPER= cargo test -p nori-tui` - [x] `RUSTC_WRAPPER= cargo build --bin nori` - [x] `RUSTC_WRAPPER= cargo test -p tui-pty-e2e` - [x] `just fmt` - [x] `RUSTC_WRAPPER= just fix -p nori-tui` - [x] `RUSTC_WRAPPER= cargo insta pending-snapshots --manifest-path tui/Cargo.toml` - [x] `git diff --check` - [x] TUI smoke via tmux with ElizACP config Share Nori with your team: https://www.npmjs.com/package/nori-skillsets
1 parent 8273185 commit 9b65729

2 files changed

Lines changed: 100 additions & 5 deletions

File tree

nori-rs/tui/src/nori/session_config_history.rs

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::collections::BTreeMap;
55
use nori_acp as acp;
66
use ratatui::style::Stylize;
77
use ratatui::text::Line;
8+
use ratatui::text::Span;
89

910
use crate::history_cell::PlainHistoryCell;
1011

@@ -59,7 +60,7 @@ pub(crate) fn new_agent_options_initial_history_cell(
5960
if index > 0 {
6061
line.push(", ".into());
6162
}
62-
line.push(format!("{}={}", value.name, value.value).cyan().bold());
63+
line.extend(option_assignment_spans(&value.name, &value.value));
6364
}
6465
line.push(" (/config to change)".dim());
6566

@@ -89,7 +90,7 @@ pub(crate) fn new_agent_options_history_cell(
8990
if index > 0 {
9091
line.push(", ".into());
9192
}
92-
line.push(format!("{}={}", change.name, change.value).cyan().bold());
93+
line.extend(option_assignment_spans(&change.name, &change.value));
9394
}
9495

9596
PlainHistoryCell::new(vec![Line::from(line)])
@@ -105,11 +106,21 @@ pub(crate) fn new_agent_option_set_history_cell(
105106
} else {
106107
agent_display_name
107108
};
108-
PlainHistoryCell::new(vec![Line::from(vec![
109+
let mut line = vec![
109110
"• ".dim(),
110111
format!("{agent_display_name} option set: ").into(),
111-
format!("{option_name}={value_name}").cyan().bold(),
112-
])])
112+
];
113+
line.extend(option_assignment_spans(option_name, value_name));
114+
115+
PlainHistoryCell::new(vec![Line::from(line)])
116+
}
117+
118+
fn option_assignment_spans(name: &str, value: &str) -> Vec<Span<'static>> {
119+
vec![
120+
name.to_string().into(),
121+
"=".into(),
122+
value.to_string().cyan().bold(),
123+
]
113124
}
114125

115126
fn display_value(option: &acp::SessionConfigOption) -> Option<SessionConfigDisplayValue> {
@@ -136,3 +147,78 @@ fn display_value(option: &acp::SessionConfigOption) -> Option<SessionConfigDispl
136147
value,
137148
})
138149
}
150+
151+
#[cfg(test)]
152+
mod tests {
153+
use pretty_assertions::assert_eq;
154+
use ratatui::style::Color;
155+
use ratatui::style::Modifier;
156+
use ratatui::style::Style;
157+
158+
use super::*;
159+
use crate::history_cell::HistoryCell;
160+
161+
#[test]
162+
fn history_cells_highlight_values_not_names() {
163+
let cell = new_agent_options_initial_history_cell(
164+
"Claude Code",
165+
&[acp::SessionConfigOption::select(
166+
"mode",
167+
"Mode",
168+
"default",
169+
vec![acp::SessionConfigSelectOption::new("default", "Default")],
170+
)],
171+
);
172+
173+
let lines = cell.display_lines(80);
174+
assert_value_highlighted(&lines[0].spans, "Mode", "Default");
175+
176+
let cell = new_agent_options_history_cell(
177+
"Claude Code",
178+
&[SessionConfigDisplayValue {
179+
name: "Effort".to_string(),
180+
value: "High".to_string(),
181+
}],
182+
);
183+
let lines = cell.display_lines(80);
184+
assert_value_highlighted(&lines[0].spans, "Effort", "High");
185+
186+
let cell = new_agent_option_set_history_cell("Claude Code", "Model", "Opus 4.6");
187+
let lines = cell.display_lines(80);
188+
assert_value_highlighted(&lines[0].spans, "Model", "Opus 4.6");
189+
190+
insta::assert_snapshot!(spans_to_style_snapshot(&lines[0].spans));
191+
}
192+
193+
fn assert_value_highlighted(
194+
spans: &[ratatui::text::Span<'static>],
195+
expected_name: &str,
196+
expected_value: &str,
197+
) {
198+
let name = spans
199+
.iter()
200+
.find(|span| span.content.as_ref() == expected_name)
201+
.expect("option name should be its own span");
202+
let separator = spans
203+
.iter()
204+
.find(|span| span.content.as_ref() == "=")
205+
.expect("separator should be its own span");
206+
let value = spans
207+
.iter()
208+
.find(|span| span.content.as_ref() == expected_value)
209+
.expect("option value should be its own span");
210+
211+
assert_eq!(name.style, Style::default());
212+
assert_eq!(separator.style, Style::default());
213+
assert_eq!(value.style.fg, Some(Color::Cyan));
214+
assert!(value.style.add_modifier.contains(Modifier::BOLD));
215+
}
216+
217+
fn spans_to_style_snapshot(spans: &[ratatui::text::Span<'static>]) -> String {
218+
spans
219+
.iter()
220+
.map(|span| format!("{:?} {:?}", span.content, span.style))
221+
.collect::<Vec<_>>()
222+
.join("\n")
223+
}
224+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
source: tui/src/nori/session_config_history.rs
3+
expression: "spans_to_style_snapshot(&lines[0].spans)"
4+
---
5+
"" Style::new().dim()
6+
"Claude Code option set: " Style::new()
7+
"Model" Style::new()
8+
"=" Style::new()
9+
"Opus 4.6" Style::new().cyan().bold()

0 commit comments

Comments
 (0)