Remove randomized greetings from TUI session headers (#49395)

## What changed

Remove startup greeting phrases and the shared greeting state from startup drafts, session headers, and the empty-state animation. Raw session headers now consistently include `model:` and `directory:` fields.

## Testing

Update startup and fresh-thread snapshots to omit greetings, and adjust raw-header assertions to check model and directory fields.

GitOrigin-RevId: 531b5ba42d7a88f86b1c7f69030f3560abc25198
This commit is contained in:
Eric Traut
2026-09-29 23:09:32 +00:00
committed by copyberry
parent 05ea5f757e
commit ceea67163f
19 changed files with 22 additions and 279 deletions
@@ -181,14 +181,6 @@ async fn empty_state_animation_preserves_header_cursor_and_footer() -> Result<()
let size = Size::new(/*width*/ 120, /*height*/ 44);
let mut tui = crate::tui::test_support::make_test_tui()?;
tui.set_owned_screen(/*owned*/ true)?;
app.chat_widget
.empty_state_animation
.borrow()
.greeting
.set(crate::empty_state_animation::Greeting {
phrase: "Pull up a prompt.",
})
.expect("initial greeting");
app.queue_clear_ui_header(&mut tui);
app.transcript_cells
.push(Arc::new(history_cell::StartupWarningsCell::mcp(
@@ -209,7 +201,6 @@ async fn empty_state_animation_preserves_header_cursor_and_footer() -> Result<()
let after = crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal);
assert!(has_blossom(&tui));
assert_eq!(tui.terminal.last_known_cursor_pos, cursor);
assert!(text(&before).contains("Pull up a prompt."));
assert_eq!(
&after.content[after.index_of(/*x*/ 0, before_bottom.y)..],
&before.content[before.index_of(/*x*/ 0, before_bottom.y)..]
@@ -222,14 +213,6 @@ async fn empty_state_animation_preserves_header_cursor_and_footer() -> Result<()
text(&before)
)
);
// Editing, clearing, and resizing must never choose another phrase.
let phrase_pos = after
.content
.iter()
.position(|cell| cell.symbol() == "P")
.expect("the phrase is visible above the composer");
assert_eq!(after.content[phrase_pos].fg, crate::style::accent_color());
let short = Size::new(/*width*/ 120, /*height*/ 12);
draw(&mut app, &mut tui, short)?;
assert!(!has_blossom(&tui));
@@ -242,12 +225,6 @@ async fn empty_state_animation_preserves_header_cursor_and_footer() -> Result<()
app.chat_widget.apply_external_edit(String::new());
draw(&mut app, &mut tui, size)?;
assert!(has_blossom(&tui));
assert!(
text(crate::custom_terminal::test_support::last_rendered_buffer(
&tui.terminal
))
.contains("Pull up a prompt.")
);
assert_eq!(app.transcript_cells.len(), history_len);
app.local_settings.tui.animations = false;
draw(&mut app, &mut tui, size)?;
@@ -269,7 +246,7 @@ async fn empty_state_animation_preserves_header_cursor_and_footer() -> Result<()
}
#[tokio::test]
async fn submitting_a_draft_keeps_greeting_and_dismisses_logo_even_after_clear() -> Result<()> {
async fn submitting_a_draft_dismisses_logo_even_after_clear() -> Result<()> {
let (mut app, _events, _ops) = crate::app::tests::make_test_app_with_channels().await;
app.local_settings.tui.animations = true;
let size = Size::new(/*width*/ 120, /*height*/ 44);
@@ -282,20 +259,12 @@ async fn submitting_a_draft_keeps_greeting_and_dismisses_logo_even_after_clear()
.start_fresh();
draw(&mut app, &mut tui, size)?;
assert!(has_blossom(&tui));
let greeting = *app
.chat_widget
.empty_state_animation
.borrow()
.greeting
.get()
.expect("choose a greeting for the fresh thread");
app.chat_widget
.apply_external_edit("first prompt".to_string());
draw(&mut app, &mut tui, size)?;
let drafting = crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal);
assert!(!has_blossom(&tui));
assert!(text(drafting).contains("first prompt"));
assert!(text(drafting).contains(greeting.phrase));
app.chat_widget.apply_external_edit(String::new());
draw(&mut app, &mut tui, size)?;
assert!(has_blossom(&tui));
@@ -305,14 +274,9 @@ async fn submitting_a_draft_keeps_greeting_and_dismisses_logo_even_after_clear()
.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
draw(&mut app, &mut tui, size)?;
assert!(!has_blossom(&tui));
let submitted = crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal);
assert_eq!(text(submitted).matches(greeting.phrase).count(), 1);
// The header is also stable when it scrolls out and back into the viewport.
let short = Size::new(/*width*/ 120, /*height*/ 8);
draw(&mut app, &mut tui, short)?;
draw(&mut app, &mut tui, size)?;
let restored = crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal);
assert!(text(restored).contains(greeting.phrase));
assert!(!has_blossom(&tui));
app.reset_transcript_state_after_clear();
draw(&mut app, &mut tui, size)?;
+2 -7
View File
@@ -316,18 +316,13 @@ impl App {
&self,
version: &'static str,
) -> history_cell::SessionHeaderHistoryCell {
let mut header = history_cell::SessionHeaderHistoryCell::new(
history_cell::SessionHeaderHistoryCell::new(
self.chat_widget.model_display_name().to_string(),
self.chat_widget.current_reasoning_effort(),
self.config.cwd.to_path_buf(),
version,
)
.with_yolo_mode(history_cell::is_yolo_mode(&self.config));
history_cell::set_session_greeting(
&mut header,
&self.chat_widget.empty_state_animation.borrow().greeting,
);
header
.with_yolo_mode(history_cell::is_yolo_mode(&self.config))
}
pub(super) fn clear_ui_header_lines(&self, width: u16) -> Vec<Line<'static>> {
+1 -1
View File
@@ -1108,7 +1108,7 @@ impl App {
ThreadAttachPresentation::Fresh | ThreadAttachPresentation::FreshWithDraft
) {
self.chat_widget.mark_fresh_task_for_sparkle(&started);
// FreshWithDraft inherits its provisional greeting and replay at the handoff.
// FreshWithDraft inherits its provisional replay at the handoff.
if matches!(presentation, ThreadAttachPresentation::Fresh) {
self.chat_widget
.empty_state_animation
@@ -7,7 +7,7 @@ enabled:
>_ OpenAI Codex (v0.0.0)
/tmp/project
Pull up a prompt.
@@ -53,7 +53,7 @@ disabled:
>_ OpenAI Codex (v0.0.0)
/tmp/project
Pull up a prompt.
@@ -86,16 +86,6 @@ async fn command_center_new_keeps_startup_draft_visible_through_handoff() -> Res
app.chat_widget.composer_text_with_pending(),
"draft during startup"
);
assert_eq!(
app.chat_widget
.empty_state_animation
.borrow()
.greeting
.get()
.unwrap()
.phrase,
"Pull up a prompt."
);
while let Ok(event) = events.try_recv() {
Box::pin(app.handle_event(&mut tui, &mut server, event)).await?;
@@ -1,6 +1,5 @@
---
source: tui/src/app/tests/startup_frame_tests.rs
assertion_line: 72
expression: "normalize_snapshot_paths(normalize_agent_center_snapshot(snapshots.join(\"\\n\\n\")))"
---
80 columns
@@ -8,8 +7,6 @@ expression: "normalize_snapshot_paths(normalize_agent_center_snapshot(snapshots.
>_ OpenAI Codex (v0.0.0)
/tmp/project
Pull up a prompt.
• Conversation continues here.
@@ -20,6 +17,8 @@ expression: "normalize_snapshot_paths(normalize_agent_center_snapshot(snapshots.
› Ask Codex to do anything
GPT-5.6-Sol default · /tmp/project
@@ -30,8 +29,6 @@ expression: "normalize_snapshot_paths(normalize_agent_center_snapshot(snapshots.
>_ OpenAI Codex (v0.0.0)
/tmp/project
Pull up a prompt.
• Conversation continues here.
@@ -42,6 +39,8 @@ expression: "normalize_snapshot_paths(normalize_agent_center_snapshot(snapshots.
› Ask Codex to do anything
GPT-5.6-Sol default · /tmp/pr…
@@ -21,14 +21,8 @@ async fn owned_startup_hides_tip_in_transcript() -> Result<()> {
let mut app = crate::app::test_support::make_test_app().await;
app.local_settings.tui.show_tooltips = true;
app.local_settings.tui.animations = false;
let greeting = Arc::new(std::sync::OnceLock::new());
greeting
.set(crate::empty_state_animation::Greeting {
phrase: "Pull up a prompt.",
})
.unwrap();
let session = test_thread_session(ThreadId::new(), app.config.cwd.to_path_buf());
let mut session_info = new_session_info(
let session_info = new_session_info(
&app.config,
&app.local_settings,
&session.model,
@@ -38,7 +32,6 @@ async fn owned_startup_hides_tip_in_transcript() -> Result<()> {
Some("Use /mcp to list configured MCP tools.".into()),
/*auth_plan*/ None,
);
history_cell::set_session_greeting(&mut session_info, &greeting);
app.transcript_cells = vec![
Arc::new(session_info),
Arc::new(AgentMessageCell::new(
@@ -80,9 +73,8 @@ async fn owned_startup_hides_tip_in_transcript() -> Result<()> {
.map(ToString::to_string)
.collect::<Vec<_>>()
.join("\n");
assert!(text.contains("Pull up a prompt."));
assert!(text.contains("Use /mcp"));
assert!(!text.contains("model:"));
assert_eq!(text.contains("model:"), mode == HistoryRenderMode::Raw);
assert!(!text.contains('╭'));
}
app.transcript_view.begin_search();
+1 -2
View File
@@ -64,8 +64,7 @@ impl ChatWidget {
};
let empty_state_animation = crate::empty_state_animation::EmptyStateAnimation::default();
let mut header = Self::placeholder_session_header_cell(&config);
history_cell::set_session_greeting(header.as_mut(), &empty_state_animation.greeting);
let header = Self::placeholder_session_header_cell(&config);
let active_cell = Some(header);
let current_cwd = Some(config.cwd.to_path_buf());
+1 -5
View File
@@ -201,7 +201,7 @@ impl ChatWidget {
let model_for_header = self.current_model().to_string();
if display == SessionConfiguredDisplay::Normal {
let startup_tooltip_override = self.startup_tooltip_override.take();
let mut session_info_cell = history_cell::new_session_info(
let session_info_cell = history_cell::new_session_info(
&self.config,
&self.local_settings,
&model_for_header,
@@ -211,10 +211,6 @@ impl ChatWidget {
startup_tooltip_override,
self.plan_type,
);
history_cell::set_session_greeting(
&mut session_info_cell,
&self.empty_state_animation.borrow().greeting,
);
self.apply_session_info_cell(session_info_cell);
} else if self
.transcript
+1 -12
View File
@@ -2,14 +2,12 @@
//! Visible time pauses while hidden. Fresh conversations start settled and can replay on a click.
mod geometry;
mod greetings;
mod lighting;
mod paths;
mod policy;
mod renderer;
mod sequence;
use std::sync::Arc;
use std::sync::OnceLock;
use std::time::Duration;
use std::time::Instant;
@@ -24,7 +22,6 @@ use ratatui::style::Color;
use crate::motion::MotionMode;
use crate::terminal_palette;
pub(crate) use greetings::Greeting;
use lighting::Lighting;
pub(crate) use policy::Presentation;
pub(crate) use policy::is_startup_cell;
@@ -45,9 +42,6 @@ pub(crate) enum ComposerState {
#[derive(Default)]
pub(crate) struct EmptyStateAnimation {
eligible: bool,
// Initialized once for fresh threads; never initialized for a resumed or forked thread.
// Headers retain the selection after the temporary blossom is dismissed.
pub(crate) greeting: Arc<OnceLock<Greeting>>,
spin_elapsed: Duration,
last_frame: Option<Instant>,
fade_elapsed: Duration,
@@ -67,7 +61,6 @@ impl EmptyStateAnimation {
pub(crate) fn start_fresh(&mut self) {
self.cancel_replay();
self.eligible = true;
self.greeting.get_or_init(Greeting::choose);
self.spin_elapsed = Duration::ZERO;
self.last_frame = None;
self.fade_elapsed = Duration::ZERO;
@@ -75,16 +68,12 @@ impl EmptyStateAnimation {
self.opacity = 1.0;
}
/// Keep the provisional pose and phrase in headers already bound to the live thread.
/// Keep the provisional pose when handing off to the live thread.
pub(crate) fn continue_from(&mut self, source: &mut Self) {
let mut previous = std::mem::take(source);
if !previous.is_eligible() {
previous.start_fresh();
}
if let Some(greeting) = previous.greeting.get() {
let _ = self.greeting.set(*greeting);
}
previous.greeting = Arc::clone(&self.greeting);
*self = previous;
}
@@ -1,108 +0,0 @@
//! Startup phrases retained from the approved greeting list (PR #10248).
//! One selection is shared by the provisional, live, and committed session headers.
use rand::Rng;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct Greeting {
pub(crate) phrase: &'static str,
}
impl Greeting {
pub(super) fn choose() -> Self {
Self {
phrase: GREETINGS[rand::rng().random_range(0..GREETINGS.len())],
}
}
}
const GREETINGS: &[&str] = &[
"Whoa, fancy meeting you here!",
"Look who’s at the keyboard.",
"Hello, you. Got an idea?",
"Nice to see you in these parts.",
"Pull up a prompt.",
"What brings you to this corner of the terminal?",
"Hey there. Big plans or little fixes?",
"What are we getting into today?",
"Got something you want to try?",
"What’s today’s little adventure?",
"Anything interesting on the docket?",
"Take your time. The cursor can wait.",
"A half-formed idea will do.",
"Come on in. There’s room for an idea.",
"You, me, and a blinking cursor.",
"It takes two to tango. What’s our first step?",
"You bring the idea. I’ll bring the brackets.",
"Your move, teammate.",
"What are we cooking up?",
"Shall we turn “what if” into something?",
"What’s the first thing on our napkin sketch?",
"Bring your unfinished thoughts.",
"You set the direction. We’ll work out the steps.",
"Ah, the terminal. A classic meeting spot.",
"Nice place you’ve got here. Very monospace.",
"Welcome to our little rectangle of possibility.",
"A cursor blinks. The plot thickens.",
"The prompt is yours.",
"Fancy a little quality terminal time?",
"How’s life between the brackets?",
"Shall we give this cursor a purpose?",
"A fresh prompt. An open question.",
"Your keyboard has entered the chat.",
"Hello, world. Hello, you.",
"Welcome to the blinking edge of possibility.",
"Any loose ends? Semicolons count.",
"Shall we make this terminal earn its keep?",
"Got an itch to fix a thing?",
"Show me the bit that’s being weird.",
"Greetings, fellow tinkerer.",
"Well, well, well. An idea approaches.",
"What’s today’s side quest?",
"Is this a plan day or a poke-around day?",
"Practical, peculiar, or a little of both?",
"Rough sketches welcome.",
"Shall we see where this goes?",
"All right. What have you got?",
"Back for another round?",
"Same terminal, new possibilities.",
"Welcome back. Familiar territory or a fresh adventure?",
"Follow the white cursor.",
"Welcome to the command line, Neo.",
"A glitch in the Matrix, or just a missing semicolon?",
"How deep does this codebase go?",
"Speak, friend, and enter a prompt.",
"One prompt to begin the journey.",
"May the source be with you.",
"These might be the bugs you’re looking for.",
"A new prompt awakens.",
"Forty-two is an answer. What’s the question?",
"It’s dangerous to code alone. Take a prompt.",
"The code must flow.",
"You rang? Metaphorically. You typed.",
"Hello again, carbon-based collaborator.",
"This looks like the start of a perfectly reasonable rabbit hole.",
"Shall we turn “huh?” into “aha!”?",
"Well, this terminal just got interesting.",
"The source is strong with this one.",
"There’s a perfectly good prompt with your name on it.",
"Here for a quick fix or the extended edition?",
"What’s the latest from your side of the keyboard?",
"Got a minute and a mildly unreasonable idea?",
"A hunch is a perfectly respectable starting point.",
"Hello again. What’s the plot this time?",
"Shall we make a little something out of nothing?",
"Welcome to the neighborhood. Lots of characters here.",
"Nice terminal. Does it come in widescreen?",
"Your cursor called. It wants a plot.",
"Shall we put some verbs after that cursor?",
"Welcome. There’s no dress code, just code.",
"This terminal has excellent conversational potential.",
"Got an idea that won’t stay on the napkin?",
"What are we building in this episode?",
"Bring a question. Bonus points if it’s a weird one.",
"What are we poking with a metaphorical stick?",
"Shall we make the thing that makes the other thing easier?",
"Welcome to the part where the idea gets interesting.",
"A long time ago, in a directory not so far away…",
];
-31
View File
@@ -1,10 +1,6 @@
//! Session headers, onboarding guidance, and transcript cards.
use std::sync::Arc;
use std::sync::OnceLock;
use super::*;
use crate::empty_state_animation::Greeting;
use crate::line_truncation::line_width;
use crate::line_truncation::truncate_line_with_ellipsis_if_overflow;
use crate::style::accent_color;
@@ -110,17 +106,6 @@ impl HistoryCell for SessionNoticeCell {
#[derive(Debug)]
pub struct SessionInfoCell(CompositeHistoryCell);
/// Bind provisional and configured banners to the thread's chosen greeting.
pub(crate) fn set_session_greeting(cell: &mut dyn HistoryCell, greeting: &Arc<OnceLock<Greeting>>) {
if let Some(header) = cell.as_any_mut().downcast_mut::<SessionHeaderHistoryCell>() {
header.greeting = Arc::clone(greeting);
} else if let Some(info) = cell.as_any_mut().downcast_mut::<SessionInfoCell>() {
for part in &mut info.0.parts {
set_session_greeting(part.as_mut(), greeting);
}
}
}
/// Fullscreen transcript presentation omits tips; scrollback retains the original cells.
pub(crate) fn fullscreen_session_lines(
cell: &dyn HistoryCell,
@@ -292,7 +277,6 @@ pub(crate) struct SessionHeaderHistoryCell {
reasoning_effort: Option<ReasoningEffortConfig>,
directory: PathBuf,
yolo_mode: bool,
greeting: Arc<OnceLock<Greeting>>,
}
impl SessionHeaderHistoryCell {
@@ -308,7 +292,6 @@ impl SessionHeaderHistoryCell {
reasoning_effort,
directory,
yolo_mode: false,
greeting: Default::default(),
}
}
@@ -371,13 +354,6 @@ impl HistoryCell for SessionHeaderHistoryCell {
"YOLO mode".magenta().bold(),
]));
}
if let Some(greeting) = self.greeting.get() {
// The tip/help that follows has its own normal composite separator.
lines.extend([
Line::default(),
Line::from(vec![" ".into(), greeting.phrase.fg(accent_color())]),
]);
}
lines
.into_iter()
.map(|line| truncate_line_with_ellipsis_if_overflow(line, width))
@@ -385,13 +361,6 @@ impl HistoryCell for SessionHeaderHistoryCell {
}
fn raw_lines(&self) -> Vec<Line<'static>> {
if self.greeting.get().is_some() {
return self
.display_lines(u16::MAX)
.into_iter()
.map(|line| Line::from(line.to_string()))
.collect();
}
let mut lines = vec![
Line::from(format!("OpenAI Codex (v{})", self.version)),
Line::from(format!(
@@ -7,7 +7,7 @@ cursor=Some((13, 12))
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
@@ -1,6 +1,5 @@
---
source: tui/src/startup_draft_tests.rs
assertion_line: 285
expression: "snapshots.join(\"\\n---\\n\")"
---
resume lookup fallback:
@@ -8,8 +7,6 @@ before:
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
Resuming session…
› draft while loading
@@ -20,8 +17,6 @@ after:
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
› draft while loading
@@ -32,8 +27,6 @@ before:
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
Forking session…
› draft while loading
@@ -44,8 +37,6 @@ after:
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
› draft while loading
@@ -59,8 +50,6 @@ after:
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
› Ask Codex to do anything
@@ -74,8 +63,6 @@ after:
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
› Ask Codex to do anything
@@ -1,6 +1,5 @@
---
source: tui/src/startup_draft_tests.rs
assertion_line: 154
expression: "snapshots.join(\"\\n---\\n\")"
---
empty (48 columns):
@@ -8,8 +7,6 @@ empty (48 columns):
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
› Ask Codex to do anything
@@ -40,8 +37,6 @@ multiline (48 columns):
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
› first startup line
second startup line
@@ -53,8 +48,6 @@ narrow (18 columns):
>_ OpenAI Codex…
loading
Pull up a promp…
› first startup
line
@@ -1,6 +1,5 @@
---
source: tui/src/startup_draft_tests.rs
assertion_line: 802
expression: frames
---
before onboarding: hidden (0x0 viewport)
@@ -10,8 +9,6 @@ after onboarding:
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
› Ask Codex to do anything
@@ -1,6 +1,5 @@
---
source: tui/src/startup_draft_tests.rs
assertion_line: 194
expression: "frames.join(\"\\n---\\n\").replace(crate::version::CODEX_CLI_VERSION, \"<VERSION>\")"
---
terminal_app_over_ssh=false, owned=true
@@ -8,7 +7,7 @@ terminal_app_over_ssh=false, owned=true
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
@@ -26,8 +25,6 @@ terminal_app_over_ssh=true, owned=false
>_ OpenAI Codex (v<VERSION>)
loading
Pull up a prompt.
› Ask Codex to do anything
+1 -3
View File
@@ -202,8 +202,7 @@ impl StartupDraftPump {
) {
blossom.start_fresh();
}
let mut header = startup_session_header(/*config*/ None);
history_cell::set_session_greeting(header.as_mut(), &blossom.greeting);
let header = startup_session_header(/*config*/ None);
Self {
header,
blossom: std::cell::RefCell::new(blossom),
@@ -262,7 +261,6 @@ impl StartupDraftPump {
local_settings.tui.animations && local_settings.tui.effects.welcome,
);
self.header = startup_session_header(Some(config));
history_cell::set_session_greeting(self.header.as_mut(), &self.blossom.borrow().greeting);
self.bottom_pane.set_status_line_enabled(
local_settings
.tui
+4 -18
View File
@@ -29,15 +29,8 @@ where
{
let (tx, rx) = unbounded_channel();
let mut blossom = crate::empty_state_animation::EmptyStateAnimation::default();
blossom
.greeting
.set(crate::empty_state_animation::Greeting {
phrase: "Pull up a prompt.",
})
.expect("initial greeting");
blossom.start_fresh();
let mut header = startup_session_header(/*config*/ None);
crate::history_cell::set_session_greeting(header.as_mut(), &blossom.greeting);
let header = startup_session_header(/*config*/ None);
StartupDraftPump {
header,
blossom: std::cell::RefCell::new(blossom),
@@ -100,13 +93,6 @@ fn startup_draft_renders_full_empty_and_multiline_composer_frames() {
] {
let mut pump = startup_test_pump(std::iter::empty());
pump.session_action = session_action;
// Resume and fork have no fresh-thread greeting. Exercise the real initial state.
if matches!(
session_action,
StartupDraftSessionAction::Resume | StartupDraftSessionAction::Fork
) {
pump.header = startup_session_header(/*config*/ None);
}
pump.bottom_pane
.set_composer_text(text.to_string(), Vec::new(), Vec::new());
let renderable =
@@ -314,15 +300,15 @@ async fn startup_draft_hydrates_its_header_without_moving_the_composer() {
startup_draft_renderable(&pump.header, &pump.bottom_pane, pump.session_action)
.desired_height(width);
assert_eq!(pump.header.raw_lines()[2].to_string().trim(), "loading");
assert_eq!(pump.header.raw_lines()[2].to_string(), "directory: loading");
pump.apply_config(&config);
let expected_directory = crate::history_cell::SessionHeaderHistoryCell::format_directory_inner(
config.cwd.as_path(),
/*max_width*/ None,
);
assert_eq!(
pump.header.raw_lines()[2].to_string().trim(),
expected_directory
pump.header.raw_lines()[2].to_string(),
format!("directory: {expected_directory}")
);
assert_eq!(
startup_draft_renderable(&pump.header, &pump.bottom_pane, pump.session_action)