Merge pull request #334 from danschwarz/osc52

Add cop[y] status feature - copies status text to clipboard
This commit is contained in:
Ivan Habunek 2023-03-07 11:01:50 +01:00 committed by GitHub
commit 9d51546be3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 1 deletions

View File

@ -14,7 +14,7 @@ from .overlays import ExceptionStackTrace, GotoMenu, Help, StatusSource, StatusL
from .overlays import StatusDeleteConfirmation, Account from .overlays import StatusDeleteConfirmation, Account
from .poll import Poll from .poll import Poll
from .timeline import Timeline from .timeline import Timeline
from .utils import parse_content_links, show_media from .utils import parse_content_links, show_media, copy_to_clipboard
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -111,6 +111,7 @@ class TUI(urwid.Frame):
self.overlay = None self.overlay = None
self.exception = None self.exception = None
self.can_translate = False self.can_translate = False
self.screen = urwid.raw_display.Screen()
super().__init__(self.body, header=self.header, footer=self.footer) super().__init__(self.body, header=self.header, footer=self.footer)
@ -210,6 +211,9 @@ class TUI(urwid.Frame):
def _clear(*args): def _clear(*args):
self.clear_screen() self.clear_screen()
def _copy(timeline, status):
self.copy_status(status)
urwid.connect_signal(timeline, "account", _account) urwid.connect_signal(timeline, "account", _account)
urwid.connect_signal(timeline, "bookmark", self.async_toggle_bookmark) urwid.connect_signal(timeline, "bookmark", self.async_toggle_bookmark)
urwid.connect_signal(timeline, "compose", _compose) urwid.connect_signal(timeline, "compose", _compose)
@ -226,6 +230,7 @@ class TUI(urwid.Frame):
urwid.connect_signal(timeline, "zoom", _zoom) urwid.connect_signal(timeline, "zoom", _zoom)
urwid.connect_signal(timeline, "translate", self.async_translate) urwid.connect_signal(timeline, "translate", self.async_translate)
urwid.connect_signal(timeline, "clear-screen", _clear) urwid.connect_signal(timeline, "clear-screen", _clear)
urwid.connect_signal(timeline, "copy-status", _copy)
def build_timeline(self, name, statuses, local): def build_timeline(self, name, statuses, local):
def _close(*args): def _close(*args):
@ -657,6 +662,12 @@ class TUI(urwid.Frame):
return self.run_in_thread(_delete, done_callback=_done) return self.run_in_thread(_delete, done_callback=_done)
def copy_status(self, status):
# TODO: copy a better version of status content
# including URLs
copy_to_clipboard(self.screen, status.original.data["content"])
self.footer.set_message(f"Status {status.original.id} copied")
# --- Overlay handling ----------------------------------------------------- # --- Overlay handling -----------------------------------------------------
default_overlay_options = dict( default_overlay_options = dict(

View File

@ -206,6 +206,7 @@ class Help(urwid.Padding):
yield urwid.Text(h(" [L] - Show the status links")) yield urwid.Text(h(" [L] - Show the status links"))
yield urwid.Text(h(" [U] - Show the status data in JSON as received from the server")) yield urwid.Text(h(" [U] - Show the status data in JSON as received from the server"))
yield urwid.Text(h(" [V] - Open status in default browser")) yield urwid.Text(h(" [V] - Open status in default browser"))
yield urwid.Text(h(" [Y] - Copy status to clipboard"))
yield urwid.Text(h(" [Z] - Open status in scrollable popup window")) yield urwid.Text(h(" [Z] - Open status in scrollable popup window"))
yield urwid.Divider() yield urwid.Divider()
yield urwid.Text(("bold", "Links")) yield urwid.Text(("bold", "Links"))

View File

@ -41,6 +41,7 @@ class Timeline(urwid.Columns):
"save", # Save current timeline "save", # Save current timeline
"zoom", # Open status in scrollable popup window "zoom", # Open status in scrollable popup window
"clear-screen", # Clear the screen (used internally) "clear-screen", # Clear the screen (used internally)
"copy-status", # Copy status to clipboard
] ]
def __init__(self, name, statuses, can_translate, followed_tags=[], focus=0, is_thread=False): def __init__(self, name, statuses, can_translate, followed_tags=[], focus=0, is_thread=False):
@ -120,6 +121,7 @@ class Timeline(urwid.Columns):
"So[u]rce", "So[u]rce",
"[Z]oom", "[Z]oom",
"Tra[n]slate" if self.can_translate else "", "Tra[n]slate" if self.can_translate else "",
"Cop[y]",
"[H]elp", "[H]elp",
] ]
options = "\n" + " ".join(o for o in options if o) options = "\n" + " ".join(o for o in options if o)
@ -261,6 +263,10 @@ class Timeline(urwid.Columns):
self._emit("poll", status) self._emit("poll", status)
return return
if key in ("y", "Y"):
self._emit("copy-status", status)
return
return super().keypress(size, key) return super().keypress(size, key)
def append_status(self, status): def append_status(self, status):

View File

@ -1,3 +1,5 @@
import base64
import urwid
from html.parser import HTMLParser from html.parser import HTMLParser
import math import math
import os import os
@ -144,3 +146,20 @@ def parse_content_links(content):
parser = LinkParser() parser = LinkParser()
parser.feed(content) parser.feed(content)
return parser.links[:] return parser.links[:]
def copy_to_clipboard(screen: urwid.raw_display.Screen, text: str):
""" copy text to clipboard using OSC 52
This escape sequence is documented
here https://iterm2.com/documentation-escape-codes.html
It has wide support - XTerm, Windows Terminal,
Kitty, iTerm2, others. Some terminals may require a setting to be
enabled in order to use OSC 52 clipboard functions.
"""
text_bytes = text.encode("utf-8")
b64_bytes = base64.b64encode(text_bytes)
b64_text = b64_bytes.decode("utf-8")
screen.write(f"\033]52;c;{b64_text}\a")
screen.flush()