Skip to content

feat(prompt): edit image and pasted-text placeholders as blocks#1848

Open
HynoR wants to merge 1 commit intoMoonshotAI:mainfrom
HynoR:feat/paste-atomic
Open

feat(prompt): edit image and pasted-text placeholders as blocks#1848
HynoR wants to merge 1 commit intoMoonshotAI:mainfrom
HynoR:feat/paste-atomic

Conversation

@HynoR
Copy link
Copy Markdown
Contributor

@HynoR HynoR commented Apr 12, 2026

Related Issue

Resolve #1847

Description

把粘贴文本和粘贴图片当做一个placeholder块来处理。

  • Backspace / Delete 在 placeholder 边界时按整体处理
  • 左右方向键按整体选中 placeholder
  • 已选中的 placeholder 可被整块删除

测试

(AI生成的测试)补充了 prompt clipboard 相关测试,覆盖边界选择、整块删除、多 placeholder 以及 shell mode 不启用检查等场景。

修改后的效果

2026-04-12.15.30.36.mov

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Copilot AI review requested due to automatic review settings April 12, 2026 07:52
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +1458 to +1461
Keys.Backspace,
eager=True,
filter=Condition(self._should_handle_placeholder_backspace),
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 PromptPlaceholderManager to 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()
Comment on lines +476 to +482
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))
Comment on lines +509 to +516
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

Comment on lines +529 to +536
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
Comment on lines +537 to +543

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
Comment on lines +548 to +552

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
Comment on lines +562 to +568
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
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

把粘贴的图片和文本的placeholder 当做一个整体块处理 || Treat the pasted image and text placeholder as a whole block

2 participants