From d4c4a6e9fb656e3c554cab4486fef25139715d3c Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Tue, 16 Dec 2025 13:25:14 +0000 Subject: [PATCH 1/5] :hammer: Move clipboard copy handling into the app --- src/aging/aging.py | 28 ++++++++++++++++++++++++++++ src/aging/screens/main.py | 26 -------------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/aging/aging.py b/src/aging/aging.py index 22ae5ad..7b54e50 100644 --- a/src/aging/aging.py +++ b/src/aging/aging.py @@ -4,8 +4,14 @@ # Python imports. from argparse import Namespace +############################################################################## +# Pyperclip imports. +from pyperclip import PyperclipException +from pyperclip import copy as copy_to_clipboard + ############################################################################## # Textual imports. +from textual import on from textual.app import InvalidThemeError, ScreenStackError ############################################################################## @@ -19,6 +25,7 @@ load_configuration, update_configuration, ) +from .messages import CopyToClipboard from .screens import Main @@ -81,5 +88,26 @@ def get_default_screen(self) -> Main: """Get the main screen for the application.""" return Main(self._arguments) + @on(CopyToClipboard) + def _copy_text_to_clipbaord(self, message: CopyToClipboard) -> None: + """Copy some text into the clipboard. + + Args: + message: The message requesting the text be copied. + """ + # First off, use Textual's own copy to clipboard facility. Generally + # this will work in most terminals, and if it does it'll likely work + # best, getting the text through remote connections to the user's + # own environment. + self.copy_to_clipboard(message.text) + # However, as a backup, use pyerclip too. If the above did fail due + # to the terminal not supporting the operation, this might work. + try: + copy_to_clipboard(message.text) + except PyperclipException: + pass + # Give the user some feedback. + self.notify(f"Copied {message.description or ''}".strip()) + ### aging.py ends here diff --git a/src/aging/screens/main.py b/src/aging/screens/main.py index 11c9687..34b3a9d 100644 --- a/src/aging/screens/main.py +++ b/src/aging/screens/main.py @@ -10,11 +10,6 @@ # NGDB imports. from ngdb import Long, NGDBError, NortonGuide, PlainText, Short, make_dos_like -############################################################################## -# Pyperclip imports. -from pyperclip import PyperclipException -from pyperclip import copy as copy_to_clipboard - ############################################################################## # Textual imports. from textual import on, work @@ -470,27 +465,6 @@ def action_change_guides_side_command(self) -> None: """Change which side the guides directory is docked to.""" self.guides_on_right = not self.guides_on_right - @on(CopyToClipboard) - def _copy_text_to_clipbaord(self, message: CopyToClipboard) -> None: - """Copy some text into the clipboard. - - Args: - message: The message requesting the text be copied. - """ - # First off, use Textual's own copy to clipboard facility. Generally - # this will work in most terminals, and if it does it'll likely work - # best, getting the text through remote connections to the user's - # own environment. - self.app.copy_to_clipboard(message.text) - # However, as a backup, use pyerclip too. If the above did fail due - # to the terminal not supporting the operation, this might. - try: - copy_to_clipboard(message.text) - except PyperclipException: - pass - # Give the user some feedback. - self.notify(f"Copied {message.description or ''}".strip()) - @property def _entry_text(self) -> str: """The text of the current entry.""" From e377c41dce2905dc5ac9d840a20aa97f3bfcde0f Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Tue, 16 Dec 2025 13:38:43 +0000 Subject: [PATCH 2/5] :sparkles: Add the ability to copy the credits of a guide --- src/aging/screens/about.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/aging/screens/about.py b/src/aging/screens/about.py index 853e3d3..2057005 100644 --- a/src/aging/screens/about.py +++ b/src/aging/screens/about.py @@ -24,6 +24,10 @@ # Textual enhanced imports. from textual_enhanced.tools import add_key +############################################################################## +# Local imports. +from ..messages.clipboard import CopyToClipboard + ############################################################################## class Title(Label): @@ -62,6 +66,10 @@ class About(ModalScreen[None]): border-top: solid $border; width: 100%; height: auto; + + #copy { + margin-left: 1; + } } Title, { @@ -81,7 +89,7 @@ class About(ModalScreen[None]): } """ - BINDINGS = [("escape", "dismiss(None)")] + BINDINGS = [("c", "copy_credits"), ("escape", "dismiss(None)")] def __init__(self, guide: NortonGuide) -> None: """Initialise the object. @@ -93,17 +101,17 @@ def __init__(self, guide: NortonGuide) -> None: """The guide we're viewing.""" super().__init__() + @property + def _credits(self) -> str: + """The credits of the guide as a single string.""" + return "\n".join(make_dos_like(line) for line in self._guide.credits) + def compose(self) -> ComposeResult: """Compose the content of the screen.""" with Vertical() as dialog: dialog.border_title = f"About {self._guide.path.name}" - if any(line.strip() for line in self._guide.credits): - yield ( - data := Data( - "\n".join(make_dos_like(line) for line in self._guide.credits), - id="credits", - ) - ) + if has_credits := any(line.strip() for line in self._guide.credits): + yield (data := Data(self._credits, id="credits")) data.border_title = "Credits" yield Title("Made With:") yield Data(self._guide.made_with) @@ -116,12 +124,20 @@ def compose(self) -> ComposeResult: f"{datetime.fromtimestamp(int(self._guide.path.stat().st_ctime))}" ) with Horizontal(id="buttons"): - yield Button(add_key("Close", "Esc", self)) + yield Button(add_key("Close", "Esc", self), id="close") + if has_credits: + yield Button(add_key("Copy Credits", "c", self), id="copy") - @on(Button.Pressed) + @on(Button.Pressed, "#close") def _close_about(self) -> None: """Close the about dialog.""" self.dismiss(None) + @on(Button.Pressed, "#copy") + def action_copy_credits(self) -> None: + """Copy the credits to the clipboard.""" + if self.query("#copy"): + self.post_message(CopyToClipboard(self._credits, "the guide's credits")) + ### about.py ends here From e155d1bc649238f463bcdd7d671cf5917c178e20 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Tue, 16 Dec 2025 13:39:28 +0000 Subject: [PATCH 3/5] :books: Update the ChangeLog --- ChangeLog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 9ad4256..10e3c11 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,11 @@ # AgiNG ChangeLog +## Unreleased + +**Released: WiP** + +- Added the ability to copy the credits of a guide from the About dalog. + ## v1.1.1 **Released: 2025-12-12** From 37aac78836382f5bf85d2e753c816229f9337a8a Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Tue, 16 Dec 2025 13:40:10 +0000 Subject: [PATCH 4/5] :pencil: Fix a typo --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 10e3c11..2a62661 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -4,7 +4,7 @@ **Released: WiP** -- Added the ability to copy the credits of a guide from the About dalog. +- Added the ability to copy the credits of a guide from the About dialog. ## v1.1.1 From 2d67bf94ae534c5bf54a0129790c9122baf8cbd4 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Tue, 16 Dec 2025 13:43:04 +0000 Subject: [PATCH 5/5] :books: Link the ChangeLog to the PR --- ChangeLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog.md b/ChangeLog.md index 2a62661..6ba3208 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -5,6 +5,7 @@ **Released: WiP** - Added the ability to copy the credits of a guide from the About dialog. + ([#55](https://github.com/davep/aging/pull/55)) ## v1.1.1