Apply argument comment lint across codex-rs (#14652)

## Why

Once the repo-local lint exists, `codex-rs` needs to follow the
checked-in convention and CI needs to keep it from drifting. This commit
applies the fallback `/*param*/` style consistently across existing
positional literal call sites without changing those APIs.

The longer-term preference is still to avoid APIs that require comments
by choosing clearer parameter types and call shapes. This PR is
intentionally the mechanical follow-through for the places where the
existing signatures stay in place.

After rebasing onto newer `main`, the rollout also had to cover newly
introduced `tui_app_server` call sites. That made it clear the first cut
of the CI job was too expensive for the common path: it was spending
almost as much time installing `cargo-dylint` and re-testing the lint
crate as a representative test job spends running product tests. The CI
update keeps the full workspace enforcement but trims that extra
overhead from ordinary `codex-rs` PRs.

## What changed

- keep a dedicated `argument_comment_lint` job in `rust-ci`
- mechanically annotate remaining opaque positional literals across
`codex-rs` with exact `/*param*/` comments, including the rebased
`tui_app_server` call sites that now fall under the lint
- keep the checked-in style aligned with the lint policy by using
`/*param*/` and leaving string and char literals uncommented
- cache `cargo-dylint`, `dylint-link`, and the relevant Cargo
registry/git metadata in the lint job
- split changed-path detection so the lint crate's own `cargo test` step
runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes
- continue to run the repo wrapper over the `codex-rs` workspace, so
product-code enforcement is unchanged

Most of the code changes in this commit are intentionally mechanical
comment rewrites or insertions driven by the lint itself.

## Verification

- `./tools/argument-comment-lint/run.sh --workspace`
- `cargo test -p codex-tui-app-server -p codex-tui`
- parsed `.github/workflows/rust-ci.yml` locally with PyYAML

---

* -> #14652
* #14651
This commit is contained in:
Michael Bolin
2026-03-16 16:48:15 -07:00
committed by GitHub
parent 6f05d8d735
commit b77fe8fefe
261 changed files with 2311 additions and 1377 deletions
+56 -42
View File
@@ -236,10 +236,10 @@ fn emit_skill_load_warnings(app_event_tx: &AppEventSender, errors: &[SkillErrorI
fn emit_project_config_warnings(app_event_tx: &AppEventSender, config: &Config) {
let mut disabled_folders = Vec::new();
for layer in config
.config_layer_stack
.get_layers(ConfigLayerStackOrdering::LowestPrecedenceFirst, true)
{
for layer in config.config_layer_stack.get_layers(
ConfigLayerStackOrdering::LowestPrecedenceFirst,
/*include_disabled*/ true,
) {
let ConfigLayerSource::Project { dot_codex_folder } = &layer.name else {
continue;
};
@@ -1117,17 +1117,17 @@ impl App {
// this runtime patch, the config edit would only affect future
// sessions or turns recreated from disk.
let op = AppCommand::override_turn_context(
None,
/*cwd*/ None,
approval_policy_override,
approvals_reviewer_override,
sandbox_policy_override,
None,
None,
None,
None,
None,
None,
None,
/*windows_sandbox_level*/ None,
/*model*/ None,
/*effort*/ None,
/*summary*/ None,
/*service_tier*/ None,
/*collaboration_mode*/ None,
/*personality*/ None,
);
let replay_state_op =
ThreadEventStore::op_can_change_pending_replay_state(&op).then(|| op.clone());
@@ -1163,8 +1163,10 @@ impl App {
}
if let Some(label) = permissions_history_label {
self.chat_widget
.add_info_message(format!("Permissions updated to {label}"), None);
self.chat_widget.add_info_message(
format!("Permissions updated to {label}"),
/*hint*/ None,
);
}
}
@@ -1176,7 +1178,7 @@ impl App {
}
self.chat_widget
.add_info_message(format!("Opened {url} in your browser."), None);
.add_info_message(format!("Opened {url} in your browser."), /*hint*/ None);
}
fn clear_ui_header_lines_with_version(
@@ -1292,7 +1294,7 @@ impl App {
if self.active_thread_id.is_some() {
return;
}
self.set_thread_active(thread_id, true).await;
self.set_thread_active(thread_id, /*active*/ true).await;
let receiver = if let Some(channel) = self.thread_event_channels.get_mut(&thread_id) {
channel.receiver.take()
} else {
@@ -1333,7 +1335,7 @@ impl App {
async fn clear_active_thread(&mut self) {
if let Some(active_id) = self.active_thread_id.take() {
self.set_thread_active(active_id, false).await;
self.set_thread_active(active_id, /*active*/ false).await;
}
self.active_thread_rx = None;
self.refresh_pending_thread_approvals().await;
@@ -1860,7 +1862,10 @@ impl App {
let thread_id = session.session_id;
self.primary_thread_id = Some(thread_id);
self.primary_session_configured = Some(session.clone());
self.upsert_agent_picker_thread(thread_id, None, None, false);
self.upsert_agent_picker_thread(
thread_id, /*agent_nickname*/ None, /*agent_role*/ None,
/*is_closed*/ false,
);
self.ensure_thread_channel(thread_id);
self.activate_thread_channel(thread_id).await;
self.enqueue_thread_event(thread_id, event).await?;
@@ -1886,7 +1891,10 @@ impl App {
for thread_id in thread_ids {
if self.thread_event_listener_tasks.contains_key(&thread_id) {
if self.agent_navigation.get(&thread_id).is_none() {
self.upsert_agent_picker_thread(thread_id, None, None, false);
self.upsert_agent_picker_thread(
thread_id, /*agent_nickname*/ None, /*agent_role*/ None,
/*is_closed*/ false,
);
}
} else {
self.mark_agent_picker_thread_closed(thread_id);
@@ -1903,7 +1911,7 @@ impl App {
if self.agent_navigation.is_empty() {
self.chat_widget
.add_info_message("No agents available yet.".to_string(), None);
.add_info_message("No agents available yet.".to_string(), /*hint*/ None);
return;
}
@@ -2014,7 +2022,7 @@ impl App {
if is_replay_only {
self.chat_widget.add_info_message(
format!("Agent thread {thread_id} is closed. Replaying saved transcript."),
None,
/*hint*/ None,
);
}
self.drain_active_thread_events(tui).await?;
@@ -2182,13 +2190,15 @@ impl App {
if let Some(event) = snapshot.session_configured {
self.handle_codex_event_replay(event);
}
self.chat_widget.set_queue_autosend_suppressed(true);
self.chat_widget
.set_queue_autosend_suppressed(/*suppressed*/ true);
self.chat_widget
.restore_thread_input_state(snapshot.input_state);
for event in snapshot.events {
self.handle_codex_event_replay(event);
}
self.chat_widget.set_queue_autosend_suppressed(false);
self.chat_widget
.set_queue_autosend_suppressed(/*suppressed*/ false);
if resume_restored_queue {
self.chat_widget.maybe_send_next_queued_input();
}
@@ -2282,7 +2292,7 @@ impl App {
ThreadId::new(),
model.as_str(),
model.as_str(),
None,
/*account_id*/ None,
bootstrap.account_email.clone(),
auth_mode,
codex_core::default_client::originator().value,
@@ -2295,7 +2305,7 @@ impl App {
.as_ref()
.is_some_and(|cmd| !cmd.is_empty())
{
session_telemetry.counter("codex.status_line", 1, &[]);
session_telemetry.counter("codex.status_line", /*inc*/ 1, &[]);
}
let status_line_invalid_items_warned = Arc::new(AtomicBool::new(false));
@@ -2374,7 +2384,11 @@ impl App {
)
}
SessionSelection::Fork(target_session) => {
session_telemetry.counter("codex.thread.fork", 1, &[("source", "cli_subcommand")]);
session_telemetry.counter(
"codex.thread.fork",
/*inc*/ 1,
&[("source", "cli_subcommand")],
);
let forked = app_server
.fork_thread(config.clone(), target_session.thread_id)
.await
@@ -2680,7 +2694,7 @@ impl App {
.await;
}
AppEvent::ClearUi => {
self.clear_terminal_ui(tui, false)?;
self.clear_terminal_ui(tui, /*redraw_header*/ false)?;
self.reset_app_ui_state_after_clear();
self.start_fresh_session_with_summary_hint(tui, app_server)
@@ -2707,7 +2721,7 @@ impl App {
match crate::resume_picker::run_resume_picker_with_app_server(
tui,
&self.config,
false,
/*show_all*/ false,
picker_app_server,
)
.await?
@@ -2724,7 +2738,7 @@ impl App {
target_session.thread_id,
target_session.path.as_deref(),
CwdPromptAction::Resume,
true,
/*allow_prompt*/ true,
)
.await?
{
@@ -2806,7 +2820,7 @@ impl App {
AppEvent::ForkCurrentSession => {
self.session_telemetry.counter(
"codex.thread.fork",
1,
/*inc*/ 1,
&[("source", "slash_command")],
);
let summary = session_summary(
@@ -3065,7 +3079,7 @@ impl App {
AppEvent::OpenWindowsSandboxFallbackPrompt { preset } => {
self.session_telemetry.counter(
"codex.windows_sandbox.fallback_prompt_shown",
1,
/*inc*/ 1,
&[],
);
self.chat_widget.clear_windows_sandbox_setup_status();
@@ -3259,7 +3273,7 @@ impl App {
self.chat_widget
.add_to_history(history_cell::new_info_event(
format!("Sandbox read access granted for {}", path.display()),
None,
/*hint*/ None,
));
}
},
@@ -3398,7 +3412,7 @@ impl App {
message.push_str(profile);
message.push_str(" profile");
}
self.chat_widget.add_info_message(message, None);
self.chat_widget.add_info_message(message, /*hint*/ None);
}
Err(err) => {
tracing::error!(
@@ -3432,7 +3446,7 @@ impl App {
message.push_str(profile);
message.push_str(" profile");
}
self.chat_widget.add_info_message(message, None);
self.chat_widget.add_info_message(message, /*hint*/ None);
}
Err(err) => {
tracing::error!(
@@ -3468,7 +3482,7 @@ impl App {
message.push_str(profile);
message.push_str(" profile");
}
self.chat_widget.add_info_message(message, None);
self.chat_widget.add_info_message(message, /*hint*/ None);
}
Err(err) => {
tracing::error!(error = %err, "failed to persist fast mode selection");
@@ -3515,7 +3529,7 @@ impl App {
let selection = name.unwrap_or_else(|| "System default".to_string());
self.chat_widget.add_info_message(
format!("Realtime {} set to {selection}", kind.noun()),
None,
/*hint*/ None,
);
}
}
@@ -3661,7 +3675,7 @@ impl App {
}
AppEvent::PersistFullAccessWarningAcknowledged => {
if let Err(err) = ConfigEditsBuilder::new(&self.config.codex_home)
.set_hide_full_access_warning(true)
.set_hide_full_access_warning(/*acknowledged*/ true)
.apply()
.await
{
@@ -3676,7 +3690,7 @@ impl App {
}
AppEvent::PersistWorldWritableWarningAcknowledged => {
if let Err(err) = ConfigEditsBuilder::new(&self.config.codex_home)
.set_hide_world_writable_warning(true)
.set_hide_world_writable_warning(/*acknowledged*/ true)
.apply()
.await
{
@@ -3691,7 +3705,7 @@ impl App {
}
AppEvent::PersistRateLimitSwitchPromptHidden => {
if let Err(err) = ConfigEditsBuilder::new(&self.config.codex_home)
.set_hide_rate_limit_model_nudge(true)
.set_hide_rate_limit_model_nudge(/*acknowledged*/ true)
.apply()
.await
{
@@ -4090,7 +4104,7 @@ impl App {
format!(
"Agent thread {closed_thread_id} closed. Switched back to main thread."
),
None,
/*hint*/ None,
);
} else {
self.clear_active_thread().await;
@@ -4237,7 +4251,7 @@ impl App {
fn reset_external_editor_state(&mut self, tui: &mut tui::Tui) {
self.chat_widget
.set_external_editor_state(ExternalEditorState::Closed);
self.chat_widget.set_footer_hint_override(None);
self.chat_widget.set_footer_hint_override(/*items*/ None);
tui.frame_requester().schedule_frame();
}
@@ -4301,7 +4315,7 @@ impl App {
if !self.chat_widget.can_run_ctrl_l_clear_now() {
return;
}
if let Err(err) = self.clear_terminal_ui(tui, false) {
if let Err(err) = self.clear_terminal_ui(tui, /*redraw_header*/ false) {
tracing::warn!(error = %err, "failed to clear terminal UI");
self.chat_widget
.add_error_message(format!("Failed to clear terminal UI: {err}"));
@@ -106,7 +106,10 @@ impl AgentNavigationState {
if let Some(entry) = self.threads.get_mut(&thread_id) {
entry.is_closed = true;
} else {
self.upsert(thread_id, None, None, true);
self.upsert(
thread_id, /*agent_nickname*/ None, /*agent_role*/ None,
/*is_closed*/ true,
);
}
}
@@ -202,7 +205,11 @@ impl AgentNavigationState {
is_primary,
)
})
.unwrap_or_else(|| format_agent_picker_item_name(None, None, is_primary)),
.unwrap_or_else(|| {
format_agent_picker_item_name(
/*agent_nickname*/ None, /*agent_role*/ None, is_primary,
)
}),
)
}
+1 -1
View File
@@ -345,7 +345,7 @@ impl App {
} else {
self.backtrack.nth_user_message = usize::MAX;
if let Some(Overlay::Transcript(t)) = &mut self.overlay {
t.set_highlight_cell(None);
t.set_highlight_cell(/*cell*/ None);
}
}
}
@@ -82,7 +82,7 @@ impl AppEventSender {
pub(crate) fn exec_approval(&self, thread_id: ThreadId, id: String, decision: ReviewDecision) {
self.send(AppEvent::SubmitThreadOp {
thread_id,
op: AppCommand::exec_approval(id, None, decision).into_core(),
op: AppCommand::exec_approval(id, /*turn_id*/ None, decision).into_core(),
});
}
@@ -19,7 +19,7 @@ pub(crate) struct AsciiAnimation {
impl AsciiAnimation {
pub(crate) fn new(request_frame: FrameRequester) -> Self {
Self::with_variants(request_frame, ALL_VARIANTS, 0)
Self::with_variants(request_frame, ALL_VARIANTS, /*variant_idx*/ 0)
}
pub(crate) fn with_variants(
@@ -156,8 +156,8 @@ impl AppLinkView {
target.server_name.clone(),
target.request_id.clone(),
decision,
None,
None,
/*content*/ None,
/*meta*/ None,
);
}
@@ -505,7 +505,7 @@ impl crate::render::renderable::Renderable for AppLinkView {
])
.areas(area);
let inner = content_area.inset(Insets::vh(1, 2));
let inner = content_area.inset(Insets::vh(/*v*/ 1, /*h*/ 2));
let content_width = inner.width.max(1);
let lines = self.content_lines(content_width);
Paragraph::new(lines)
@@ -342,8 +342,8 @@ impl ApprovalOverlay {
server_name.to_string(),
request_id.clone(),
decision,
None,
None,
/*content*/ None,
/*meta*/ None,
);
}
@@ -674,7 +674,12 @@ impl ChatComposer {
};
let [composer_rect, popup_rect] =
Layout::vertical([Constraint::Min(3), popup_constraint]).areas(area);
let mut textarea_rect = composer_rect.inset(Insets::tlbr(1, LIVE_PREFIX_COLS, 1, 1));
let mut textarea_rect = composer_rect.inset(Insets::tlbr(
/*top*/ 1,
LIVE_PREFIX_COLS,
/*bottom*/ 1,
/*right*/ 1,
));
let remote_images_height = self
.remote_images_lines(textarea_rect.width)
.len()
@@ -1037,7 +1042,7 @@ impl ChatComposer {
self.bind_mentions_from_snapshot(mention_bindings);
self.relabel_attached_images_and_update_placeholders();
self.selected_remote_image_index = None;
self.textarea.set_cursor(0);
self.textarea.set_cursor(/*pos*/ 0);
self.sync_popups();
}
@@ -2092,14 +2097,14 @@ impl ChatComposer {
///
/// The returned string **does not** include the leading `@`.
fn current_at_token(textarea: &TextArea) -> Option<String> {
Self::current_prefixed_token(textarea, '@', false)
Self::current_prefixed_token(textarea, '@', /*allow_empty*/ false)
}
fn current_mention_token(&self) -> Option<String> {
if !self.mentions_enabled() {
return None;
}
Self::current_prefixed_token(&self.textarea, '$', true)
Self::current_prefixed_token(&self.textarea, '$', /*allow_empty*/ true)
}
/// Replace the active `@token` (the one under the cursor) with `path`.
@@ -2342,7 +2347,7 @@ impl ChatComposer {
)));
} else {
self.app_event_tx.send(AppEvent::InsertHistoryCell(Box::new(
history_cell::new_info_event(message, None),
history_cell::new_info_event(message, /*hint*/ None),
)));
}
self.set_text_content_with_mention_bindings(
@@ -2495,7 +2500,9 @@ impl ChatComposer {
return (result, true);
}
if let Some((text, text_elements)) = self.prepare_submission_text(true) {
if let Some((text, text_elements)) =
self.prepare_submission_text(/*record_history*/ true)
{
if should_queue {
(
InputResult::Queued {
@@ -2802,7 +2809,7 @@ impl ChatComposer {
code: KeyCode::Enter,
modifiers: KeyModifiers::NONE,
..
} => self.handle_submission(false),
} => self.handle_submission(/*should_queue*/ false),
input => self.handle_input_basic(input),
}
}
@@ -4175,7 +4182,7 @@ impl Renderable for ChatComposer {
}
fn render(&self, area: Rect, buf: &mut Buffer) {
self.render_with_mask(area, buf, None);
self.render_with_mask(area, buf, /*mask_char*/ None);
}
}
@@ -4269,7 +4276,10 @@ impl ChatComposer {
let right_line = if status_line_active {
let full =
mode_indicator_line(self.collaboration_mode_indicator, show_cycle_hint);
let compact = mode_indicator_line(self.collaboration_mode_indicator, false);
let compact = mode_indicator_line(
self.collaboration_mode_indicator,
/*show_cycle_hint*/ false,
);
let full_width = full.as_ref().map(|l| l.width() as u16).unwrap_or(0);
if can_show_left_with_context(hint_rect, left_width, full_width) {
full
@@ -275,7 +275,9 @@ impl WidgetRef for CommandPopup {
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
let rows = self.rows_from_matches(self.filtered());
render_rows(
area.inset(Insets::tlbr(0, 2, 0, 0)),
area.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
buf,
&rows,
&self.state,
@@ -243,7 +243,7 @@ impl Renderable for ExperimentalFeaturesView {
Constraint::Max(1),
Constraint::Length(rows_height),
])
.areas(content_area.inset(Insets::vh(1, 2)));
.areas(content_area.inset(Insets::vh(/*v*/ 1, /*h*/ 2)));
self.header.render(header_area, buf);
@@ -104,7 +104,7 @@ impl FeedbackNoteView {
self.include_logs,
&attachment_paths,
Some(SessionSource::Cli),
None,
/*logs_override*/ None,
);
match result {
@@ -141,7 +141,9 @@ impl WidgetRef for &FileSearchPopup {
};
render_rows(
area.inset(Insets::tlbr(0, 2, 0, 0)),
area.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
buf,
&rows_all,
&self.state,
@@ -199,7 +199,14 @@ pub(crate) fn footer_height(props: &FooterProps) -> u16 {
| FooterMode::ShortcutOverlay
| FooterMode::EscHint => false,
};
footer_from_props_lines(props, None, false, show_shortcuts_hint, show_queue_hint).len() as u16
footer_from_props_lines(
props,
/*collaboration_mode_indicator*/ None,
/*show_cycle_hint*/ false,
show_shortcuts_hint,
show_queue_hint,
)
.len() as u16
}
/// Render a single precomputed footer line.
@@ -1088,8 +1088,8 @@ impl McpServerElicitationOverlay {
self.request.server_name.clone(),
self.request.request_id.clone(),
ElicitationAction::Cancel,
None,
None,
/*content*/ None,
/*meta*/ None,
);
}
@@ -1102,30 +1102,31 @@ impl McpServerElicitationOverlay {
}
self.validation_error = None;
if self.request.response_mode == McpServerElicitationResponseMode::ApprovalAction {
let (decision, meta) = match self.field_value(0).as_ref().and_then(Value::as_str) {
Some(APPROVAL_ACCEPT_ONCE_VALUE) => (ElicitationAction::Accept, None),
Some(APPROVAL_ACCEPT_SESSION_VALUE) => (
ElicitationAction::Accept,
Some(serde_json::json!({
APPROVAL_PERSIST_KEY: APPROVAL_PERSIST_SESSION_VALUE,
})),
),
Some(APPROVAL_ACCEPT_ALWAYS_VALUE) => (
ElicitationAction::Accept,
Some(serde_json::json!({
APPROVAL_PERSIST_KEY: APPROVAL_PERSIST_ALWAYS_VALUE,
})),
),
Some(APPROVAL_DECLINE_VALUE) => (ElicitationAction::Decline, None),
Some(APPROVAL_CANCEL_VALUE) => (ElicitationAction::Cancel, None),
_ => (ElicitationAction::Cancel, None),
};
let (decision, meta) =
match self.field_value(/*idx*/ 0).as_ref().and_then(Value::as_str) {
Some(APPROVAL_ACCEPT_ONCE_VALUE) => (ElicitationAction::Accept, None),
Some(APPROVAL_ACCEPT_SESSION_VALUE) => (
ElicitationAction::Accept,
Some(serde_json::json!({
APPROVAL_PERSIST_KEY: APPROVAL_PERSIST_SESSION_VALUE,
})),
),
Some(APPROVAL_ACCEPT_ALWAYS_VALUE) => (
ElicitationAction::Accept,
Some(serde_json::json!({
APPROVAL_PERSIST_KEY: APPROVAL_PERSIST_ALWAYS_VALUE,
})),
),
Some(APPROVAL_DECLINE_VALUE) => (ElicitationAction::Decline, None),
Some(APPROVAL_CANCEL_VALUE) => (ElicitationAction::Cancel, None),
_ => (ElicitationAction::Cancel, None),
};
self.app_event_tx.resolve_elicitation(
self.request.thread_id,
self.request.server_name.clone(),
self.request.request_id.clone(),
decision,
None,
/*content*/ None,
meta,
);
if let Some(next) = self.queue.pop_front() {
@@ -1150,7 +1151,7 @@ impl McpServerElicitationOverlay {
self.request.request_id.clone(),
ElicitationAction::Accept,
Some(Value::Object(content)),
None,
/*meta*/ None,
);
if let Some(next) = self.queue.pop_front() {
self.request = next;
@@ -1165,7 +1166,7 @@ impl McpServerElicitationOverlay {
if self.current_index() + 1 >= self.field_count() {
self.submit_answers();
} else {
self.move_field(true);
self.move_field(/*next*/ true);
}
}
@@ -1460,7 +1461,7 @@ impl BottomPaneView for McpServerElicitationOverlay {
modifiers: KeyModifiers::NONE,
..
} => {
self.move_field(false);
self.move_field(/*next*/ false);
return;
}
KeyEvent {
@@ -1473,7 +1474,7 @@ impl BottomPaneView for McpServerElicitationOverlay {
modifiers: KeyModifiers::NONE,
..
} => {
self.move_field(true);
self.move_field(/*next*/ true);
return;
}
KeyEvent {
@@ -1481,7 +1482,7 @@ impl BottomPaneView for McpServerElicitationOverlay {
modifiers: KeyModifiers::NONE,
..
} if self.current_field_is_select() => {
self.move_field(false);
self.move_field(/*next*/ false);
return;
}
KeyEvent {
@@ -1489,7 +1490,7 @@ impl BottomPaneView for McpServerElicitationOverlay {
modifiers: KeyModifiers::NONE,
..
} if self.current_field_is_select() => {
self.move_field(true);
self.move_field(/*next*/ true);
return;
}
_ => {}
@@ -1512,10 +1513,10 @@ impl BottomPaneView for McpServerElicitationOverlay {
}
}
KeyCode::Backspace | KeyCode::Delete => self.clear_selection(),
KeyCode::Char(' ') => self.select_current_option(true),
KeyCode::Char(' ') => self.select_current_option(/*committed*/ true),
KeyCode::Enter => {
if self.selected_option_index().is_some() {
self.select_current_option(true);
self.select_current_option(/*committed*/ true);
}
self.go_next_or_submit();
}
@@ -1524,7 +1525,7 @@ impl BottomPaneView for McpServerElicitationOverlay {
if let Some(answer) = self.current_answer_mut() {
answer.selection.selected_idx = Some(option_idx);
}
self.select_current_option(true);
self.select_current_option(/*committed*/ true);
self.go_next_or_submit();
}
}
+25 -16
View File
@@ -699,14 +699,14 @@ impl BottomPane {
pub(crate) fn show_esc_backtrack_hint(&mut self) {
self.esc_backtrack_hint = true;
self.composer.set_esc_backtrack_hint(true);
self.composer.set_esc_backtrack_hint(/*show*/ true);
self.request_redraw();
}
pub(crate) fn clear_esc_backtrack_hint(&mut self) {
if self.esc_backtrack_hint {
self.esc_backtrack_hint = false;
self.composer.set_esc_backtrack_hint(false);
self.composer.set_esc_backtrack_hint(/*show*/ false);
self.request_redraw();
}
}
@@ -728,7 +728,7 @@ impl BottomPane {
));
}
if let Some(status) = self.status.as_mut() {
status.set_interrupt_hint_visible(true);
status.set_interrupt_hint_visible(/*visible*/ true);
}
self.sync_status_inline_message();
self.request_redraw();
@@ -936,7 +936,7 @@ impl BottomPane {
);
self.pause_status_timer_for_modal();
self.set_composer_input_enabled(
false,
/*enabled*/ false,
Some("Answer the questions to continue.".to_string()),
);
self.push_view(Box::new(modal));
@@ -997,7 +997,7 @@ impl BottomPane {
);
self.pause_status_timer_for_modal();
self.set_composer_input_enabled(
false,
/*enabled*/ false,
Some("Respond to the tool suggestion to continue.".to_string()),
);
self.push_view(Box::new(view));
@@ -1013,7 +1013,7 @@ impl BottomPane {
);
self.pause_status_timer_for_modal();
self.set_composer_input_enabled(
false,
/*enabled*/ false,
Some("Respond to the MCP server request to continue.".to_string()),
);
self.push_view(Box::new(modal));
@@ -1021,7 +1021,7 @@ impl BottomPane {
fn on_active_view_complete(&mut self) {
self.resume_status_timer_after_modal();
self.set_composer_input_enabled(true, None);
self.set_composer_input_enabled(/*enabled*/ true, /*placeholder*/ None);
}
fn pause_status_timer_for_modal(&mut self) {
@@ -1124,12 +1124,15 @@ impl BottomPane {
} else {
let mut flex = FlexRenderable::new();
if let Some(status) = &self.status {
flex.push(0, RenderableItem::Borrowed(status));
flex.push(/*flex*/ 0, RenderableItem::Borrowed(status));
}
// Avoid double-surfacing the same summary and avoid adding an extra
// row while the status line is already visible.
if self.status.is_none() && !self.unified_exec_footer.is_empty() {
flex.push(0, RenderableItem::Borrowed(&self.unified_exec_footer));
flex.push(
/*flex*/ 0,
RenderableItem::Borrowed(&self.unified_exec_footer),
);
}
let has_pending_thread_approvals = !self.pending_thread_approvals.is_empty();
let has_pending_input = !self.pending_input_preview.queued_messages.is_empty()
@@ -1138,19 +1141,25 @@ impl BottomPane {
self.status.is_some() || !self.unified_exec_footer.is_empty();
let has_inline_previews = has_pending_thread_approvals || has_pending_input;
if has_inline_previews && has_status_or_footer {
flex.push(0, RenderableItem::Owned("".into()));
flex.push(/*flex*/ 0, RenderableItem::Owned("".into()));
}
flex.push(1, RenderableItem::Borrowed(&self.pending_thread_approvals));
flex.push(
/*flex*/ 1,
RenderableItem::Borrowed(&self.pending_thread_approvals),
);
if has_pending_thread_approvals && has_pending_input {
flex.push(0, RenderableItem::Owned("".into()));
flex.push(/*flex*/ 0, RenderableItem::Owned("".into()));
}
flex.push(1, RenderableItem::Borrowed(&self.pending_input_preview));
flex.push(
/*flex*/ 1,
RenderableItem::Borrowed(&self.pending_input_preview),
);
if !has_inline_previews && has_status_or_footer {
flex.push(0, RenderableItem::Owned("".into()));
flex.push(/*flex*/ 0, RenderableItem::Owned("".into()));
}
let mut flex2 = FlexRenderable::new();
flex2.push(1, RenderableItem::Owned(flex.into()));
flex2.push(0, RenderableItem::Borrowed(&self.composer));
flex2.push(/*flex*/ 1, RenderableItem::Owned(flex.into()));
flex2.push(/*flex*/ 0, RenderableItem::Borrowed(&self.composer));
RenderableItem::Owned(Box::new(flex2))
}
}
@@ -533,7 +533,7 @@ impl Renderable for MultiSelectPicker {
Constraint::Length(2),
Constraint::Length(rows_height),
])
.areas(content_area.inset(Insets::vh(1, 2)));
.areas(content_area.inset(Insets::vh(/*v*/ 1, /*h*/ 2)));
self.header.render(header_area, buf);
@@ -707,7 +707,7 @@ impl RequestUserInputOverlay {
self.submit_answers();
}
} else {
self.move_question(true);
self.move_question(/*next*/ true);
}
}
@@ -958,10 +958,10 @@ impl RequestUserInputOverlay {
}
}
KeyCode::Up | KeyCode::Char('k') => {
state.move_up_wrap(2);
state.move_up_wrap(/*len*/ 2);
}
KeyCode::Down | KeyCode::Char('j') => {
state.move_down_wrap(2);
state.move_down_wrap(/*len*/ 2);
}
KeyCode::Enter => {
let selected = state.selected_idx.unwrap_or(0);
@@ -1024,7 +1024,7 @@ impl BottomPaneView for RequestUserInputOverlay {
modifiers: KeyModifiers::NONE,
..
} => {
self.move_question(false);
self.move_question(/*next*/ false);
return;
}
KeyEvent {
@@ -1037,7 +1037,7 @@ impl BottomPaneView for RequestUserInputOverlay {
modifiers: KeyModifiers::CONTROL,
..
} => {
self.move_question(true);
self.move_question(/*next*/ true);
return;
}
KeyEvent {
@@ -1045,7 +1045,7 @@ impl BottomPaneView for RequestUserInputOverlay {
modifiers: KeyModifiers::NONE,
..
} if self.has_options() && matches!(self.focus, Focus::Options) => {
self.move_question(false);
self.move_question(/*next*/ false);
return;
}
KeyEvent {
@@ -1053,7 +1053,7 @@ impl BottomPaneView for RequestUserInputOverlay {
modifiers: KeyModifiers::NONE,
..
} if self.has_options() && matches!(self.focus, Focus::Options) => {
self.move_question(false);
self.move_question(/*next*/ false);
return;
}
KeyEvent {
@@ -1061,7 +1061,7 @@ impl BottomPaneView for RequestUserInputOverlay {
modifiers: KeyModifiers::NONE,
..
} if self.has_options() && matches!(self.focus, Focus::Options) => {
self.move_question(true);
self.move_question(/*next*/ true);
return;
}
KeyEvent {
@@ -1069,7 +1069,7 @@ impl BottomPaneView for RequestUserInputOverlay {
modifiers: KeyModifiers::NONE,
..
} if self.has_options() && matches!(self.focus, Focus::Options) => {
self.move_question(true);
self.move_question(/*next*/ true);
return;
}
_ => {}
@@ -1105,7 +1105,7 @@ impl BottomPaneView for RequestUserInputOverlay {
}
}
KeyCode::Char(' ') => {
self.select_current_option(true);
self.select_current_option(/*committed*/ true);
}
KeyCode::Backspace | KeyCode::Delete => {
self.clear_selection();
@@ -1119,7 +1119,7 @@ impl BottomPaneView for RequestUserInputOverlay {
KeyCode::Enter => {
let has_selection = self.selected_option_index().is_some();
if has_selection {
self.select_current_option(true);
self.select_current_option(/*committed*/ true);
}
self.go_next_or_submit();
}
@@ -1128,7 +1128,7 @@ impl BottomPaneView for RequestUserInputOverlay {
if let Some(answer) = self.current_answer_mut() {
answer.options_state.selected_idx = Some(option_idx);
}
self.select_current_option(true);
self.select_current_option(/*committed*/ true);
self.go_next_or_submit();
}
}
@@ -1158,7 +1158,7 @@ impl BottomPaneView for RequestUserInputOverlay {
if !self.handle_composer_input_result(result) {
self.pending_submission_draft = None;
if self.has_options() {
self.select_current_option(true);
self.select_current_option(/*committed*/ true);
}
self.go_next_or_submit();
}
@@ -199,7 +199,9 @@ impl WidgetRef for SkillPopup {
};
let rows = self.rows_from_matches(self.filtered());
render_rows_single_line(
list_area.inset(Insets::tlbr(0, 2, 0, 0)),
list_area.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
buf,
&rows,
&self.state,
@@ -186,7 +186,8 @@ impl SkillsToggleView {
}
self.complete = true;
self.app_event_tx.send(AppEvent::ManageSkillsClosed);
self.app_event_tx.list_skills(Vec::new(), true);
self.app_event_tx
.list_skills(Vec::new(), /*force_reload*/ true);
}
fn rows_width(total_width: u16) -> u16 {
@@ -310,7 +311,7 @@ impl Renderable for SkillsToggleView {
Constraint::Length(2),
Constraint::Length(rows_height),
])
.areas(content_area.inset(Insets::vh(1, 2)));
.areas(content_area.inset(Insets::vh(/*v*/ 1, /*h*/ 2)));
self.header.render(header_area, buf);
@@ -205,7 +205,7 @@ impl StatusLineSetupView {
if !used_ids.insert(item_id.clone()) {
continue;
}
items.push(Self::status_line_select_item(item, true));
items.push(Self::status_line_select_item(item, /*enabled*/ true));
}
}
@@ -214,7 +214,7 @@ impl StatusLineSetupView {
if used_ids.contains(&item_id) {
continue;
}
items.push(Self::status_line_select_item(item, false));
items.push(Self::status_line_select_item(item, /*enabled*/ false));
}
Self {
@@ -101,7 +101,7 @@ impl TextArea {
/// as submit or slash-command dispatch clear the draft through this method and still want
/// `Ctrl+Y` to recover the user's most recent kill.
pub fn set_text_clearing_elements(&mut self, text: &str) {
self.set_text_inner(text, None);
self.set_text_inner(text, /*elements*/ None);
}
/// Replace the visible textarea text and rebuild the provided text elements.
@@ -160,7 +160,7 @@ impl TextArea {
if pos <= self.cursor_pos {
self.cursor_pos += text.len();
}
self.shift_elements(pos, 0, text.len());
self.shift_elements(pos, /*removed*/ 0, text.len());
self.preferred_col = None;
}
@@ -355,7 +355,7 @@ impl TextArea {
code: KeyCode::Char('h'),
modifiers: KeyModifiers::CONTROL,
..
} => self.delete_backward(1),
} => self.delete_backward(/*n*/ 1),
KeyEvent {
code: KeyCode::Delete,
modifiers: KeyModifiers::ALT,
@@ -374,7 +374,7 @@ impl TextArea {
code: KeyCode::Char('d'),
modifiers: KeyModifiers::CONTROL,
..
} => self.delete_forward(1),
} => self.delete_forward(/*n*/ 1),
KeyEvent {
code: KeyCode::Char('w'),
@@ -507,27 +507,27 @@ impl TextArea {
code: KeyCode::Home,
..
} => {
self.move_cursor_to_beginning_of_line(false);
self.move_cursor_to_beginning_of_line(/*move_up_at_bol*/ false);
}
KeyEvent {
code: KeyCode::Char('a'),
modifiers: KeyModifiers::CONTROL,
..
} => {
self.move_cursor_to_beginning_of_line(true);
self.move_cursor_to_beginning_of_line(/*move_up_at_bol*/ true);
}
KeyEvent {
code: KeyCode::End, ..
} => {
self.move_cursor_to_end_of_line(false);
self.move_cursor_to_end_of_line(/*move_down_at_eol*/ false);
}
KeyEvent {
code: KeyCode::Char('e'),
modifiers: KeyModifiers::CONTROL,
..
} => {
self.move_cursor_to_end_of_line(true);
self.move_cursor_to_end_of_line(/*move_down_at_eol*/ true);
}
_o => {
#[cfg(feature = "debug-logs")]
@@ -999,7 +999,7 @@ impl TextArea {
}
fn add_element(&mut self, range: Range<usize>) -> u64 {
self.add_element_with_id(range, None)
self.add_element_with_id(range, /*name*/ None)
}
/// Mark an existing text range as an atomic element without changing the text.
@@ -1228,7 +1228,7 @@ impl TextArea {
}
start = idx;
}
self.adjust_pos_out_of_elements(start, true)
self.adjust_pos_out_of_elements(start, /*prefer_start*/ true)
}
pub(crate) fn end_of_next_word(&self) -> usize {
@@ -1249,7 +1249,7 @@ impl TextArea {
break;
}
}
self.adjust_pos_out_of_elements(end, false)
self.adjust_pos_out_of_elements(end, /*prefer_start*/ false)
}
fn adjust_pos_out_of_elements(&self, pos: usize, prefer_start: bool) -> usize {
+193 -126
View File
@@ -1194,7 +1194,7 @@ impl ChatWidget {
fn set_status_header(&mut self, header: String) {
self.set_status(
header,
None,
/*details*/ None,
StatusDetailsCapitalization::CapitalizeFirst,
STATUS_DETAILS_DEFAULT_MAX_LINES,
);
@@ -1251,7 +1251,7 @@ impl ChatWidget {
let enabled = !items.is_empty();
self.bottom_pane.set_status_line_enabled(enabled);
if !enabled {
self.set_status_line(None);
self.set_status_line(/*status_line*/ None);
return;
}
@@ -1356,7 +1356,7 @@ impl ChatWidget {
fn on_session_configured(&mut self, event: codex_protocol::protocol::SessionConfiguredEvent) {
self.bottom_pane
.set_history_metadata(event.history_log_id, event.history_entry_count);
self.set_skills(None);
self.set_skills(/*skills*/ None);
self.session_network_proxy = event.network_proxy.clone();
self.thread_id = Some(event.session_id);
self.thread_name = event.thread_name.clone();
@@ -1393,7 +1393,7 @@ impl ChatWidget {
self.current_collaboration_mode = self.current_collaboration_mode.with_updates(
Some(model_for_header.clone()),
Some(event.reasoning_effort),
None,
/*developer_instructions*/ None,
);
if let Some(mask) = self.active_collaboration_mask.as_mut() {
mask.model = Some(model_for_header.clone());
@@ -1419,7 +1419,10 @@ impl ChatWidget {
if let Some(messages) = initial_messages {
self.replay_initial_messages(messages);
}
self.submit_op(AppCommand::list_skills(Vec::new(), true));
self.submit_op(AppCommand::list_skills(
Vec::new(),
/*force_reload*/ true,
));
if self.connectors_enabled() {
self.prefetch_connectors();
}
@@ -1671,7 +1674,8 @@ impl ChatWidget {
fn on_task_started(&mut self) {
self.agent_turn_running = true;
self.turn_sleep_inhibitor.set_turn_running(true);
self.turn_sleep_inhibitor
.set_turn_running(/*turn_running*/ true);
self.saw_plan_update_this_turn = false;
self.saw_plan_item_this_turn = false;
self.plan_delta_buffer.clear();
@@ -1686,7 +1690,8 @@ impl ChatWidget {
self.update_task_running_state();
self.retry_status_header = None;
self.pending_status_indicator_restore = false;
self.bottom_pane.set_interrupt_hint_visible(true);
self.bottom_pane
.set_interrupt_hint_visible(/*visible*/ true);
self.set_status_header(String::from("Working"));
self.full_reasoning_buffer.clear();
self.reasoning_buffer.clear();
@@ -1735,7 +1740,8 @@ impl ChatWidget {
// Mark task stopped and request redraw now that all content is in history.
self.pending_status_indicator_restore = false;
self.agent_turn_running = false;
self.turn_sleep_inhibitor.set_turn_running(false);
self.turn_sleep_inhibitor
.set_turn_running(/*turn_running*/ false);
self.update_task_running_state();
self.running_commands.clear();
self.suppressed_exec_calls.clear();
@@ -1879,7 +1885,8 @@ impl ChatWidget {
match info {
Some(info) => self.apply_token_info(info),
None => {
self.bottom_pane.set_context_window(None, None);
self.bottom_pane
.set_context_window(/*percent*/ None, /*used_tokens*/ None);
self.token_info = None;
}
}
@@ -1933,7 +1940,8 @@ impl ChatWidget {
match saved {
Some(info) => self.apply_token_info(info),
None => {
self.bottom_pane.set_context_window(None, None);
self.bottom_pane
.set_context_window(/*percent*/ None, /*used_tokens*/ None);
self.token_info = None;
}
}
@@ -2033,7 +2041,8 @@ impl ChatWidget {
self.finalize_active_cell_as_failed();
// Reset running state and clear streaming buffers.
self.agent_turn_running = false;
self.turn_sleep_inhibitor.set_turn_running(false);
self.turn_sleep_inhibitor
.set_turn_running(/*turn_running*/ false);
self.update_task_running_state();
self.running_commands.clear();
self.suppressed_exec_calls.clear();
@@ -2157,7 +2166,7 @@ impl ChatWidget {
if send_pending_steers_immediately {
self.add_to_history(history_cell::new_info_event(
"Model interrupted to submit steer instructions.".to_owned(),
None,
/*hint*/ None,
));
} else {
self.add_to_history(history_cell::new_error_event(
@@ -2437,7 +2446,8 @@ impl ChatWidget {
// review is pending. Parallel reviews are aggregated into one
// footer summary by `PendingGuardianReviewStatus`.
self.bottom_pane.ensure_status_indicator();
self.bottom_pane.set_interrupt_hint_visible(true);
self.bottom_pane
.set_interrupt_hint_visible(/*visible*/ true);
self.pending_guardian_review_status
.start_or_update(ev.id.clone(), detail);
if let Some(status) = self.pending_guardian_review_status.status_indicator_state() {
@@ -2641,12 +2651,13 @@ impl ChatWidget {
// Surface this in the status indicator (single "waiting" surface) instead of
// the transcript. Keep the header short so the interrupt hint remains visible.
self.bottom_pane.ensure_status_indicator();
self.bottom_pane.set_interrupt_hint_visible(true);
self.bottom_pane
.set_interrupt_hint_visible(/*visible*/ true);
self.set_status(
"Waiting for background terminal".to_string(),
command_display.clone(),
StatusDetailsCapitalization::Preserve,
1,
/*details_max_lines*/ 1,
);
match &mut self.unified_exec_wait_streak {
Some(wait) if wait.process_id == ev.process_id => {
@@ -2896,7 +2907,8 @@ impl ChatWidget {
fn on_background_event(&mut self, message: String) {
debug!("BackgroundEvent: {message}");
self.bottom_pane.ensure_status_indicator();
self.bottom_pane.set_interrupt_hint_visible(true);
self.bottom_pane
.set_interrupt_hint_visible(/*visible*/ true);
self.set_status_header(message);
}
@@ -2909,7 +2921,7 @@ impl ChatWidget {
message.push_str(": ");
message.push_str(&status_message);
}
self.add_to_history(history_cell::new_info_event(message, None));
self.add_to_history(history_cell::new_info_event(message, /*hint*/ None));
self.request_redraw();
}
@@ -2933,7 +2945,8 @@ impl ChatWidget {
fn on_undo_started(&mut self, event: UndoStartedEvent) {
self.bottom_pane.ensure_status_indicator();
self.bottom_pane.set_interrupt_hint_visible(false);
self.bottom_pane
.set_interrupt_hint_visible(/*visible*/ false);
let message = event
.message
.unwrap_or_else(|| "Undo in progress...".to_string());
@@ -2951,7 +2964,7 @@ impl ChatWidget {
}
});
if success {
self.add_info_message(message, None);
self.add_info_message(message, /*hint*/ None);
} else {
self.add_error_message(message);
}
@@ -3091,7 +3104,7 @@ impl ChatWidget {
.map(|current| self.worked_elapsed_from(current));
self.add_to_history(history_cell::FinalMessageSeparator::new(
elapsed_seconds,
None,
/*runtime_metrics*/ None,
));
self.needs_final_message_separator = false;
self.had_work_activity = false;
@@ -3652,7 +3665,9 @@ impl ChatWidget {
widget
.bottom_pane
.set_status_line_enabled(!widget.configured_status_line_items().is_empty());
widget.bottom_pane.set_collaboration_modes_enabled(true);
widget
.bottom_pane
.set_collaboration_modes_enabled(/*enabled*/ true);
widget.sync_fast_command_enabled();
widget.sync_personality_command_enabled();
widget
@@ -3842,7 +3857,9 @@ impl ChatWidget {
widget
.bottom_pane
.set_status_line_enabled(!widget.configured_status_line_items().is_empty());
widget.bottom_pane.set_collaboration_modes_enabled(true);
widget
.bottom_pane
.set_collaboration_modes_enabled(/*enabled*/ true);
widget.sync_fast_command_enabled();
widget.sync_personality_command_enabled();
widget
@@ -4143,7 +4160,7 @@ impl ChatWidget {
let message = format!(
"{DEFAULT_PROJECT_DOC_FILENAME} already exists here. Skipping /init to avoid overwriting it."
);
self.add_info_message(message, None);
self.add_info_message(message, /*hint*/ None);
return;
}
const INIT_PROMPT: &str = include_str!("../prompt_for_init_command.md");
@@ -4158,7 +4175,7 @@ impl ChatWidget {
}
SlashCommand::Rename => {
self.session_telemetry
.counter("codex.thread.rename", 1, &[]);
.counter("codex.thread.rename", /*inc*/ 1, &[]);
self.show_rename_prompt();
}
SlashCommand::Model => {
@@ -4177,7 +4194,7 @@ impl ChatWidget {
return;
}
if self.realtime_conversation.is_live() {
self.request_realtime_conversation_close(None);
self.request_realtime_conversation_close(/*info_message*/ None);
} else {
self.start_realtime_conversation();
}
@@ -4202,7 +4219,10 @@ impl ChatWidget {
if let Some(mask) = collaboration_modes::plan_mask(self.model_catalog.as_ref()) {
self.set_collaboration_mask(mask);
} else {
self.add_info_message("Plan mode unavailable right now.".to_string(), None);
self.add_info_message(
"Plan mode unavailable right now.".to_string(),
/*hint*/ None,
);
}
}
SlashCommand::Collab => {
@@ -4319,7 +4339,7 @@ impl ChatWidget {
self.add_info_message(
"`/copy` is unavailable before the first Codex output or right after a rollback."
.to_string(),
None,
/*hint*/ None,
);
return;
};
@@ -4382,10 +4402,13 @@ impl ChatWidget {
if let Some(path) = self.rollout_path() {
self.add_info_message(
format!("Current rollout path: {}", path.display()),
None,
/*hint*/ None,
);
} else {
self.add_info_message("Rollout path is not available yet.".to_string(), None);
self.add_info_message(
"Rollout path is not available yet.".to_string(),
/*hint*/ None,
);
}
}
SlashCommand::TestApproval => {
@@ -4458,7 +4481,7 @@ impl ChatWidget {
}
match trimmed.to_ascii_lowercase().as_str() {
"on" => self.set_service_tier_selection(Some(ServiceTier::Fast)),
"off" => self.set_service_tier_selection(None),
"off" => self.set_service_tier_selection(/*service_tier*/ None),
"status" => {
let status = if matches!(self.config.service_tier, Some(ServiceTier::Fast))
{
@@ -4466,7 +4489,10 @@ impl ChatWidget {
} else {
"off"
};
self.add_info_message(format!("Fast mode is {status}."), None);
self.add_info_message(
format!("Fast mode is {status}."),
/*hint*/ None,
);
}
_ => {
self.add_error_message("Usage: /fast [on|off|status]".to_string());
@@ -4475,9 +4501,10 @@ impl ChatWidget {
}
SlashCommand::Rename if !trimmed.is_empty() => {
self.session_telemetry
.counter("codex.thread.rename", 1, &[]);
let Some((prepared_args, _prepared_elements)) =
self.bottom_pane.prepare_inline_args_submission(false)
.counter("codex.thread.rename", /*inc*/ 1, &[]);
let Some((prepared_args, _prepared_elements)) = self
.bottom_pane
.prepare_inline_args_submission(/*record_history*/ false)
else {
return;
};
@@ -4496,8 +4523,9 @@ impl ChatWidget {
if self.active_mode_kind() != ModeKind::Plan {
return;
}
let Some((prepared_args, prepared_elements)) =
self.bottom_pane.prepare_inline_args_submission(true)
let Some((prepared_args, prepared_elements)) = self
.bottom_pane
.prepare_inline_args_submission(/*record_history*/ true)
else {
return;
};
@@ -4522,8 +4550,9 @@ impl ChatWidget {
}
}
SlashCommand::Review if !trimmed.is_empty() => {
let Some((prepared_args, _prepared_elements)) =
self.bottom_pane.prepare_inline_args_submission(false)
let Some((prepared_args, _prepared_elements)) = self
.bottom_pane
.prepare_inline_args_submission(/*record_history*/ false)
else {
return;
};
@@ -4536,8 +4565,9 @@ impl ChatWidget {
self.bottom_pane.drain_pending_submission_state();
}
SlashCommand::SandboxReadRoot if !trimmed.is_empty() => {
let Some((prepared_args, _prepared_elements)) =
self.bottom_pane.prepare_inline_args_submission(false)
let Some((prepared_args, _prepared_elements)) = self
.bottom_pane
.prepare_inline_args_submission(/*record_history*/ false)
else {
return;
};
@@ -4566,7 +4596,7 @@ impl ChatWidget {
let view = CustomPromptView::new(
title.to_string(),
"Type a name and press Enter".to_string(),
None,
/*context_label*/ None,
Box::new(move |name: String| {
let Some(name) = codex_core::util::normalize_thread_name(&name) else {
tx.send(AppEvent::InsertHistoryCell(Box::new(
@@ -4862,9 +4892,9 @@ impl ChatWidget {
self.config.permissions.sandbox_policy.get().clone(),
effective_mode.model().to_string(),
effective_mode.reasoning_effort(),
None,
/*summary*/ None,
service_tier,
None,
/*final_output_json_schema*/ None,
collaboration_mode,
personality,
);
@@ -4966,13 +4996,17 @@ impl ChatWidget {
continue;
}
// `id: None` indicates a synthetic/fake id coming from replay.
self.dispatch_event_msg(None, msg, Some(ReplayKind::ResumeInitialMessages));
self.dispatch_event_msg(
/*id*/ None,
msg,
Some(ReplayKind::ResumeInitialMessages),
);
}
}
pub(crate) fn handle_codex_event(&mut self, event: Event) {
let Event { id, msg } = event;
self.dispatch_event_msg(Some(id), msg, None);
self.dispatch_event_msg(Some(id), msg, /*replay_kind*/ None);
}
pub(crate) fn handle_codex_event_replay(&mut self, event: Event) {
@@ -4980,7 +5014,7 @@ impl ChatWidget {
if matches!(msg, EventMsg::ShutdownComplete) {
return;
}
self.dispatch_event_msg(None, msg, Some(ReplayKind::ThreadSnapshot));
self.dispatch_event_msg(/*id*/ None, msg, Some(ReplayKind::ThreadSnapshot));
}
/// Dispatch a protocol `EventMsg` to the appropriate handler.
@@ -5133,7 +5167,10 @@ impl ChatWidget {
EventMsg::ListSkillsResponse(ev) => self.on_list_skills(ev),
EventMsg::ListRemoteSkillsResponse(_) | EventMsg::RemoteSkillDownloaded(_) => {}
EventMsg::SkillsUpdateAvailable => {
self.submit_op(AppCommand::list_skills(Vec::new(), true));
self.submit_op(AppCommand::list_skills(
Vec::new(),
/*force_reload*/ true,
));
}
EventMsg::ShutdownComplete => self.on_shutdown_complete(),
EventMsg::TurnDiff(TurnDiffEvent { unified_diff }) => self.on_turn_diff(unified_diff),
@@ -5286,7 +5323,7 @@ impl ChatWidget {
}
// Avoid toggling running state for replayed history events on resume.
if !from_replay && !self.bottom_pane.is_task_running() {
self.bottom_pane.set_task_running(true);
self.bottom_pane.set_task_running(/*running*/ true);
}
self.is_review_mode = true;
let hint = review
@@ -5316,11 +5353,11 @@ impl ChatWidget {
let mut rendered: Vec<ratatui::text::Line<'static>> = vec!["".into()];
append_markdown(
&explanation,
None,
/*width*/ None,
Some(self.config.cwd.as_path()),
&mut rendered,
);
let body_cell = AgentMessageCell::new(rendered, false);
let body_cell = AgentMessageCell::new(rendered, /*is_first_line*/ false);
self.app_event_tx
.send(AppEvent::InsertHistoryCell(Box::new(body_cell)));
}
@@ -5564,7 +5601,10 @@ impl ChatWidget {
self.config
.config_layer_stack
.get_layers(ConfigLayerStackOrdering::LowestPrecedenceFirst, true)
.get_layers(
ConfigLayerStackOrdering::LowestPrecedenceFirst,
/*include_disabled*/ true,
)
.iter()
.find_map(|layer| match &layer.name {
ConfigLayerSource::Project { dot_codex_folder } => {
@@ -5578,7 +5618,7 @@ impl ChatWidget {
self.status_line_project_root().map(|root| {
root.file_name()
.map(|name| name.to_string_lossy().to_string())
.unwrap_or_else(|| format_directory_display(&root, None))
.unwrap_or_else(|| format_directory_display(&root, /*max_width*/ None))
})
}
@@ -5637,7 +5677,10 @@ impl ChatWidget {
Some(format!("{} {label}{fast_label}", self.model_display_name()))
}
StatusLineItem::CurrentDir => {
Some(format_directory_display(self.status_line_cwd(), None))
Some(format_directory_display(
self.status_line_cwd(),
/*max_width*/ None,
))
}
StatusLineItem::ProjectRoot => self.status_line_project_root_name(),
StatusLineItem::GitBranch => self.status_line_branch.clone(),
@@ -5772,7 +5815,10 @@ impl ChatWidget {
fn clean_background_terminals(&mut self) {
self.submit_op(AppCommand::clean_background_terminals());
self.add_info_message("Stopping all background terminals.".to_string(), None);
self.add_info_message(
"Stopping all background terminals.".to_string(),
/*hint*/ None,
);
}
fn stop_rate_limit_poller(&mut self) {}
@@ -5782,7 +5828,7 @@ impl ChatWidget {
}
fn prefetch_connectors(&mut self) {
self.prefetch_connectors_with_options(false);
self.prefetch_connectors_with_options(/*force_refetch*/ false);
}
fn prefetch_connectors_with_options(&mut self, force_refetch: bool) {
@@ -5837,7 +5883,7 @@ impl ChatWidget {
let connectors = connectors::merge_connectors_with_accessible(
all_connectors,
accessible_connectors,
true,
/*all_connectors_loaded*/ true,
);
Ok(ConnectorsSnapshot { connectors })
}
@@ -5909,17 +5955,17 @@ impl ChatWidget {
let switch_actions: Vec<SelectionAction> = vec![Box::new(move |tx| {
tx.send(AppEvent::CodexOp(
AppCommand::override_turn_context(
None,
None,
None,
None,
None,
/*cwd*/ None,
/*approval_policy*/ None,
/*approvals_reviewer*/ None,
/*sandbox_policy*/ None,
/*windows_sandbox_level*/ None,
Some(switch_model_for_events.clone()),
Some(Some(default_effort)),
None,
None,
None,
None,
/*summary*/ None,
/*service_tier*/ None,
/*collaboration_mode*/ None,
/*personality*/ None,
)
.into_core(),
));
@@ -5985,7 +6031,7 @@ impl ChatWidget {
if !self.is_session_configured() {
self.add_info_message(
"Model selection is disabled until startup completes.".to_string(),
None,
/*hint*/ None,
);
return;
}
@@ -5995,7 +6041,7 @@ impl ChatWidget {
Err(_) => {
self.add_info_message(
"Models are being updated; please try /model again in a moment.".to_string(),
None,
/*hint*/ None,
);
return;
}
@@ -6007,7 +6053,7 @@ impl ChatWidget {
if !self.is_session_configured() {
self.add_info_message(
"Personality selection is disabled until startup completes.".to_string(),
None,
/*hint*/ None,
);
return;
}
@@ -6034,16 +6080,16 @@ impl ChatWidget {
let actions: Vec<SelectionAction> = vec![Box::new(move |tx| {
tx.send(AppEvent::CodexOp(
AppCommand::override_turn_context(
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
/*cwd*/ None,
/*approval_policy*/ None,
/*approvals_reviewer*/ None,
/*sandbox_policy*/ None,
/*windows_sandbox_level*/ None,
/*model*/ None,
/*effort*/ None,
/*summary*/ None,
/*service_tier*/ None,
/*collaboration_mode*/ None,
Some(personality),
)
.into_core(),
@@ -6371,7 +6417,7 @@ impl ChatWidget {
if presets.is_empty() {
self.add_info_message(
"No additional models are available right now.".to_string(),
None,
/*hint*/ None,
);
return;
}
@@ -6417,7 +6463,7 @@ impl ChatWidget {
if presets.is_empty() {
self.add_info_message(
"No collaboration modes are available right now.".to_string(),
None,
/*hint*/ None,
);
return;
}
@@ -7019,17 +7065,17 @@ impl ChatWidget {
let sandbox_clone = sandbox.clone();
tx.send(AppEvent::CodexOp(
AppCommand::override_turn_context(
None,
/*cwd*/ None,
Some(approval),
Some(approvals_reviewer),
Some(sandbox_clone.clone()),
None,
None,
None,
None,
None,
None,
None,
/*windows_sandbox_level*/ None,
/*model*/ None,
/*effort*/ None,
/*summary*/ None,
/*service_tier*/ None,
/*collaboration_mode*/ None,
/*personality*/ None,
)
.into_core(),
));
@@ -7037,7 +7083,10 @@ impl ChatWidget {
tx.send(AppEvent::UpdateSandboxPolicy(sandbox_clone));
tx.send(AppEvent::UpdateApprovalsReviewer(approvals_reviewer));
tx.send(AppEvent::InsertHistoryCell(Box::new(
history_cell::new_info_event(format!("Permissions updated to {label}"), None),
history_cell::new_info_event(
format!("Permissions updated to {label}"),
/*hint*/ None,
),
)));
})]
}
@@ -7681,9 +7730,11 @@ impl ChatWidget {
/// Set the reasoning effort in the stored collaboration mode.
pub(crate) fn set_reasoning_effort(&mut self, effort: Option<ReasoningEffortConfig>) {
self.current_collaboration_mode =
self.current_collaboration_mode
.with_updates(None, Some(effort), None);
self.current_collaboration_mode = self.current_collaboration_mode.with_updates(
/*model*/ None,
Some(effort),
/*developer_instructions*/ None,
);
if self.collaboration_modes_enabled()
&& let Some(mask) = self.active_collaboration_mask.as_mut()
&& mask.mode != Some(ModeKind::Plan)
@@ -7770,9 +7821,11 @@ impl ChatWidget {
/// Set the model in the widget's config copy and stored collaboration mode.
pub(crate) fn set_model(&mut self, model: &str) {
self.current_collaboration_mode =
self.current_collaboration_mode
.with_updates(Some(model.to_string()), None, None);
self.current_collaboration_mode = self.current_collaboration_mode.with_updates(
Some(model.to_string()),
/*effort*/ None,
/*developer_instructions*/ None,
);
if self.collaboration_modes_enabled()
&& let Some(mask) = self.active_collaboration_mask.as_mut()
{
@@ -7785,17 +7838,17 @@ impl ChatWidget {
self.set_service_tier(service_tier);
self.app_event_tx.send(AppEvent::CodexOp(
AppCommand::override_turn_context(
None,
None,
None,
None,
None,
None,
None,
None,
/*cwd*/ None,
/*approval_policy*/ None,
/*approvals_reviewer*/ None,
/*sandbox_policy*/ None,
/*windows_sandbox_level*/ None,
/*model*/ None,
/*effort*/ None,
/*summary*/ None,
Some(service_tier),
None,
None,
/*collaboration_mode*/ None,
/*personality*/ None,
)
.into_core(),
));
@@ -8058,7 +8111,7 @@ impl ChatWidget {
message.push_str(" for ");
message.push_str(next_mode.display_name());
message.push_str(" mode.");
self.add_info_message(message, None);
self.add_info_message(message, /*hint*/ None);
}
self.request_redraw();
}
@@ -8096,8 +8149,8 @@ impl ChatWidget {
Box::new(history_cell::SessionHeaderHistoryCell::new_with_style(
DEFAULT_MODEL_DISPLAY_NAME.to_string(),
placeholder_style,
None,
false,
/*reasoning_effort*/ None,
/*show_fast_status*/ false,
config.cwd.clone(),
CODEX_CLI_VERSION,
))
@@ -8169,7 +8222,10 @@ impl ChatWidget {
let mcp_manager = McpManager::new(Arc::new(PluginsManager::new(
self.config.codex_home.clone(),
)));
if mcp_manager.effective_servers(&self.config, None).is_empty() {
if mcp_manager
.effective_servers(&self.config, /*auth*/ None)
.is_empty()
{
self.add_to_history(history_cell::empty_mcp_output());
} else {
self.add_app_server_stub_message("MCP tool inventory");
@@ -8193,7 +8249,7 @@ impl ChatWidget {
match connectors_cache {
ConnectorsCacheState::Ready(snapshot) => {
if snapshot.connectors.is_empty() {
self.add_info_message("No apps available.".to_string(), None);
self.add_info_message("No apps available.".to_string(), /*hint*/ None);
} else {
self.open_connectors_popup(&snapshot.connectors);
}
@@ -8219,8 +8275,9 @@ impl ChatWidget {
}
fn open_connectors_popup(&mut self, connectors: &[connectors::AppInfo]) {
self.bottom_pane
.show_selection_view(self.connectors_popup_params(connectors, None));
self.bottom_pane.show_selection_view(
self.connectors_popup_params(connectors, /*selected_connector_id*/ None),
);
}
fn connectors_loading_popup_params(&self) -> SelectionViewParams {
@@ -8315,7 +8372,10 @@ impl ChatWidget {
let missing_label_for_action = missing_label.clone();
item.actions = vec![Box::new(move |tx| {
tx.send(AppEvent::InsertHistoryCell(Box::new(
history_cell::new_info_event(missing_label_for_action.clone(), None),
history_cell::new_info_event(
missing_label_for_action.clone(),
/*hint*/ None,
),
)));
})];
item.dismiss_on_select = true;
@@ -8612,7 +8672,7 @@ impl ChatWidget {
{
let op: AppCommand = op.into();
if op.is_review() && !self.bottom_pane.is_task_running() {
self.bottom_pane.set_task_running(true);
self.bottom_pane.set_task_running(/*running*/ true);
}
match &self.codex_op_target {
CodexOpTarget::Direct(codex_op_tx) => {
@@ -8664,7 +8724,7 @@ impl ChatWidget {
snapshot.connectors = connectors::merge_connectors_with_accessible(
Vec::new(),
snapshot.connectors,
false,
/*all_connectors_loaded*/ false,
);
}
snapshot.connectors =
@@ -8705,13 +8765,13 @@ impl ChatWidget {
self.bottom_pane.set_connectors_snapshot(Some(snapshot));
} else {
self.connectors_cache = ConnectorsCacheState::Failed(err);
self.bottom_pane.set_connectors_snapshot(None);
self.bottom_pane.set_connectors_snapshot(/*snapshot*/ None);
}
}
}
if trigger_pending_force_refetch {
self.prefetch_connectors_with_options(true);
self.prefetch_connectors_with_options(/*force_refetch*/ true);
}
}
@@ -8740,7 +8800,7 @@ impl ChatWidget {
fn refresh_plugin_mentions(&mut self) {
if !self.config.features.enabled(Feature::Plugins) {
self.bottom_pane.set_plugin_mentions(None);
self.bottom_pane.set_plugin_mentions(/*plugins*/ None);
return;
}
@@ -8845,7 +8905,7 @@ impl ChatWidget {
}
pub(crate) async fn show_review_commit_picker(&mut self, cwd: &Path) {
let commits = codex_core::git_info::recent_commits(cwd, 100).await;
let commits = codex_core::git_info::recent_commits(cwd, /*limit*/ 100).await;
let mut items: Vec<SelectionItem> = Vec::with_capacity(commits.len());
for entry in commits {
@@ -8885,7 +8945,7 @@ impl ChatWidget {
let view = CustomPromptView::new(
"Custom review instructions".to_string(),
"Type instructions and press Enter".to_string(),
None,
/*context_label*/ None,
Box::new(move |prompt: String| {
let trimmed = prompt.trim().to_string();
if trimmed.is_empty() {
@@ -8974,14 +9034,18 @@ impl ChatWidget {
fn as_renderable(&self) -> RenderableItem<'_> {
let active_cell_renderable = match &self.active_cell {
Some(cell) => RenderableItem::Borrowed(cell).inset(Insets::tlbr(1, 0, 0, 0)),
Some(cell) => RenderableItem::Borrowed(cell).inset(Insets::tlbr(
/*top*/ 1, /*left*/ 0, /*bottom*/ 0, /*right*/ 0,
)),
None => RenderableItem::Owned(Box::new(())),
};
let mut flex = FlexRenderable::new();
flex.push(1, active_cell_renderable);
flex.push(/*flex*/ 1, active_cell_renderable);
flex.push(
0,
RenderableItem::Borrowed(&self.bottom_pane).inset(Insets::tlbr(1, 0, 0, 0)),
/*flex*/ 0,
RenderableItem::Borrowed(&self.bottom_pane).inset(Insets::tlbr(
/*top*/ 1, /*left*/ 0, /*bottom*/ 0, /*right*/ 0,
)),
);
RenderableItem::Owned(Box::new(flex))
}
@@ -9073,7 +9137,10 @@ impl Notification {
.unwrap_or_else(|| "Agent turn complete".to_string())
}
Notification::ExecApprovalRequested { command } => {
format!("Approval requested: {}", truncate_text(command, 30))
format!(
"Approval requested: {}",
truncate_text(command, /*max_graphemes*/ 30)
)
}
Notification::EditApprovalRequested { cwd, changes } => {
format!(
@@ -9160,7 +9227,7 @@ impl Notification {
if summary.is_empty() {
None
} else {
Some(truncate_text(summary, 30))
Some(truncate_text(summary, /*max_graphemes*/ 30))
}
}
}
@@ -185,7 +185,7 @@ impl ChatWidget {
self.realtime_conversation.warned_audio_only_submission = true;
self.add_info_message(
"Realtime voice mode is audio-only. Use /realtime to stop.".to_string(),
None,
/*hint*/ None,
);
} else {
self.request_redraw();
@@ -216,7 +216,7 @@ impl ChatWidget {
pub(super) fn request_realtime_conversation_close(&mut self, info_message: Option<String>) {
if !self.realtime_conversation.is_live() {
if let Some(message) = info_message {
self.add_info_message(message, None);
self.add_info_message(message, /*hint*/ None);
}
return;
}
@@ -225,10 +225,10 @@ impl ChatWidget {
self.realtime_conversation.phase = RealtimeConversationPhase::Stopping;
self.submit_op(AppCommand::realtime_conversation_close());
self.stop_realtime_local_audio();
self.set_footer_hint_override(None);
self.set_footer_hint_override(/*items*/ None);
if let Some(message) = info_message {
self.add_info_message(message, None);
self.add_info_message(message, /*hint*/ None);
} else {
self.request_redraw();
}
@@ -236,7 +236,7 @@ impl ChatWidget {
pub(super) fn reset_realtime_conversation_state(&mut self) {
self.stop_realtime_local_audio();
self.set_footer_hint_override(None);
self.set_footer_hint_override(/*items*/ None);
self.realtime_conversation.phase = RealtimeConversationPhase::Inactive;
self.realtime_conversation.requested_close = false;
self.realtime_conversation.session_id = None;
@@ -286,7 +286,10 @@ impl ChatWidget {
let reason = ev.reason;
self.reset_realtime_conversation_state();
if !requested && let Some(reason) = reason {
self.add_info_message(format!("Realtime voice mode closed: {reason}"), None);
self.add_info_message(
format!("Realtime voice mode closed: {reason}"),
/*hint*/ None,
);
}
self.request_redraw();
}
@@ -61,7 +61,7 @@ impl ChatWidget {
pub(crate) fn open_manage_skills_popup(&mut self) {
if self.skills_all.is_empty() {
self.add_info_message("No skills available.".to_string(), None);
self.add_info_message("No skills available.".to_string(), /*hint*/ None);
return;
}
@@ -133,7 +133,7 @@ impl ChatWidget {
}
self.add_info_message(
format!("{enabled_count} skills enabled, {disabled_count} skills disabled"),
None,
/*hint*/ None,
);
}
+11 -6
View File
@@ -212,20 +212,23 @@ impl WidgetRef for &CwdPromptScreen {
"Session = latest cwd recorded in the {action_past} session"
))
.dim()
.inset(Insets::tlbr(0, 2, 0, 0)),
.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
);
column.push(
Line::from("Current = your current working directory".dim())
.inset(Insets::tlbr(0, 2, 0, 0)),
Line::from("Current = your current working directory".dim()).inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
);
column.push("");
column.push(selection_option_row(
0,
/*index*/ 0,
format!("Use session directory ({session_cwd})"),
self.highlighted == CwdSelection::Session,
));
column.push(selection_option_row(
1,
/*index*/ 1,
format!("Use current directory ({current_cwd})"),
self.highlighted == CwdSelection::Current,
));
@@ -236,7 +239,9 @@ impl WidgetRef for &CwdPromptScreen {
key_hint::plain(KeyCode::Enter).into(),
" to continue".dim(),
])
.inset(Insets::tlbr(0, 2, 0, 0)),
.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
);
column.render(area, buf);
}
+5 -2
View File
@@ -60,7 +60,10 @@ fn render_debug_config_lines(stack: &ConfigLayerStack) -> Vec<Line<'static>> {
.bold()
.into(),
);
let layers = stack.get_layers(ConfigLayerStackOrdering::LowestPrecedenceFirst, true);
let layers = stack.get_layers(
ConfigLayerStackOrdering::LowestPrecedenceFirst,
/*include_disabled*/ true,
);
if layers.is_empty() {
lines.push(" <none>".dim().into());
} else {
@@ -186,7 +189,7 @@ fn render_non_file_layer_details(layer: &ConfigLayerEntry) -> Vec<Line<'static>>
fn render_session_flag_details(config: &TomlValue) -> Vec<Line<'static>> {
let mut pairs = Vec::new();
flatten_toml_key_values(config, None, &mut pairs);
flatten_toml_key_values(config, /*prefix*/ None, &mut pairs);
if pairs.is_empty() {
return vec![" - <none>".dim().into()];
+11 -9
View File
@@ -306,13 +306,13 @@ impl DiffSummary {
impl Renderable for FileChange {
fn render(&self, area: Rect, buf: &mut Buffer) {
let mut lines = vec![];
render_change(self, &mut lines, area.width as usize, None);
render_change(self, &mut lines, area.width as usize, /*lang*/ None);
Paragraph::new(lines).render(area, buf);
}
fn desired_height(&self, width: u16) -> u16 {
let mut lines = vec![];
render_change(self, &mut lines, width as usize, None);
render_change(self, &mut lines, width as usize, /*lang*/ None);
lines.len() as u16
}
}
@@ -332,7 +332,9 @@ impl From<DiffSummary> for Box<dyn Renderable> {
rows.push(Box::new(RtLine::from("")));
rows.push(Box::new(InsetRenderable::new(
Box::new(row.change) as Box<dyn Renderable>,
Insets::tlbr(0, 2, 0, 0),
Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
),
)));
}
@@ -502,7 +504,7 @@ fn render_change(
raw,
width,
line_number_width,
None,
/*syntax_spans*/ None,
style_context.theme,
style_context.color_level,
style_context.diff_backgrounds,
@@ -534,7 +536,7 @@ fn render_change(
raw,
width,
line_number_width,
None,
/*syntax_spans*/ None,
style_context.theme,
style_context.color_level,
style_context.diff_backgrounds,
@@ -649,7 +651,7 @@ fn render_change(
s,
width,
line_number_width,
None,
/*syntax_spans*/ None,
style_context.theme,
style_context.color_level,
style_context.diff_backgrounds,
@@ -682,7 +684,7 @@ fn render_change(
s,
width,
line_number_width,
None,
/*syntax_spans*/ None,
style_context.theme,
style_context.color_level,
style_context.diff_backgrounds,
@@ -715,7 +717,7 @@ fn render_change(
s,
width,
line_number_width,
None,
/*syntax_spans*/ None,
style_context.theme,
style_context.color_level,
style_context.diff_backgrounds,
@@ -796,7 +798,7 @@ pub(crate) fn push_wrapped_diff_line_with_style_context(
text,
width,
line_number_width,
None,
/*syntax_spans*/ None,
style_context.theme,
style_context.color_level,
style_context.diff_backgrounds,
@@ -681,9 +681,9 @@ impl ExecDisplayLayout {
const EXEC_DISPLAY_LAYOUT: ExecDisplayLayout = ExecDisplayLayout::new(
PrefixedBlock::new("", ""),
2,
/*command_continuation_max_lines*/ 2,
PrefixedBlock::new("", " "),
5,
/*output_max_lines*/ 5,
);
#[cfg(test)]
+1 -1
View File
@@ -87,7 +87,7 @@ impl FileSearchManager {
..Default::default()
},
reporter,
None,
/*cancel_flag*/ None,
);
match session {
Ok(session) => st.session = Some(session),
+12 -7
View File
@@ -782,7 +782,7 @@ fn truncate_exec_snippet(full_cmd: &str) -> String {
Some((first, _)) => format!("{first} ..."),
None => full_cmd.to_string(),
};
snippet = truncate_text(&snippet, 80);
snippet = truncate_text(&snippet, /*max_graphemes*/ 80);
snippet
}
@@ -1003,7 +1003,7 @@ pub(crate) fn card_inner_width(width: u16, max_inner_width: usize) -> Option<usi
/// Render `lines` inside a border sized to the widest span in the content.
pub(crate) fn with_border(lines: Vec<Line<'static>>) -> Vec<Line<'static>> {
with_border_internal(lines, None)
with_border_internal(lines, /*forced_inner_width*/ None)
}
/// Render `lines` inside a border whose inner width is at least `inner_width`.
@@ -1660,7 +1660,7 @@ pub(crate) fn new_active_web_search_call(
query: String,
animations_enabled: bool,
) -> WebSearchCell {
WebSearchCell::new(call_id, query, None, animations_enabled)
WebSearchCell::new(call_id, query, /*action*/ None, animations_enabled)
}
pub(crate) fn new_web_search_call(
@@ -1668,7 +1668,12 @@ pub(crate) fn new_web_search_call(
query: String,
action: WebSearchAction,
) -> WebSearchCell {
let mut cell = WebSearchCell::new(call_id, query, Some(action), false);
let mut cell = WebSearchCell::new(
call_id,
query,
Some(action),
/*animations_enabled*/ false,
);
cell.complete();
cell
}
@@ -1812,7 +1817,7 @@ pub(crate) fn new_mcp_tools_output(
}
let mcp_manager = McpManager::new(Arc::new(PluginsManager::new(config.codex_home.clone())));
let effective_servers = mcp_manager.effective_servers(config, None);
let effective_servers = mcp_manager.effective_servers(config, /*auth*/ None);
let mut servers: Vec<_> = effective_servers.iter().collect();
servers.sort_by(|(a, _), (b, _)| a.cmp(b));
@@ -2345,7 +2350,7 @@ pub(crate) fn new_reasoning_summary_block(
header_buffer,
summary_buffer,
&cwd,
false,
/*transcript_only*/ false,
));
}
}
@@ -2354,7 +2359,7 @@ pub(crate) fn new_reasoning_summary_block(
"".to_string(),
full_reasoning_buffer.to_string(),
&cwd,
true,
/*transcript_only*/ true,
))
}
+24 -7
View File
@@ -504,7 +504,10 @@ async fn lookup_session_target_with_app_server(
return Ok(None);
}
};
return match app_server.thread_read(thread_id, false).await {
return match app_server
.thread_read(thread_id, /*include_turns*/ false)
.await
{
Ok(thread) => Ok(session_target_from_app_server_thread(thread)),
Err(err) => {
warn!(
@@ -668,7 +671,7 @@ pub async fn run_main(
.unwrap_or_else(|| "https://chatgpt.com/backend-api/".to_string());
let cloud_requirements = cloud_requirements_loader_for_storage(
codex_home.to_path_buf(),
false,
/*enable_codex_api_key_env*/ false,
config_toml.cli_auth_credentials_store.unwrap_or_default(),
chatgpt_base_url,
);
@@ -825,7 +828,12 @@ pub async fn run_main(
}
let otel = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
codex_core::otel_init::build_provider(&config, env!("CARGO_PKG_VERSION"), None, true)
codex_core::otel_init::build_provider(
&config,
env!("CARGO_PKG_VERSION"),
/*service_name_override*/ None,
/*default_analytics_enabled*/ true,
)
})) {
Ok(Ok(otel)) => otel,
Ok(Err(e)) => {
@@ -1004,7 +1012,7 @@ async fn run_ratatui_app(
if show_login_screen && !remote_mode {
cloud_requirements = cloud_requirements_loader_for_storage(
initial_config.codex_home.clone(),
false,
/*enable_codex_api_key_env*/ false,
initial_config.cli_auth_credentials_store_mode,
initial_config.chatgpt_base_url.clone(),
);
@@ -1086,7 +1094,11 @@ async fn run_ratatui_app(
let Some(app_server) = session_lookup_app_server.as_mut() else {
unreachable!("session lookup app server should be initialized for --fork --last");
};
match lookup_latest_session_target_with_app_server(app_server, &config, None).await? {
match lookup_latest_session_target_with_app_server(
app_server, &config, /*cwd_filter*/ None,
)
.await?
{
Some(target_session) => resume_picker::SessionSelection::Fork(target_session),
None => resume_picker::SessionSelection::StartFresh,
}
@@ -1475,8 +1487,13 @@ async fn load_config_or_exit(
overrides: ConfigOverrides,
cloud_requirements: CloudRequirementsLoader,
) -> Config {
load_config_or_exit_with_fallback_cwd(cli_kv_overrides, overrides, cloud_requirements, None)
.await
load_config_or_exit_with_fallback_cwd(
cli_kv_overrides,
overrides,
cloud_requirements,
/*fallback_cwd*/ None,
)
.await
}
async fn load_config_or_exit_with_fallback_cwd(
+2 -2
View File
@@ -66,7 +66,7 @@ impl RowBuilder {
if start < i {
self.current_line.push_str(&fragment[start..i]);
}
self.flush_current_line(true);
self.flush_current_line(/*explicit_break*/ true);
start = i + ch.len_utf8();
}
}
@@ -78,7 +78,7 @@ impl RowBuilder {
/// Mark the end of the current logical line (equivalent to pushing a '\n').
pub fn end_line(&mut self) {
self.flush_current_line(true);
self.flush_current_line(/*explicit_break*/ true);
}
/// Drain and return all produced rows.
+1 -1
View File
@@ -26,7 +26,7 @@ fn main() -> anyhow::Result<()> {
inner,
arg0_paths,
codex_core::config_loader::LoaderOverrides::default(),
None,
/*remote*/ None,
)
.await?;
let token_usage = exit_info.token_usage;
+16 -10
View File
@@ -87,7 +87,7 @@ impl IndentContext {
}
pub fn render_markdown_text(input: &str) -> Text<'static> {
render_markdown_text_with_width(input, None)
render_markdown_text_with_width(input, /*width*/ None)
}
/// Render markdown using the current process working directory for local file-link display.
@@ -227,8 +227,8 @@ where
self.push_line(Line::from("———"));
self.needs_newline = true;
}
Event::Html(html) => self.html(html, false),
Event::InlineHtml(html) => self.html(html, true),
Event::Html(html) => self.html(html, /*inline*/ false),
Event::InlineHtml(html) => self.html(html, /*inline*/ true),
Event::FootnoteReference(_) => {}
Event::TaskListMarker(_) => {}
}
@@ -352,8 +352,11 @@ where
self.push_blank_line();
self.needs_newline = false;
}
self.indent_stack
.push(IndentContext::new(vec![Span::from("> ")], None, false));
self.indent_stack.push(IndentContext::new(
vec![Span::from("> ")],
/*marker*/ None,
/*is_list*/ false,
));
}
fn end_blockquote(&mut self) {
@@ -512,8 +515,11 @@ where
let indent_len = if is_ordered { width + 2 } else { width + 1 };
vec![Span::from(" ".repeat(indent_len))]
};
self.indent_stack
.push(IndentContext::new(indent_prefix, marker, true));
self.indent_stack.push(IndentContext::new(
indent_prefix,
marker,
/*is_list*/ true,
));
self.needs_newline = false;
}
@@ -538,8 +544,8 @@ where
self.indent_stack.push(IndentContext::new(
vec![indent.unwrap_or_default()],
None,
false,
/*marker*/ None,
/*is_list*/ false,
));
self.needs_newline = true;
}
@@ -659,7 +665,7 @@ where
let was_pending = self.pending_marker_line;
self.current_initial_indent = self.prefix_spans(was_pending);
self.current_subsequent_indent = self.prefix_spans(false);
self.current_subsequent_indent = self.prefix_spans(/*pending_marker_line*/ false);
self.current_line_style = style;
self.current_line_content = Some(line);
self.current_line_in_code_block = self.in_code_block;
+15 -4
View File
@@ -307,7 +307,9 @@ impl ModelMigrationScreen {
column.push(
Paragraph::new(line.clone())
.wrap(Wrap { trim: false })
.inset(Insets::tlbr(0, 2, 0, 0)),
.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
);
}
}
@@ -326,7 +328,12 @@ impl ModelMigrationScreen {
column.push(
Paragraph::new(line)
.wrap(Wrap { trim: false })
.inset(Insets::tlbr(0, horizontal_inset, 0, 0)),
.inset(Insets::tlbr(
/*top*/ 0,
horizontal_inset,
/*bottom*/ 0,
/*right*/ 0,
)),
);
}
}
@@ -336,7 +343,9 @@ impl ModelMigrationScreen {
column.push(
Paragraph::new("Choose how you'd like Codex to proceed.")
.wrap(Wrap { trim: false })
.inset(Insets::tlbr(0, 2, 0, 0)),
.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
);
column.push(Line::from(""));
@@ -359,7 +368,9 @@ impl ModelMigrationScreen {
key_hint::plain(KeyCode::Enter).into(),
" to confirm".dim(),
])
.inset(Insets::tlbr(0, 2, 0, 0)),
.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
);
}
}
+9 -5
View File
@@ -224,7 +224,7 @@ pub(crate) fn interaction_end(ev: CollabAgentInteractionEndEvent) -> PlainHistor
nickname: receiver_agent_nickname.as_deref(),
role: receiver_agent_role.as_deref(),
},
None,
/*spawn_request*/ None,
);
let mut details = Vec::new();
@@ -244,7 +244,11 @@ pub(crate) fn waiting_begin(ev: CollabWaitingBeginEvent) -> PlainHistoryCell {
let receiver_agents = merge_wait_receivers(&receiver_thread_ids, receiver_agents);
let title = match receiver_agents.as_slice() {
[receiver] => title_with_agent("Waiting for", agent_label_from_ref(receiver), None),
[receiver] => title_with_agent(
"Waiting for",
agent_label_from_ref(receiver),
/*spawn_request*/ None,
),
[] => title_text("Waiting for agents"),
_ => title_text(format!("Waiting for {} agents", receiver_agents.len())),
};
@@ -290,7 +294,7 @@ pub(crate) fn close_end(ev: CollabCloseEndEvent) -> PlainHistoryCell {
nickname: receiver_agent_nickname.as_deref(),
role: receiver_agent_role.as_deref(),
},
None,
/*spawn_request*/ None,
),
Vec::new(),
)
@@ -313,7 +317,7 @@ pub(crate) fn resume_begin(ev: CollabResumeBeginEvent) -> PlainHistoryCell {
nickname: receiver_agent_nickname.as_deref(),
role: receiver_agent_role.as_deref(),
},
None,
/*spawn_request*/ None,
),
Vec::new(),
)
@@ -337,7 +341,7 @@ pub(crate) fn resume_end(ev: CollabResumeEndEvent) -> PlainHistoryCell {
nickname: receiver_agent_nickname.as_deref(),
role: receiver_agent_role.as_deref(),
},
None,
/*spawn_request*/ None,
),
vec![status_summary_line(&status)],
)
+15 -15
View File
@@ -137,19 +137,19 @@ impl KeyboardHandler for AuthModeWidget {
match key_event.code {
KeyCode::Up | KeyCode::Char('k') => {
self.move_highlight(-1);
self.move_highlight(/*delta*/ -1);
}
KeyCode::Down | KeyCode::Char('j') => {
self.move_highlight(1);
self.move_highlight(/*delta*/ 1);
}
KeyCode::Char('1') => {
self.select_option_by_index(0);
self.select_option_by_index(/*index*/ 0);
}
KeyCode::Char('2') => {
self.select_option_by_index(1);
self.select_option_by_index(/*index*/ 1);
}
KeyCode::Char('3') => {
self.select_option_by_index(2);
self.select_option_by_index(/*index*/ 2);
}
KeyCode::Enter => {
let sign_in_state = { (*self.sign_in_state.read().unwrap()).clone() };
@@ -182,7 +182,7 @@ impl KeyboardHandler for AuthModeWidget {
});
*sign_in_state = SignInState::PickMode;
drop(sign_in_state);
self.set_error(None);
self.set_error(/*message*/ None);
self.request_frame.schedule_frame();
}
SignInState::ChatGptDeviceCode(state) => {
@@ -191,7 +191,7 @@ impl KeyboardHandler for AuthModeWidget {
}
*sign_in_state = SignInState::PickMode;
drop(sign_in_state);
self.set_error(None);
self.set_error(/*message*/ None);
self.request_frame.schedule_frame();
}
_ => {}
@@ -585,7 +585,7 @@ impl AuthModeWidget {
match key_event.code {
KeyCode::Esc => {
*guard = SignInState::PickMode;
self.set_error(None);
self.set_error(/*message*/ None);
should_request_frame = true;
}
KeyCode::Enter => {
@@ -604,7 +604,7 @@ impl AuthModeWidget {
} else {
state.value.pop();
}
self.set_error(None);
self.set_error(/*message*/ None);
should_request_frame = true;
}
KeyCode::Char(c)
@@ -618,7 +618,7 @@ impl AuthModeWidget {
state.prepopulated_from_env = false;
}
state.value.push(c);
self.set_error(None);
self.set_error(/*message*/ None);
should_request_frame = true;
}
_ => {}
@@ -651,7 +651,7 @@ impl AuthModeWidget {
} else {
state.value.push_str(trimmed);
}
self.set_error(None);
self.set_error(/*message*/ None);
} else {
return false;
}
@@ -666,7 +666,7 @@ impl AuthModeWidget {
self.disallow_api_login();
return;
}
self.set_error(None);
self.set_error(/*message*/ None);
let prefill_from_env = read_openai_api_key_from_env();
let mut guard = self.sign_in_state.write().unwrap();
match &mut *guard {
@@ -696,7 +696,7 @@ impl AuthModeWidget {
self.disallow_api_login();
return;
}
self.set_error(None);
self.set_error(/*message*/ None);
let request_handle = self.app_server_request_handle.clone();
let sign_in_state = self.sign_in_state.clone();
let error = self.error.clone();
@@ -758,7 +758,7 @@ impl AuthModeWidget {
return;
}
self.set_error(None);
self.set_error(/*message*/ None);
let request_handle = self.app_server_request_handle.clone();
let sign_in_state = self.sign_in_state.clone();
let error = self.error.clone();
@@ -822,7 +822,7 @@ impl AuthModeWidget {
}
if notification.success {
self.set_error(None);
self.set_error(/*message*/ None);
*self.sign_in_state.write().unwrap() = SignInState::ChatGptSuccessMessage;
} else {
self.set_error(notification.error);
@@ -56,7 +56,7 @@ impl WidgetRef for &TrustDirectoryWidget {
"Do you trust the contents of this directory? Working with untrusted contents comes with higher risk of prompt injection.".to_string(),
)
.wrap(Wrap { trim: true })
.inset(Insets::tlbr(0, 2, 0, 0)),
.inset(Insets::tlbr(/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0)),
);
column.push("");
@@ -80,7 +80,9 @@ impl WidgetRef for &TrustDirectoryWidget {
Paragraph::new(error.to_string())
.red()
.wrap(Wrap { trim: true })
.inset(Insets::tlbr(0, 2, 0, 0)),
.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
);
column.push("");
}
@@ -95,7 +97,9 @@ impl WidgetRef for &TrustDirectoryWidget {
" to continue".dim()
},
])
.inset(Insets::tlbr(0, 2, 0, 0)),
.inset(Insets::tlbr(
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
)),
);
column.render(area, buf);
+17 -6
View File
@@ -457,7 +457,7 @@ impl TranscriptOverlay {
pub(crate) fn new(transcript_cells: Vec<Arc<dyn HistoryCell>>) -> Self {
Self {
view: PagerView::new(
Self::render_cells(&transcript_cells, None),
Self::render_cells(&transcript_cells, /*highlight_cell*/ None),
"T R A N S C R I P T".to_string(),
usize::MAX,
),
@@ -495,7 +495,9 @@ impl TranscriptOverlay {
if !c.is_stream_continuation() && i > 0 {
cell_renderable = Box::new(InsetRenderable::new(
cell_renderable,
Insets::tlbr(1, 0, 0, 0),
Insets::tlbr(
/*top*/ 1, /*left*/ 0, /*bottom*/ 0, /*right*/ 0,
),
));
}
v.push(cell_renderable);
@@ -528,8 +530,12 @@ impl TranscriptOverlay {
{
// The tail was rendered as the only entry, so it lacks a top
// inset; add one now that it follows a committed cell.
Box::new(InsetRenderable::new(tail, Insets::tlbr(1, 0, 0, 0)))
as Box<dyn Renderable>
Box::new(InsetRenderable::new(
tail,
Insets::tlbr(
/*top*/ 1, /*left*/ 0, /*bottom*/ 0, /*right*/ 0,
),
)) as Box<dyn Renderable>
} else {
tail
};
@@ -649,7 +655,12 @@ impl TranscriptOverlay {
let paragraph = Paragraph::new(Text::from(lines)).wrap(Wrap { trim: false });
let mut renderable: Box<dyn Renderable> = Box::new(CachedRenderable::new(paragraph));
if has_prior_cells && !is_stream_continuation {
renderable = Box::new(InsetRenderable::new(renderable, Insets::tlbr(1, 0, 0, 0)));
renderable = Box::new(InsetRenderable::new(
renderable,
Insets::tlbr(
/*top*/ 1, /*left*/ 0, /*bottom*/ 0, /*right*/ 0,
),
));
}
renderable
}
@@ -721,7 +732,7 @@ impl StaticOverlay {
pub(crate) fn with_renderables(renderables: Vec<Box<dyn Renderable>>, title: String) -> Self {
Self {
view: PagerView::new(renderables, title, 0),
view: PagerView::new(renderables, title, /*scroll_offset*/ 0),
is_done: false,
}
}
@@ -37,7 +37,13 @@ impl ComposerInput {
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
let sender = AppEventSender::new(tx.clone());
// `enhanced_keys_supported=true` enables Shift+Enter newline hint/behavior.
let inner = ChatComposer::new(true, sender, true, "Compose new task".to_string(), false);
let inner = ChatComposer::new(
/*has_input_focus*/ true,
sender,
/*enhanced_keys_supported*/ true,
"Compose new task".to_string(),
/*disable_paste_burst*/ false,
);
Self { inner, _tx: tx, rx }
}
@@ -80,7 +86,7 @@ impl ComposerInput {
/// Clear any previously set custom hint items and restore the default hints.
pub fn clear_hint_items(&mut self) {
self.inner.set_footer_hint_override(None);
self.inner.set_footer_hint_override(/*items*/ None);
}
/// Desired height (in rows) for a given width.
+8 -4
View File
@@ -325,7 +325,7 @@ fn spawn_rollout_page_loader(
INTERACTIVE_SESSION_SOURCES,
default_provider.as_ref().map(std::slice::from_ref),
default_provider.as_deref().unwrap_or_default(),
None,
/*search_term*/ None,
)
.await
.map(picker_page_from_rollout_page);
@@ -603,7 +603,11 @@ impl PickerState {
Some(thread_id) => Some(thread_id),
None => match path.as_ref() {
Some(path) => {
crate::resolve_session_thread_id(path.as_path(), None).await
crate::resolve_session_thread_id(
path.as_path(),
/*id_str_if_uuid*/ None,
)
.await
}
None => None,
},
@@ -1518,14 +1522,14 @@ fn calculate_column_metrics(rows: &[Row], include_cwd: bool) -> ColumnMetrics {
let created = format_created_label(row);
let updated = format_updated_label(row);
let branch_raw = row.git_branch.clone().unwrap_or_default();
let branch = right_elide(&branch_raw, 24);
let branch = right_elide(&branch_raw, /*max*/ 24);
let cwd = if include_cwd {
let cwd_raw = row
.cwd
.as_ref()
.map(|p| display_path_for(p, std::path::Path::new("/")))
.unwrap_or_default();
right_elide(&cwd_raw, 24)
right_elide(&cwd_raw, /*max*/ 24)
} else {
String::new()
};
@@ -12,7 +12,7 @@ pub(crate) fn selection_option_row(
label: String,
is_selected: bool,
) -> Box<dyn Renderable> {
selection_option_row_with_dim(index, label, is_selected, false)
selection_option_row_with_dim(index, label, is_selected, /*dim*/ false)
}
pub(crate) fn selection_option_row_with_dim(
@@ -207,7 +207,7 @@ impl StatusIndicatorWidget {
let opts = RtOptions::new(usize::from(width))
.initial_indent(Line::from(DETAILS_PREFIX.dim()))
.subsequent_indent(Line::from(Span::from(" ".repeat(prefix_width)).dim()))
.break_words(true);
.break_words(/*break_words*/ true);
let mut out = word_wrap_lines(details.lines().map(|line| vec![line.dim()]), opts);
@@ -167,13 +167,16 @@ impl PlanStreamController {
}
self.state.clear();
self.emit(out_lines, true)
self.emit(out_lines, /*include_bottom_padding*/ true)
}
/// Step animation: commit at most one queued line and handle end-of-drain cleanup.
pub(crate) fn on_commit_tick(&mut self) -> (Option<Box<dyn HistoryCell>>, bool) {
let step = self.state.step();
(self.emit(step, false), self.state.is_idle())
(
self.emit(step, /*include_bottom_padding*/ false),
self.state.is_idle(),
)
}
/// Step animation: commit at most `max_lines` queued lines.
@@ -185,7 +188,10 @@ impl PlanStreamController {
max_lines: usize,
) -> (Option<Box<dyn HistoryCell>>, bool) {
let step = self.state.drain_n(max_lines.max(1));
(self.emit(step, false), self.state.is_idle())
(
self.emit(step, /*include_bottom_padding*/ false),
self.state.is_idle(),
)
}
/// Returns the current number of queued plan lines waiting to be displayed.
+15 -3
View File
@@ -242,7 +242,13 @@ impl Renderable for ThemePreviewWideRenderable {
}
fn render(&self, area: Rect, buf: &mut Buffer) {
render_preview(area, buf, &WIDE_PREVIEW_ROWS, true, WIDE_PREVIEW_LEFT_INSET);
render_preview(
area,
buf,
&WIDE_PREVIEW_ROWS,
/*center_vertically*/ true,
WIDE_PREVIEW_LEFT_INSET,
);
}
}
@@ -252,7 +258,13 @@ impl Renderable for ThemePreviewNarrowRenderable {
}
fn render(&self, area: Rect, buf: &mut Buffer) {
render_preview(area, buf, &NARROW_PREVIEW_ROWS, false, 0);
render_preview(
area,
buf,
&NARROW_PREVIEW_ROWS,
/*center_vertically*/ false,
/*left_inset*/ 0,
);
}
}
@@ -274,7 +286,7 @@ fn theme_picker_subtitle(codex_home: Option<&Path>, terminal_width: Option<u16>)
let themes_dir = codex_home.map(|home| home.join("themes"));
let themes_dir_display = themes_dir
.as_deref()
.map(|path| format_directory_display(path, None));
.map(|path| format_directory_display(path, /*max_width*/ None));
let available_width = subtitle_available_width(terminal_width);
if let Some(path) = themes_dir_display
+1 -1
View File
@@ -464,7 +464,7 @@ fn is_domain_label(label: &str) -> bool {
pub(crate) fn url_preserving_wrap_options<'a>(opts: RtOptions<'a>) -> RtOptions<'a> {
opts.word_separator(textwrap::WordSeparator::AsciiSpace)
.word_splitter(textwrap::WordSplitter::Custom(split_non_url_word))
.break_words(false)
.break_words(/*break_words*/ false)
}
/// Custom `textwrap::WordSplitter` callback. Returns empty (no split