fix(tui): pasted U+2028 and U+2029 become line breaks
str::lines() splits on neither separator, so a paste carrying them counted as one line and the invisible characters broke the textarea's width model. Bare \r, U+2028 and U+2029 now normalize to \n on every paste route (the prompt, the inline paste key and the previous-message editor); dropped file paths keep their bytes verbatim because a separator in a filename is payload. Ported from upstream 1.0.18 (grok-build prompt_widget normalize_line_breaks). Claude-Session: https://claude.ai/code/session_01RUqV8HVGXcAETyYbZ2tPQ4
This commit is contained in:
1 parent
d8609267a1
commit
901203c2b2
5 files changed
+73
-21
No files matched your search
@@ -734,7 +734,8 @@ impl AgentView {
|
||||
Event::Mouse(mouse) => self.handle_inline_edit_mouse(mouse),
|
||||
Event::Paste(text) => {
|
||||
if let Some(ref mut edit) = self.inline_edit {
|
||||
edit.textarea.insert_str(text);
|
||||
edit.textarea
|
||||
.insert_str(&crate::views::prompt_widget::normalize_line_breaks(text));
|
||||
}
|
||||
InputOutcome::Changed
|
||||
}
|
||||
|
||||
@@ -344,7 +344,10 @@ impl AgentView {
|
||||
self.prompt.textarea.begin_undo_group();
|
||||
group_open = true;
|
||||
}
|
||||
if matches!(self.prompt.handle_paste(&to_insert), PromptEvent::Edited) {
|
||||
if matches!(
|
||||
self.prompt.insert_dropped_path(&to_insert),
|
||||
PromptEvent::Edited
|
||||
) {
|
||||
inserted_non_image = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,6 +290,27 @@ mod tests {
|
||||
agent
|
||||
}
|
||||
|
||||
/// The previous-message editor is its own paste route; separators normalize there too.
|
||||
#[test]
|
||||
fn inline_edit_paste_normalizes_line_separators() {
|
||||
let mut agent = agent_with_prompt();
|
||||
assert!(agent.enter_inline_edit(0));
|
||||
let registry = crate::actions::ActionRegistry::defaults();
|
||||
agent.handle_input(
|
||||
&crossterm::event::Event::Paste("a\u{2028}b\u{2029}c".into()),
|
||||
®istry,
|
||||
);
|
||||
let text = agent
|
||||
.inline_edit
|
||||
.as_ref()
|
||||
.expect("editing state")
|
||||
.textarea
|
||||
.text()
|
||||
.to_owned();
|
||||
assert!(text.contains("a\nb\nc"), "{text:?}");
|
||||
assert!(!text.contains('\u{2028}'), "{text:?}");
|
||||
}
|
||||
|
||||
/// Entering edit mode on a plain user prompt captures the original text,
|
||||
/// resolves the rewind target, and selects the entry.
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user