feat(prompt): edit image and pasted-text placeholders as blocks#1848
feat(prompt): edit image and pasted-text placeholders as blocks#1848HynoR wants to merge 1 commit intoMoonshotAI:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1eacb7b2a6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Keys.Backspace, | ||
| eager=True, | ||
| filter=Condition(self._should_handle_placeholder_backspace), | ||
| ) |
There was a problem hiding this comment.
Gate placeholder keybindings on focused buffer
The new placeholder handlers are enabled by filters that inspect self._session.default_buffer, but the handler mutates event.current_buffer. In prompt_toolkit flows where another buffer is focused (for example incremental history/search buffers), Backspace/Delete/Left/Right can be captured because the default buffer happens to sit on a placeholder boundary, then the active buffer does not receive its normal key behavior. Please add a focus guard (e.g. has_focus(self._session.default_buffer)) so these bindings only fire when the editable prompt buffer is actually active.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR adds “atomic block” editing behavior for pasted-text and image placeholders in the interactive agent prompt, so users can select/delete placeholders as whole units at cursor boundaries (per #1847).
Changes:
- Add placeholder-span indexing to
PromptPlaceholderManagerto support fast boundary/selection lookups. - Add keybindings/handlers in the prompt to select/collapse/delete placeholders as a block on Backspace/Delete/Left/Right.
- Add tests covering boundary selection, block deletion/collapse, multi-placeholder cases, and shell-mode non-applicability.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
src/kimi_cli/ui/shell/placeholders.py |
Introduces PlaceholderSpan and span-index lookup methods for placeholder boundary/selection detection. |
src/kimi_cli/ui/shell/prompt.py |
Adds keybindings and editing logic to treat placeholders as atomic blocks in agent mode. |
tests/ui_and_conv/test_prompt_clipboard.py |
Adds tests for placeholder atomic editing behavior and non-applicability in shell mode. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if selected_span is not None: | ||
| match selected_action: | ||
| case "delete": | ||
| buffer.cut_selection() |
| for handler, text, cursor, target, expected_text, expected_cursor in cases: | ||
| buffer.exit_selection() | ||
| start = text.index(target) | ||
| end = start + len(target) | ||
| buffer.document = shell_prompt.Document(text=text, cursor_position=cursor) | ||
|
|
||
| handler(_make_key_event(buffer)) |
| for handler, text, expected_cursor in cases: | ||
| buffer.exit_selection() | ||
| start = text.index(token) | ||
| end = start + len(token) | ||
| buffer.document = shell_prompt.Document(text=text, cursor_position=start) | ||
| buffer.start_selection() | ||
| buffer.cursor_position = end | ||
|
|
| buffer = ps._session.default_buffer | ||
| token = "[image:abc123.png,10x10]" | ||
|
|
||
| buffer.document = shell_prompt.Document(text=token, cursor_position=token.index("abc123")) | ||
| assert ps._should_handle_placeholder_backspace() is False | ||
| assert ps._should_handle_placeholder_left() is False | ||
| assert ps._should_handle_placeholder_right() is False | ||
| assert ps._should_handle_placeholder_delete() is False |
|
|
||
| text = f"before {token} after" | ||
| start = text.index(token) | ||
| buffer.document = shell_prompt.Document(text=text, cursor_position=start) | ||
| buffer.start_selection() | ||
| buffer.cursor_position = start + len(token) - 1 | ||
| assert ps._selected_placeholder_span(buffer) is None |
|
|
||
| shell_ps = _make_editing_prompt_session(monkeypatch, mode=PromptMode.SHELL) | ||
| shell_buffer = shell_ps._session.default_buffer | ||
| shell_buffer.document = shell_prompt.Document(text=token, cursor_position=len(token)) | ||
| assert shell_ps._should_handle_placeholder_backspace() is False |
| token_start = text.index(token) | ||
| non_placeholder_start = text.index("prefix") | ||
| non_placeholder_end = token_start | ||
| buffer = ps._session.default_buffer | ||
| buffer.document = shell_prompt.Document(text=text, cursor_position=non_placeholder_start) | ||
| buffer.start_selection() | ||
| buffer.cursor_position = non_placeholder_end |
Related Issue
Resolve #1847
Description
把粘贴文本和粘贴图片当做一个placeholder块来处理。
Backspace/Delete在 placeholder 边界时按整体处理测试
(AI生成的测试)补充了 prompt clipboard 相关测试,覆盖边界选择、整块删除、多 placeholder 以及 shell mode 不启用检查等场景。
修改后的效果
2026-04-12.15.30.36.mov
Checklist
make gen-changelogto update the changelog.make gen-docsto update the user documentation.