From: Christian Heller <c.heller@plomlompom.de>
Date: Sun, 8 Jun 2025 11:07:06 +0000 (+0200)
Subject: Implement clipboard paste via OSC 52 sequences.
X-Git-Url: https://plomlompom.com/repos/%22https:/validator.w3.org/process?a=commitdiff_plain;h=610d3d3509381895da78dafcd68f5719ad21e68d;p=ircplom
Implement clipboard paste via OSC 52 sequences.
---
diff --git a/ircplom.py b/ircplom.py
index b1605bf..87ecac3 100755
--- a/ircplom.py
+++ b/ircplom.py
@@ -2,6 +2,7 @@
'Attempt at an IRC client.'
from abc import ABC, abstractmethod
+from base64 import b64decode
from contextlib import contextmanager
from inspect import _empty as inspect_empty, signature, stack
from queue import SimpleQueue, Empty as QueueEmpty
@@ -28,11 +29,13 @@ KEYBINDINGS = {
'KEY_PGDOWN': ('window.log.scroll', 'down'),
'[91, 49, 59, 51, 68]': ('window', 'left'),
'[91, 49, 59, 51, 67]': ('window', 'right'),
+ 'KEY_F1': ('window.paste',),
}
CMD_SHORTCUTS = {
'disconnect': 'window.disconnect',
'reconnect': 'window.reconnect'
}
+PREFIX_B64 = 'b64:'
IRCSPEC_LINE_SEPARATOR = b'\r\n'
IRCSPEC_TAG_ESCAPES = ((r'\:', ';'),
@@ -142,6 +145,18 @@ class Terminal:
n_gotchs_unprocessed -= 1
n_gotchs_unprocessed -= n_chs_blessed_key
if unhandleds:
+ if unhandleds[:6] == [93, 53, 50, 59, 99, 59]:
+ if len(unhandleds) > 6:
+ encoded = ''.join([chr(c) for c in unhandleds[:6]])
+ else:
+ encoded = ''
+ while True:
+ gotch = self._blessed.getch()
+ if ord(gotch) == 7:
+ break
+ encoded += gotch
+ yield f'{PREFIX_B64}{encoded}'
+ continue
yield str(unhandleds)
elif blessed_key.name:
yield blessed_key.name
@@ -630,6 +645,11 @@ class Window(Widget):
self._term.write_yx(YX(self._y_status, 0), status_line)
self.prompt.draw()
+ def cmd__paste(self) -> None:
+ 'Write OSC 52 ? sequence to get encoded clipboard paste into stdin.'
+ self._term.write_yx(YX(self._y_status, 0), '\033]52;c;?\007')
+ self.draw()
+
class ConnectionWindow(Window):
'Window with attributes and methods for dealing with an IrcConnection.'
@@ -711,7 +731,7 @@ class TuiLoop(Loop):
cmd = self._cmd_name_to_cmd(event.payload[0])
assert cmd is not None
cmd(*event.payload[1:])
- elif event.type_ == 'INPUT_CHAR':
+ elif event.type_ == 'PROMPT_ADD':
self.window.prompt.append(event.payload)
# elif event.type_ == 'DEBUG':
# from traceback import format_exception
@@ -814,10 +834,13 @@ class KeyboardLoop(Loop):
'Loop receiving and translating keyboard events towards main loop.'
def process_bonus(self, yielded: str) -> None:
- if yielded in KEYBINDINGS:
+ if yielded.startswith(PREFIX_B64):
+ encoded = yielded[len(PREFIX_B64):]
+ self.broadcast('PROMPT_ADD', b64decode(encoded).decode('utf-8'))
+ elif yielded in KEYBINDINGS:
self.broadcast('KEYBINDING', KEYBINDINGS[yielded])
elif len(yielded) == 1:
- self.broadcast('INPUT_CHAR', yielded)
+ self.broadcast('PROMPT_ADD', yielded)
else:
self.broadcast('ALERT', f'unknown keyboard input: {yielded}')