Add support for the paste events protocol

Fixes #9183
This commit is contained in:
Kovid Goyal 2025-11-04 15:02:19 +05:30
parent efbfcf7923
commit ab6fec104a
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
8 changed files with 38 additions and 9 deletions

View file

@ -134,6 +134,11 @@ consumption to do the same tasks.
Detailed list of changes
-------------------------------------
0.44.1 [future]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Add support for the `paste events protocol <https://rockorager.dev/misc/bracketed-paste-mime/>`__ (:iss:`9183`)
0.44.0 [2025-11-03]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -2400,10 +2400,12 @@ class Boss:
@ac('cp', 'Paste from the clipboard to the active window')
def paste_from_clipboard(self) -> None:
text = get_clipboard_string()
if text:
w = self.window_for_dispatch or self.active_window
if w is not None:
w = self.window_for_dispatch or self.active_window
if w is not None:
if w.send_paste_event():
return
text = get_clipboard_string()
if text:
w.paste_with_actions(text)
def current_primary_selection(self) -> str:
@ -2414,10 +2416,12 @@ class Boss:
@ac('cp', 'Paste from the primary selection, if present, otherwise the clipboard to the active window')
def paste_from_selection(self) -> None:
text = self.current_primary_selection_or_clipboard()
if text:
w = self.window_for_dispatch or self.active_window
if w is not None:
w = self.window_for_dispatch or self.active_window
if w is not None:
if w.send_paste_event(is_primary_selection=True):
return
text = self.current_primary_selection_or_clipboard()
if text:
w.paste_with_actions(text)
def set_primary_selection(self) -> None:

View file

@ -542,6 +542,10 @@ class ClipboardRequestManager:
else:
self.fulfill_read_request(rr, allowed=allowed)
def send_paste_event(self, is_primary_selection: bool) -> None:
rr = ReadRequest(is_primary_selection=is_primary_selection, mime_types=(TARGETS_MIME,), protocol_type=ProtocolType.osc_5522)
self.fulfill_read_request(rr)
def fulfill_read_request(self, rr: ReadRequest, allowed: bool = True) -> None:
if rr.protocol_type is ProtocolType.osc_52:
return self.fulfill_legacy_read_request(rr, allowed)

View file

@ -1218,6 +1218,7 @@ class Screen:
linebuf: LineBuf
in_bracketed_paste_mode: bool
in_band_resize_notification: bool
paste_events: bool
color_preference_notification: bool
cursor_visible: bool
scrolled_by: int

View file

@ -91,5 +91,8 @@
// In-band resize notification mode
#define INBAND_RESIZE_NOTIFICATION (2048 << 5)
// Paste events mode https://rockorager.dev/misc/bracketed-paste-mime/
#define PASTE_EVENTS (5522 << 5)
// Handle Ctrl-C/Ctrl-Z mode
#define HANDLE_TERMIOS_SIGNALS (19997 << 5)

View file

@ -1576,6 +1576,7 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) {
bool private;
switch(mode) {
SIMPLE_MODE(LNM)
SIMPLE_MODE(PASTE_EVENTS)
SIMPLE_MODE(IRM)
SIMPLE_MODE(DECARM)
SIMPLE_MODE(BRACKETED_PASTE)
@ -2182,6 +2183,7 @@ copy_specific_mode(Screen *self, unsigned int mode, const ScreenModes *src, Scre
SIMPLE_MODE(BRACKETED_PASTE)
SIMPLE_MODE(FOCUS_TRACKING)
SIMPLE_MODE(COLOR_PREFERENCE_NOTIFICATION)
SIMPLE_MODE(PASTE_EVENTS)
SIMPLE_MODE(INBAND_RESIZE_NOTIFICATION)
SIMPLE_MODE(DECCKM)
SIMPLE_MODE(DECTCEM)
@ -2225,6 +2227,7 @@ copy_specific_modes(Screen *self, const ScreenModes *src, ScreenModes *dest) {
copy_specific_mode(self, FOCUS_TRACKING, src, dest);
copy_specific_mode(self, COLOR_PREFERENCE_NOTIFICATION, src, dest);
copy_specific_mode(self, INBAND_RESIZE_NOTIFICATION, src, dest);
copy_specific_mode(self, PASTE_EVENTS, src, dest);
copy_specific_mode(self, DECCKM, src, dest);
copy_specific_mode(self, DECTCEM, src, dest);
copy_specific_mode(self, DECAWM, src, dest);
@ -2795,6 +2798,7 @@ report_mode_status(Screen *self, unsigned int which, bool private) {
KNOWN_MODE(FOCUS_TRACKING);
KNOWN_MODE(COLOR_PREFERENCE_NOTIFICATION);
KNOWN_MODE(INBAND_RESIZE_NOTIFICATION);
KNOWN_MODE(PASTE_EVENTS);
#undef KNOWN_MODE
case ALTERNATE_SCREEN:
ans = self->linebuf == self->alt_linebuf ? 1 : 2; break;
@ -4686,6 +4690,7 @@ MODE_GETSET(in_bracketed_paste_mode, BRACKETED_PASTE)
MODE_GETSET(focus_tracking_enabled, FOCUS_TRACKING)
MODE_GETSET(color_preference_notification, COLOR_PREFERENCE_NOTIFICATION)
MODE_GETSET(in_band_resize_notification, INBAND_RESIZE_NOTIFICATION)
MODE_GETSET(paste_events, PASTE_EVENTS)
MODE_GETSET(auto_repeat_enabled, DECARM)
MODE_GETSET(cursor_visible, DECTCEM)
MODE_GETSET(cursor_key_mode, DECCKM)

View file

@ -16,7 +16,8 @@ typedef enum ScrollTypes { SCROLL_LINE = -999999, SCROLL_PAGE, SCROLL_FULL } Scr
typedef struct {
bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mDECARM, mDECCKM, mCOLOR_PREFERENCE_NOTIFICATION,
mBRACKETED_PASTE, mFOCUS_TRACKING, mDECSACE, mHANDLE_TERMIOS_SIGNALS, mINBAND_RESIZE_NOTIFICATION;
mBRACKETED_PASTE, mFOCUS_TRACKING, mDECSACE, mHANDLE_TERMIOS_SIGNALS, mINBAND_RESIZE_NOTIFICATION,
mPASTE_EVENTS;
MouseTrackingMode mouse_tracking_mode;
MouseTrackingProtocol mouse_tracking_protocol;
} ScreenModes;

View file

@ -1834,6 +1834,12 @@ class Window:
path = resolve_custom_file(path) if path else ''
set_window_logo(self.os_window_id, self.tab_id, self.id, path, position or '', alpha, png_data)
def send_paste_event(self, is_primary_selection: bool = False) -> bool:
if not self.screen.paste_events:
return False
self.clipboard_request_manager.send_paste_event(is_primary_selection)
return True
def paste_with_actions(self, text: str) -> None:
if self.destroyed or not text:
return