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/do_tasks?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}')