From a6794a1eaa30ef6c4825e785a804f39d5238fd7a Mon Sep 17 00:00:00 2001 From: pap Date: Thu, 15 Jan 2026 17:56:08 +0000 Subject: [PATCH] tui2 --- .../tui2/src/bottom_pane/chat_composer.rs | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/codex-rs/tui2/src/bottom_pane/chat_composer.rs b/codex-rs/tui2/src/bottom_pane/chat_composer.rs index 7cc2dbabf1..5b5f961011 100644 --- a/codex-rs/tui2/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui2/src/bottom_pane/chat_composer.rs @@ -362,7 +362,11 @@ impl ChatComposer { let placeholder = self.next_large_paste_placeholder(char_count); self.textarea.insert_element(&placeholder); self.pending_pastes.push((placeholder, pasted)); - } else if char_count > 1 && self.handle_paste_image_path(pasted.clone()) { + } else if char_count > 1 + // Keep shell commands like `!open /path/to.png` intact (not replacing with [Image]) so they can be run in shell + && !self.textarea.text().starts_with('!') + && self.handle_paste_image_path(pasted.clone()) + { self.textarea.insert_str(" "); } else { self.textarea.insert_str(&pasted); @@ -4092,6 +4096,35 @@ mod tests { assert_eq!(imgs, vec![tmp_path]); } + #[test] + fn pasting_filepath_with_shell_prefix_keeps_text() { + let tmp = tempdir().expect("create TempDir"); + let tmp_path: PathBuf = tmp.path().join("codex_tui_test_paste_shell.png"); + let img: ImageBuffer, Vec> = + ImageBuffer::from_fn(3, 2, |_x, _y| Rgba([1, 2, 3, 255])); + img.save(&tmp_path).expect("failed to write temp png"); + + let (tx, _rx) = unbounded_channel::(); + let sender = AppEventSender::new(tx); + let mut composer = ChatComposer::new( + true, + sender, + false, + "Ask Codex to do anything".to_string(), + false, + ); + + composer.insert_str("!open "); + let pasted = tmp_path.to_string_lossy().to_string(); + let needs_redraw = composer.handle_paste(pasted.clone()); + assert!(needs_redraw); + assert!(composer.attached_images.is_empty()); + assert_eq!(composer.textarea.text(), format!("!open {pasted}")); + + let imgs = composer.take_recent_submission_images(); + assert!(imgs.is_empty()); + } + #[test] fn selecting_custom_prompt_without_args_submits_content() { let prompt_text = "Hello from saved prompt";