mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
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:
@@ -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,
|
||||
)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()];
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -87,7 +87,7 @@ impl FileSearchManager {
|
||||
..Default::default()
|
||||
},
|
||||
reporter,
|
||||
None,
|
||||
/*cancel_flag*/ None,
|
||||
);
|
||||
match session {
|
||||
Ok(session) => st.session = Some(session),
|
||||
|
||||
@@ -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,
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)],
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user