Merge pull request #229 from PR0M3TH3AN/codex/automate-installation-of-xclip-or-alternative

Improve clipboard handling
This commit is contained in:
thePR0M3TH3AN
2025-07-04 11:56:16 -04:00
committed by GitHub
4 changed files with 46 additions and 4 deletions

View File

@@ -110,6 +110,16 @@ pip install --upgrade pip
pip install -r src/requirements.txt
```
#### Linux Clipboard Support
On Linux, `pyperclip` relies on external utilities like `xclip` or `xsel`.
SeedPass will attempt to install **xclip** automatically if neither tool is
available. If the automatic installation fails, you can install it manually:
```bash
sudo apt-get install xclip
```
## Quick Start
After installing dependencies and activating your virtual environment, launch

View File

@@ -19,9 +19,8 @@ from nostr.client import NostrClient
from password_manager.entry_types import EntryType
from constants import INACTIVITY_TIMEOUT, initialize_app
from utils.password_prompt import PasswordPromptError
from utils import timed_input
from utils import timed_input, copy_to_clipboard
from local_bip85.bip85 import Bip85Error
import pyperclip
colorama_init()
@@ -852,7 +851,7 @@ def main(argv: list[str] | None = None) -> int:
)
print(code)
try:
pyperclip.copy(code)
copy_to_clipboard(code, password_manager.clipboard_clear_delay)
print(colored("Code copied to clipboard", "green"))
except Exception as exc:
logging.warning(f"Clipboard copy failed: {exc}")

View File

@@ -21,6 +21,7 @@ def make_pm(search_results, entry=None, totp_code="123456"):
nostr_client=SimpleNamespace(close_client_pool=lambda: None),
parent_seed="seed",
inactivity_timeout=1,
clipboard_clear_delay=45,
)
return pm
@@ -58,7 +59,9 @@ def test_totp_command(monkeypatch, capsys):
monkeypatch.setattr(main, "configure_logging", lambda: None)
monkeypatch.setattr(main, "initialize_app", lambda: None)
monkeypatch.setattr(main.signal, "signal", lambda *a, **k: None)
monkeypatch.setattr(main.pyperclip, "copy", lambda v: called.setdefault("val", v))
monkeypatch.setattr(
main, "copy_to_clipboard", lambda v, d: called.setdefault("val", v)
)
rc = main.main(["totp", "ex"])
assert rc == 0
out = capsys.readouterr().out

View File

@@ -1,10 +1,40 @@
import threading
import logging
import subprocess
import shutil
import sys
import pyperclip
logger = logging.getLogger(__name__)
def _ensure_clipboard() -> None:
"""Attempt to ensure a clipboard mechanism is available."""
try:
pyperclip.copy("")
except pyperclip.PyperclipException as exc:
if sys.platform.startswith("linux"):
if shutil.which("xclip") is None and shutil.which("xsel") is None:
apt = shutil.which("apt-get") or shutil.which("apt")
if apt:
try:
subprocess.run(
["sudo", apt, "install", "-y", "xclip"], check=True
)
pyperclip.copy("")
return
except Exception as install_exc: # pragma: no cover - system dep
logger.warning(
"Automatic xclip installation failed: %s", install_exc
)
raise exc
def copy_to_clipboard(text: str, timeout: int) -> None:
"""Copy text to the clipboard and clear after timeout seconds if unchanged."""
_ensure_clipboard()
pyperclip.copy(text)
def clear_clipboard() -> None: