prefer ratatui Stylized for constructing lines/spans (#3068)

no functional change, just simplifying ratatui styling and adding
guidance in AGENTS.md for future.
This commit is contained in:
Jeremy Rose
2025-09-02 16:19:54 -07:00
committed by GitHub
parent 0d5ffb000e
commit 578ff09e17
18 changed files with 203 additions and 311 deletions

View File

@@ -15,7 +15,6 @@ use ratatui::style::Modifier;
use ratatui::style::Style;
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::text::Span;
use ratatui::widgets::Paragraph;
use ratatui::widgets::WidgetRef;
use ratatui::widgets::Wrap;
@@ -120,20 +119,14 @@ impl AuthModeWidget {
fn render_pick_mode(&self, area: Rect, buf: &mut Buffer) {
let mut lines: Vec<Line> = vec![
Line::from(vec![
Span::raw("> "),
Span::styled(
"Sign in with ChatGPT to use Codex as part of your paid plan",
Style::default().add_modifier(Modifier::BOLD),
),
"> ".into(),
"Sign in with ChatGPT to use Codex as part of your paid plan".bold(),
]),
Line::from(vec![
Span::raw(" "),
Span::styled(
"or connect an API key for usage-based billing",
Style::default().add_modifier(Modifier::BOLD),
),
" ".into(),
"or connect an API key for usage-based billing".bold(),
]),
Line::from(""),
"".into(),
];
// If the user is already authenticated but the method differs from their
@@ -150,8 +143,8 @@ impl AuthModeWidget {
to_label(current),
to_label(self.preferred_auth_method)
);
lines.push(Line::from(msg).style(Style::default()));
lines.push(Line::from(""));
lines.push(msg.into());
lines.push("".into());
}
let create_mode_item = |idx: usize,
@@ -168,7 +161,7 @@ impl AuthModeWidget {
text.to_string().cyan(),
])
} else {
Line::from(format!(" {}. {text}", idx + 1))
format!(" {}. {text}", idx + 1).into()
};
let line2 = if is_selected {
@@ -207,19 +200,15 @@ impl AuthModeWidget {
api_key_label,
"Pay for what you use",
));
lines.push(Line::from(""));
lines.push("".into());
lines.push(
// AE: Following styles.md, this should probably be Cyan because it's a user input tip.
// But leaving this for a future cleanup.
Line::from(" Press Enter to continue")
.style(Style::default().add_modifier(Modifier::DIM)),
" Press Enter to continue".dim().into(),
);
if let Some(err) = &self.error {
lines.push(Line::from(""));
lines.push(Line::from(Span::styled(
err.as_str(),
Style::default().fg(Color::Red),
)));
lines.push("".into());
lines.push(err.as_str().red().into());
}
Paragraph::new(lines)
@@ -228,28 +217,23 @@ impl AuthModeWidget {
}
fn render_continue_in_browser(&self, area: Rect, buf: &mut Buffer) {
let mut spans = vec![Span::from("> ")];
let mut spans = vec!["> ".into()];
// Schedule a follow-up frame to keep the shimmer animation going.
self.request_frame
.schedule_frame_in(std::time::Duration::from_millis(100));
spans.extend(shimmer_spans("Finish signing in via your browser"));
let mut lines = vec![Line::from(spans), Line::from("")];
let mut lines = vec![spans.into(), "".into()];
let sign_in_state = self.sign_in_state.read().unwrap();
if let SignInState::ChatGptContinueInBrowser(state) = &*sign_in_state
&& !state.auth_url.is_empty()
{
lines.push(Line::from(" If the link doesn't open automatically, open the following link to authenticate:"));
lines.push(Line::from(vec![
Span::raw(" "),
state.auth_url.as_str().cyan().underlined(),
]));
lines.push(Line::from(""));
lines.push(" If the link doesn't open automatically, open the following link to authenticate:".into());
lines.push(vec![" ".into(), state.auth_url.as_str().cyan().underlined()].into());
lines.push("".into());
}
lines.push(
Line::from(" Press Esc to cancel").style(Style::default().add_modifier(Modifier::DIM)),
);
lines.push(" Press Esc to cancel".dim().into());
Paragraph::new(lines)
.wrap(Wrap { trim: false })
.render(area, buf);
@@ -257,35 +241,28 @@ impl AuthModeWidget {
fn render_chatgpt_success_message(&self, area: Rect, buf: &mut Buffer) {
let lines = vec![
Line::from("✓ Signed in with your ChatGPT account").fg(Color::Green),
Line::from(""),
Line::from("> Before you start:"),
Line::from(""),
Line::from(" Decide how much autonomy you want to grant Codex"),
"✓ Signed in with your ChatGPT account".fg(Color::Green).into(),
"".into(),
"> Before you start:".into(),
"".into(),
" Decide how much autonomy you want to grant Codex".into(),
Line::from(vec![
Span::raw(" For more details see the "),
Span::styled(
"\u{1b}]8;;https://github.com/openai/codex\u{7}Codex docs\u{1b}]8;;\u{7}",
Style::default().add_modifier(Modifier::UNDERLINED),
),
" For more details see the ".into(),
"\u{1b}]8;;https://github.com/openai/codex\u{7}Codex docs\u{1b}]8;;\u{7}".underlined(),
])
.style(Style::default().add_modifier(Modifier::DIM)),
Line::from(""),
Line::from(" Codex can make mistakes"),
Line::from(" Review the code it writes and commands it runs")
.style(Style::default().add_modifier(Modifier::DIM)),
Line::from(""),
Line::from(" Powered by your ChatGPT account"),
.dim(),
"".into(),
" Codex can make mistakes".into(),
" Review the code it writes and commands it runs".dim().into(),
"".into(),
" Powered by your ChatGPT account".into(),
Line::from(vec![
Span::raw(" Uses your plan's rate limits and "),
Span::styled(
"\u{1b}]8;;https://chatgpt.com/#settings\u{7}training data preferences\u{1b}]8;;\u{7}",
Style::default().add_modifier(Modifier::UNDERLINED),
),
" Uses your plan's rate limits and ".into(),
"\u{1b}]8;;https://chatgpt.com/#settings\u{7}training data preferences\u{1b}]8;;\u{7}".underlined(),
])
.style(Style::default().add_modifier(Modifier::DIM)),
Line::from(""),
Line::from(" Press Enter to continue").fg(Color::Cyan),
.dim(),
"".into(),
" Press Enter to continue".fg(Color::Cyan).into(),
];
Paragraph::new(lines)
@@ -294,7 +271,11 @@ impl AuthModeWidget {
}
fn render_chatgpt_success(&self, area: Rect, buf: &mut Buffer) {
let lines = vec![Line::from("✓ Signed in with your ChatGPT account").fg(Color::Green)];
let lines = vec![
"✓ Signed in with your ChatGPT account"
.fg(Color::Green)
.into(),
];
Paragraph::new(lines)
.wrap(Wrap { trim: false })
@@ -302,7 +283,7 @@ impl AuthModeWidget {
}
fn render_env_var_found(&self, area: Rect, buf: &mut Buffer) {
let lines = vec![Line::from("✓ Using OPENAI_API_KEY").fg(Color::Green)];
let lines = vec!["✓ Using OPENAI_API_KEY".fg(Color::Green).into()];
Paragraph::new(lines)
.wrap(Wrap { trim: false })
@@ -311,13 +292,11 @@ impl AuthModeWidget {
fn render_env_var_missing(&self, area: Rect, buf: &mut Buffer) {
let lines = vec![
Line::from(
" To use Codex with the OpenAI API, set OPENAI_API_KEY in your environment",
)
.style(Style::default().fg(Color::Cyan)),
Line::from(""),
Line::from(" Press Enter to return")
.style(Style::default().add_modifier(Modifier::DIM)),
" To use Codex with the OpenAI API, set OPENAI_API_KEY in your environment"
.fg(Color::Cyan)
.into(),
"".into(),
" Press Enter to return".dim().into(),
];
Paragraph::new(lines)

View File

@@ -9,10 +9,8 @@ use ratatui::layout::Rect;
use ratatui::prelude::Widget;
use ratatui::style::Color;
use ratatui::style::Modifier;
use ratatui::style::Style;
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::text::Span;
use ratatui::widgets::Paragraph;
use ratatui::widgets::WidgetRef;
use ratatui::widgets::Wrap;
@@ -41,30 +39,25 @@ impl WidgetRef for &TrustDirectoryWidget {
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
let mut lines: Vec<Line> = vec![
Line::from(vec![
Span::raw("> "),
Span::styled(
"You are running Codex in ",
Style::default().add_modifier(Modifier::BOLD),
),
Span::raw(self.cwd.to_string_lossy().to_string()),
"> ".into(),
"You are running Codex in ".bold(),
self.cwd.to_string_lossy().to_string().into(),
]),
Line::from(""),
"".into(),
];
if self.is_git_repo {
lines.push(Line::from(
" Since this folder is version controlled, you may wish to allow Codex",
));
lines.push(Line::from(
" to work in this folder without asking for approval.",
));
lines.push(
" Since this folder is version controlled, you may wish to allow Codex".into(),
);
lines.push(" to work in this folder without asking for approval.".into());
} else {
lines.push(Line::from(
" Since this folder is not version controlled, we recommend requiring",
));
lines.push(Line::from(" approval of all edits and commands."));
lines.push(
" Since this folder is not version controlled, we recommend requiring".into(),
);
lines.push(" approval of all edits and commands.".into());
}
lines.push(Line::from(""));
lines.push("".into());
let create_option =
|idx: usize, option: TrustDirectorySelection, text: &str| -> Line<'static> {
@@ -99,10 +92,10 @@ impl WidgetRef for &TrustDirectoryWidget {
"Require approval of edits and commands",
));
}
lines.push(Line::from(""));
lines.push("".into());
if let Some(error) = &self.error {
lines.push(Line::from(format!(" {error}")).fg(Color::Red));
lines.push(Line::from(""));
lines.push("".into());
}
// AE: Following styles.md, this should probably be Cyan because it's a user input tip.
// But leaving this for a future cleanup.

View File

@@ -1,10 +1,8 @@
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::prelude::Widget;
use ratatui::style::Modifier;
use ratatui::style::Style;
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::text::Span;
use ratatui::widgets::WidgetRef;
use crate::onboarding::onboarding_screen::StepStateProvider;
@@ -18,11 +16,8 @@ pub(crate) struct WelcomeWidget {
impl WidgetRef for &WelcomeWidget {
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
let line = Line::from(vec![
Span::raw(">_ "),
Span::styled(
"Welcome to Codex, OpenAI's command-line coding agent",
Style::default().add_modifier(Modifier::BOLD),
),
">_ ".into(),
"Welcome to Codex, OpenAI's command-line coding agent".bold(),
]);
line.render(area, buf);
}