fix: custom prompt expansion with large pastes (#7154)
### **Summary of Changes** **What?** Fix for slash commands (e.g., /prompts:code-review) not being recognized when large content (>3000 chars) is pasted. [Bug Report](https://github.com/openai/codex/issues/7047) **Why?** With large pastes, slash commands were ignored, so custom prompts weren't expanded and were submitted as literal text. **How?** Refactored the early return block in handle_key_event_without_popup (lines 957-968). Instead of returning early after replacing placeholders, the code now replaces placeholders in the textarea and continues to the normal submission flow. This reuses the existing slash command detection and custom prompt expansion logic (lines 981-1047), avoiding duplication. **Changes:** Modified codex-rs/tui/src/bottom_pane/chat_composer.rs: refactored early return block to continue to normal flow instead of returning immediately Added test: custom_prompt_with_large_paste_expands_correctly to verify the fix **Code Quality:** No lint warnings Code follows existing patterns and reuses existing logic Atomic change focused on the bug fix
This commit is contained in:
parent
3741f387e9
commit
523dabc1ee
1 changed files with 67 additions and 7 deletions
|
|
@ -954,21 +954,17 @@ impl ChatComposer {
|
|||
return (InputResult::None, true);
|
||||
}
|
||||
}
|
||||
// If we have pending placeholder pastes, submit immediately to expand them.
|
||||
// If we have pending placeholder pastes, replace them in the textarea text
|
||||
// and continue to the normal submission flow to handle slash commands.
|
||||
if !self.pending_pastes.is_empty() {
|
||||
let mut text = self.textarea.text().to_string();
|
||||
self.textarea.set_text("");
|
||||
for (placeholder, actual) in &self.pending_pastes {
|
||||
if text.contains(placeholder) {
|
||||
text = text.replace(placeholder, actual);
|
||||
}
|
||||
}
|
||||
self.textarea.set_text(&text);
|
||||
self.pending_pastes.clear();
|
||||
if text.is_empty() {
|
||||
return (InputResult::None, true);
|
||||
}
|
||||
self.history.record_local_submission(&text);
|
||||
return (InputResult::Submitted(text), true);
|
||||
}
|
||||
|
||||
// During a paste-like burst, treat Enter as a newline instead of submit.
|
||||
|
|
@ -3030,6 +3026,70 @@ mod tests {
|
|||
assert!(composer.textarea.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_prompt_with_large_paste_expands_correctly() {
|
||||
use crossterm::event::KeyCode;
|
||||
use crossterm::event::KeyEvent;
|
||||
use crossterm::event::KeyModifiers;
|
||||
|
||||
let (tx, _rx) = unbounded_channel::<AppEvent>();
|
||||
let sender = AppEventSender::new(tx);
|
||||
let mut composer = ChatComposer::new(
|
||||
true,
|
||||
sender,
|
||||
false,
|
||||
"Ask Codex to do anything".to_string(),
|
||||
false,
|
||||
);
|
||||
|
||||
// Create a custom prompt with positional args (no named args like $USER)
|
||||
composer.set_custom_prompts(vec![CustomPrompt {
|
||||
name: "code-review".to_string(),
|
||||
path: "/tmp/code-review.md".to_string().into(),
|
||||
content: "Please review the following code:\n\n$1".to_string(),
|
||||
description: None,
|
||||
argument_hint: None,
|
||||
}]);
|
||||
|
||||
// Type the slash command
|
||||
let command_text = "/prompts:code-review ";
|
||||
composer.textarea.set_text(command_text);
|
||||
composer.textarea.set_cursor(command_text.len());
|
||||
|
||||
// Paste large content (>3000 chars) to trigger placeholder
|
||||
let large_content = "x".repeat(LARGE_PASTE_CHAR_THRESHOLD + 3000);
|
||||
composer.handle_paste(large_content.clone());
|
||||
|
||||
// Verify placeholder was created
|
||||
let placeholder = format!("[Pasted Content {} chars]", large_content.chars().count());
|
||||
assert_eq!(
|
||||
composer.textarea.text(),
|
||||
format!("/prompts:code-review {}", placeholder)
|
||||
);
|
||||
assert_eq!(composer.pending_pastes.len(), 1);
|
||||
assert_eq!(composer.pending_pastes[0].0, placeholder);
|
||||
assert_eq!(composer.pending_pastes[0].1, large_content);
|
||||
|
||||
// Submit by pressing Enter
|
||||
let (result, _needs_redraw) =
|
||||
composer.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
|
||||
|
||||
// Verify the custom prompt was expanded with the large content as positional arg
|
||||
match result {
|
||||
InputResult::Submitted(text) => {
|
||||
// The prompt should be expanded, with the large content replacing $1
|
||||
assert_eq!(
|
||||
text,
|
||||
format!("Please review the following code:\n\n{}", large_content),
|
||||
"Expected prompt expansion with large content as $1"
|
||||
);
|
||||
}
|
||||
_ => panic!("expected Submitted, got: {result:?}"),
|
||||
}
|
||||
assert!(composer.textarea.is_empty());
|
||||
assert!(composer.pending_pastes.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slash_path_input_submits_without_command_error() {
|
||||
use crossterm::event::KeyCode;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue