fix(shell): prevent Ctrl+W from overwriting system clipboard [WIP]#1686
fix(shell): prevent Ctrl+W from overwriting system clipboard [WIP]#1686wbxl2000 wants to merge 1 commit intoMoonshotAI:mainfrom
Conversation
Replace PyperclipClipboard with the default InMemoryClipboard so that Emacs-style kill commands (Ctrl+W/K/U) only write to the internal kill ring instead of the system clipboard. Ctrl+V text paste now reads the system clipboard directly via pyperclip.paste(), keeping paste functionality intact. Closes MoonshotAI#1567
There was a problem hiding this comment.
Pull request overview
Fixes a macOS UX issue in the interactive prompt where Emacs-style kill commands (e.g. Ctrl+W) were overwriting the system clipboard by removing prompt_toolkit’s bidirectional PyperclipClipboard integration and switching Ctrl+V paste to read the system clipboard directly.
Changes:
- Stop passing
PyperclipClipboardintoPromptSessionso kill/yank operations use prompt_toolkit’s internal kill ring instead of the system clipboard. - Update the
Ctrl+Vkeybinding to paste viapyperclip.paste()(with early-return on failure/empty clipboard).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if clipboard_available: | ||
|
|
||
| @_kb.add("c-v", eager=True) | ||
| def _(event: KeyPressEvent) -> None: | ||
| if self._try_paste_media(event): | ||
| return | ||
| clipboard_data = event.app.clipboard.get_data() | ||
| if clipboard_data is None: # type: ignore[reportUnnecessaryComparison] | ||
| try: | ||
| text = pyperclip.paste() | ||
| except Exception: | ||
| return | ||
| if not text: | ||
| return | ||
| self._insert_pasted_text(event.current_buffer, clipboard_data.text) | ||
| self._insert_pasted_text(event.current_buffer, text) | ||
| event.app.invalidate() |
There was a problem hiding this comment.
The Ctrl+V handler was changed to read from the system clipboard via pyperclip.paste(), but there are no unit tests covering this keybinding behavior (successful paste, empty clipboard, and exception path). Since there are already prompt clipboard-related tests under tests/ui_and_conv/test_prompt_clipboard.py, please add coverage that mocks pyperclip.paste() and asserts the handler inserts text into the buffer and invalidates the app (and that exceptions don’t crash the prompt).
Warning
WIP — 核心思路已验证,还需要补充测试和进一步验证边界情况后再标记为 merge ready。
Summary
Closes #1567
On macOS, pressing
Ctrl+W(unix-word-rubout) in the kimi-cli prompt overwrites the system clipboard with the deleted word. This happens becausePyperclipClipboardis passed toPromptSession, causing all Emacs-style kill commands (Ctrl+W/K/U) to sync deleted text to the system clipboard viapyperclip.copy().Root cause
PyperclipClipboardwas introduced in commit0703579to fixCtrl+Vtext paste — the defaultInMemoryClipboardcannot read the system clipboard, soevent.app.clipboard.get_data()returned empty content. However,PyperclipClipboardis bidirectional: it also writes to the system clipboard on every kill operation.Fix
PyperclipClipboardwith the defaultInMemoryClipboard(passclipboard=NonetoPromptSession)Ctrl+Vtext paste handler to read the system clipboard directly viapyperclip.paste()instead ofevent.app.clipboard.get_data()This approach is consistent with how zsh/bash handle kill operations (internal kill ring only, never touching the system clipboard). For reference, among similar projects using prompt_toolkit (aider, IPython, mycli), none use
PyperclipClipboard. xonsh uses it but explicitly implementsdisable_copy_on_deletion()to prevent this exact issue.Behavior after fix
Ctrl+W/K/UCtrl+Y(yank)Ctrl+V(paste)PyperclipClipboardpyperclip.paste()directly ✅Test plan
Ctrl+Wno longer overwrites system clipboardCtrl+Vstill pastes text from system clipboardCtrl+Vstill pastes imagesCtrl+Yyanks killed text from internal kill ringCmd+V) still works