Prompt Expansion: Preserve Text Elements (#9518)

Summary
- Preserve `text_elements` through custom prompt argument parsing and
expansion (named and numeric placeholders).
- Translate text element ranges through Shlex parsing using sentinel
substitution, and rehydrate text + element ranges per arg.
- Drop image attachments when their placeholder does not survive prompt
expansion, keeping attachments consistent with rendered elements.
- Mirror changes in TUI2 and expand tests for prompt parsing/expansion
edge cases.

Tests
- placeholders with spaces as single tokens (positional + key=value,
quoted + unquoted),
  - prompt expansion with image placeholders,
  - large paste + image arg combinations,
  - unused image arg dropped after expansion.
This commit is contained in:
charley-oai
2026-01-20 18:30:20 -08:00
committed by GitHub
parent f4d55319d1
commit 531748a080
6 changed files with 2148 additions and 216 deletions

View File

@@ -47,14 +47,30 @@ impl TextElement {
}
}
/// Returns a copy of this element with a remapped byte range.
///
/// The placeholder is preserved as-is; callers must ensure the new range
/// still refers to the same logical element (and same placeholder)
/// within the new text.
pub fn map_range<F>(&self, map: F) -> Self
where
F: FnOnce(ByteRange) -> ByteRange,
{
Self {
byte_range: map(self.byte_range),
placeholder: self.placeholder.clone(),
}
}
pub fn set_placeholder(&mut self, placeholder: Option<String>) {
self.placeholder = placeholder;
}
/// Returns the stored placeholder without falling back to the text buffer.
///
/// This is intended only for protocol conversions where the full text is not
/// available; prefer `placeholder(text)` for UI logic.
/// This must only be used inside `From<TextElement>` implementations on equivalent
/// protocol types where the source text is unavailable. Prefer `placeholder(text)`
/// everywhere else.
#[doc(hidden)]
pub fn _placeholder_for_conversion_only(&self) -> Option<&str> {
self.placeholder.as_deref()