diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index fd43c036dc..8be6926502 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -1208,7 +1208,7 @@ impl App { { if self.overlay.is_none() && self.chat_widget.no_modal_or_popup_active() - && self.chat_widget.is_external_writer_view() + && self.chat_widget.is_read_only_view() && (crate::key_hint::plain(KeyCode::Esc).is_press(*key) || (crate::key_hint::plain(KeyCode::Left).is_press(*key) && self.chat_widget.agents_navigation_key_available())) diff --git a/codex-rs/tui/src/app/agents_overview.rs b/codex-rs/tui/src/app/agents_overview.rs index 8ca06f0463..974f1a2ad9 100644 --- a/codex-rs/tui/src/app/agents_overview.rs +++ b/codex-rs/tui/src/app/agents_overview.rs @@ -562,8 +562,7 @@ impl App { } let is_new_session = started.is_some(); if self.current_displayed_thread_id() == Some(root_thread_id) - && (!self.thread_unavailable(root_thread_id) - || self.chat_widget.is_external_writer_view()) + && (!self.thread_unavailable(root_thread_id) || self.chat_widget.is_read_only_view()) { // Keep the displayed read-only snapshot frozen; R explicitly retries attachment. if let Ok(mut state) = self.agents_overview.view_state.lock() { @@ -1003,8 +1002,7 @@ impl App { } if self.current_displayed_thread_id() != Some(root_thread_id) - || (self.thread_unavailable(root_thread_id) - && !self.chat_widget.is_external_writer_view()) + || (self.thread_unavailable(root_thread_id) && !self.chat_widget.is_read_only_view()) { self.select_agent_thread(tui, app_server, root_thread_id) .await?; @@ -1012,7 +1010,7 @@ impl App { if self.current_displayed_thread_id() == Some(root_thread_id) { self.remember_attached_host_project(app_server); } - let read_only = self.chat_widget.is_external_writer_view(); + let read_only = self.chat_widget.is_read_only_view(); if !read_only { self.replay_agents_overview_requests(app_server, root_thread_id) .await; @@ -1049,7 +1047,7 @@ impl App { mut input: ThreadInputState, pending_settings: Option, ) { - let preserve_in_flight_turn = !self.chat_widget.is_external_writer_view() + let preserve_in_flight_turn = !self.chat_widget.is_read_only_view() && self.active_turn_id_for_thread(thread_id).await.is_some(); self.reconcile_saved_session_input(thread_id, &mut input) .await; diff --git a/codex-rs/tui/src/app/input.rs b/codex-rs/tui/src/app/input.rs index 6968ef6e2c..3456d1f119 100644 --- a/codex-rs/tui/src/app/input.rs +++ b/codex-rs/tui/src/app/input.rs @@ -476,7 +476,7 @@ impl App { _ => {} } } - if self.chat_widget.is_external_writer_view() + if self.chat_widget.is_read_only_view() && self.overlay.is_none() && self.chat_widget.no_modal_or_popup_active() && key_event.kind == KeyEventKind::Press @@ -680,7 +680,7 @@ impl App { return; } - if self.chat_widget.is_external_writer_view() + if self.chat_widget.is_read_only_view() && self.overlay.is_none() && self.chat_widget.no_modal_or_popup_active() { @@ -852,7 +852,7 @@ impl App { } pub(crate) fn should_handle_backtrack_esc(&self, key_event: KeyEvent) -> bool { - !self.chat_widget.is_external_writer_view() + !self.chat_widget.is_read_only_view() && !self.chat_widget.has_provider_error() && !self.chat_widget.side_conversation_active() && !self.chat_widget.shortcut_overlay_visible() diff --git a/codex-rs/tui/src/app/owned_transcript.rs b/codex-rs/tui/src/app/owned_transcript.rs index ea97361ad0..a4c54fb1d6 100644 --- a/codex-rs/tui/src/app/owned_transcript.rs +++ b/codex-rs/tui/src/app/owned_transcript.rs @@ -562,7 +562,7 @@ impl App { None => (None, None), }; let mut composer_gap = (!self.chat_widget.has_active_view() - && !self.chat_widget.is_external_writer_view()) + && !self.chat_widget.is_read_only_view()) .then(crate::bottom_pane::ComposerGap::default); let prompt_footer = if self.pane_resize.is_some() { Some(crate::bottom_pane::TranscriptFooter { @@ -986,7 +986,7 @@ impl App { // Search and selection still consume Escape first to dismiss their interaction. if let TuiEvent::Key(key) = event && !self.transcript_view.has_active_interaction() - && (self.chat_widget.is_external_writer_view() || self.chat_widget.has_provider_error()) + && (self.chat_widget.is_read_only_view() || self.chat_widget.has_provider_error()) && crate::key_hint::plain(KeyCode::Esc).is_press(*key) { return Ok(false); diff --git a/codex-rs/tui/src/app/reconnect.rs b/codex-rs/tui/src/app/reconnect.rs index fb82daa3fc..e5993062a0 100644 --- a/codex-rs/tui/src/app/reconnect.rs +++ b/codex-rs/tui/src/app/reconnect.rs @@ -552,7 +552,7 @@ impl App { return Err(err); } self.config = self.chat_widget.config_ref().clone(); - if self.thread_unavailable(id) && !self.chat_widget.is_external_writer_view() { + if self.thread_unavailable(id) && !self.chat_widget.is_read_only_view() { self.agent_navigation.mark_stopped(id); self.chat_widget.pause_unavailable_thread(); self.chat_widget.add_info_message("This conversation is unavailable. Its cached transcript and draft remain here; input is paused. Open the agent picker or return to the parent to continue.".into(), /*hint*/ None); diff --git a/codex-rs/tui/src/app/session_lifecycle.rs b/codex-rs/tui/src/app/session_lifecycle.rs index e6590b5227..bf0c5b991f 100644 --- a/codex-rs/tui/src/app/session_lifecycle.rs +++ b/codex-rs/tui/src/app/session_lifecycle.rs @@ -1825,7 +1825,7 @@ impl App { && owned_channel.is_some() && (refreshing_history || was_reconnecting - || self.chat_widget.is_external_writer_view() + || self.chat_widget.is_read_only_view() || self.chat_widget.has_provider_error())) .then(|| self.chat_widget.capture_thread_input_state()) .flatten(); diff --git a/codex-rs/tui/src/app/turn_tips.rs b/codex-rs/tui/src/app/turn_tips.rs index caf751a65e..bdc48c4212 100644 --- a/codex-rs/tui/src/app/turn_tips.rs +++ b/codex-rs/tui/src/app/turn_tips.rs @@ -156,7 +156,7 @@ impl App { if !self.local_settings.tui.show_tooltips || !self.chat_widget.no_modal_or_popup_active() || !self.chat_widget.composer_is_empty() - || self.chat_widget.is_external_writer_view() + || self.chat_widget.is_read_only_view() || self.chat_widget.has_queued_follow_up_messages() || self.backtrack.primed || self.backtrack.overlay_preview_active diff --git a/codex-rs/tui/src/app_backtrack/legacy_input.rs b/codex-rs/tui/src/app_backtrack/legacy_input.rs index 00ad989f76..c70457a9c6 100644 --- a/codex-rs/tui/src/app_backtrack/legacy_input.rs +++ b/codex-rs/tui/src/app_backtrack/legacy_input.rs @@ -96,7 +96,7 @@ impl App { kind: KeyEventKind::Press, .. }) => { - if self.chat_widget.is_external_writer_view() { + if self.chat_widget.is_read_only_view() { self.close_transcript_overlay(tui); } else { self.begin_overlay_backtrack_preview(tui); diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 2e7b7115b6..af37992c19 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -1899,6 +1899,10 @@ impl ChatWidget { self.external_writer_view } + pub(crate) fn is_read_only_view(&self) -> bool { + self.is_external_writer_view() + } + fn refresh_skills_for_current_cwd(&mut self, force_reload: bool) { self.submit_op(AppCommand::list_skills( vec![self.config.cwd.to_path_buf()], diff --git a/codex-rs/tui/src/chatwidget/empty_state_policy.rs b/codex-rs/tui/src/chatwidget/empty_state_policy.rs index 747c9c372b..200044f3f2 100644 --- a/codex-rs/tui/src/chatwidget/empty_state_policy.rs +++ b/codex-rs/tui/src/chatwidget/empty_state_policy.rs @@ -29,7 +29,7 @@ impl ChatWidget { match self.external_editor_state { ExternalEditorState::Requested | ExternalEditorState::Active => None, ExternalEditorState::Closed - if !self.external_writer_view && !self.has_provider_error() => + if !self.is_read_only_view() && !self.has_provider_error() => { self.bottom_pane.empty_state_composer() } diff --git a/codex-rs/tui/src/chatwidget/interaction.rs b/codex-rs/tui/src/chatwidget/interaction.rs index db5d2d8b3c..feda07664d 100644 --- a/codex-rs/tui/src/chatwidget/interaction.rs +++ b/codex-rs/tui/src/chatwidget/interaction.rs @@ -471,7 +471,7 @@ impl ChatWidget { } pub(crate) fn can_launch_external_editor(&self) -> bool { - !self.external_writer_view && self.bottom_pane.can_launch_external_editor() + !self.is_read_only_view() && self.bottom_pane.can_launch_external_editor() } pub(crate) fn can_run_ctrl_l_clear_now(&mut self) -> bool { @@ -596,7 +596,7 @@ impl ChatWidget { pub(crate) fn handle_paste(&mut self, text: String) { self.cancel_quick_dial_menu(); - if (self.external_writer_view || self.has_provider_error()) + if (self.is_read_only_view() || self.has_provider_error()) && !self.bottom_pane.has_active_view() { return; diff --git a/codex-rs/tui/src/chatwidget/reconnect.rs b/codex-rs/tui/src/chatwidget/reconnect.rs index 262d1ad920..a9b612bdd4 100644 --- a/codex-rs/tui/src/chatwidget/reconnect.rs +++ b/codex-rs/tui/src/chatwidget/reconnect.rs @@ -203,7 +203,7 @@ impl ChatWidget { key: KeyEvent, mode: RestrictedInputMode, ) -> KeyEventAction { - if self.external_writer_view { + if self.is_read_only_view() { return KeyEventAction::None; } if mode == RestrictedInputMode::DraftHandoff {