feat(cliphist): removed unused cliphist code
This commit is contained in:
1 file changed
-203
@@ -1,203 +0,0 @@
|
|||||||
import os
|
|
||||||
import subprocess
|
|
||||||
from typing import List
|
|
||||||
from fabric import Fabricator
|
|
||||||
from fabric.widgets.box import Box
|
|
||||||
from fabric.widgets.button import Button
|
|
||||||
from fabric.widgets.entry import Entry
|
|
||||||
from fabric.widgets.label import Label
|
|
||||||
from fabric.widgets.scrolledwindow import ScrolledWindow
|
|
||||||
from gi.repository import GLib
|
|
||||||
import utils.icons as icons
|
|
||||||
|
|
||||||
|
|
||||||
class Cliphist(Box):
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super().__init__(
|
|
||||||
name="cliphist-launcher",
|
|
||||||
all_visible=False,
|
|
||||||
visible=False,
|
|
||||||
**kwargs,
|
|
||||||
)
|
|
||||||
self._arranger_handler = 0
|
|
||||||
self.cliphist_manager = CliphistManager(self)
|
|
||||||
self.viewport = None
|
|
||||||
self.launcher = kwargs["launcher"]
|
|
||||||
|
|
||||||
self.search_entry = Entry(
|
|
||||||
name="search-entry",
|
|
||||||
placeholder="Search Clipboard History...",
|
|
||||||
h_expand=True,
|
|
||||||
on_activate=self._on_search_activate,
|
|
||||||
)
|
|
||||||
self.search_entry.props.xalign = 0.5
|
|
||||||
|
|
||||||
self.header_box = Box(
|
|
||||||
name="header-box",
|
|
||||||
spacing=10,
|
|
||||||
orientation="h",
|
|
||||||
children=[
|
|
||||||
self.search_entry,
|
|
||||||
Button(
|
|
||||||
name="clear-button",
|
|
||||||
child=Label(name="clear-label", markup=icons.clear),
|
|
||||||
tooltip_text="Clear Clipboard History",
|
|
||||||
on_clicked=self.handle_clear_history,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.launcher_box = Box(
|
|
||||||
name="cliphist-launcher-box",
|
|
||||||
spacing=10,
|
|
||||||
orientation="v",
|
|
||||||
h_expand=True,
|
|
||||||
children=[self.header_box],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.add(self.launcher_box)
|
|
||||||
|
|
||||||
def _on_search_activate(self, entry, *args):
|
|
||||||
self.handle_search(entry.get_text())
|
|
||||||
|
|
||||||
def open_cliphist(self):
|
|
||||||
if not self.viewport:
|
|
||||||
self.viewport = Box(name="viewport", spacing=4, orientation="v")
|
|
||||||
self.scrolled_window = ScrolledWindow(
|
|
||||||
name="scrolled-window",
|
|
||||||
spacing=10,
|
|
||||||
min_content_size=(-1, -1),
|
|
||||||
h_scrollbar_policy="never",
|
|
||||||
child=self.viewport,
|
|
||||||
)
|
|
||||||
self.launcher_box.add(self.scrolled_window)
|
|
||||||
|
|
||||||
self.viewport.children = []
|
|
||||||
self.cliphist_manager.update_cliphist_history()
|
|
||||||
|
|
||||||
self.viewport.show()
|
|
||||||
self.search_entry.grab_focus()
|
|
||||||
|
|
||||||
def handle_search(self, text: str):
|
|
||||||
self.cliphist_manager.arrange_viewport(query=text)
|
|
||||||
|
|
||||||
def close_launcher(self):
|
|
||||||
self.launcher.close()
|
|
||||||
|
|
||||||
def handle_clear_history(self, *_):
|
|
||||||
GLib.spawn_command_line_async("cliphist wipe")
|
|
||||||
self.cliphist_manager.update_cliphist_history()
|
|
||||||
|
|
||||||
|
|
||||||
class CliphistManager:
|
|
||||||
def __init__(self, launcher):
|
|
||||||
self.launcher = launcher
|
|
||||||
self.cliphist_history = []
|
|
||||||
self.wl_paste_watcher = Fabricator(
|
|
||||||
poll_from="wl-paste --watch echo", stream=True, interval=-1
|
|
||||||
)
|
|
||||||
self.wl_paste_watcher.connect("changed", self._on_wl_paste_changed)
|
|
||||||
|
|
||||||
def _on_wl_paste_changed(self, *args):
|
|
||||||
self.update_cliphist_history()
|
|
||||||
|
|
||||||
def get_clip_history(self) -> List[dict]:
|
|
||||||
try:
|
|
||||||
result = subprocess.run(
|
|
||||||
["cliphist", "list"], capture_output=True, text=True, check=True
|
|
||||||
)
|
|
||||||
return self._parse_clip_history(result.stdout)
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"Error fetching cliphist history: {e}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
def _parse_clip_history(self, output: str) -> List[dict]:
|
|
||||||
items = []
|
|
||||||
for line in output.splitlines():
|
|
||||||
if line.strip():
|
|
||||||
parts = line.strip().split(maxsplit=1)
|
|
||||||
if len(parts) == 2:
|
|
||||||
items.append({"id": parts[0], "content": parts[1]})
|
|
||||||
return items
|
|
||||||
|
|
||||||
def copy_clip(self, clip_id: str):
|
|
||||||
try:
|
|
||||||
decode_result = subprocess.run(
|
|
||||||
["cliphist", "decode", clip_id], capture_output=True, check=True
|
|
||||||
)
|
|
||||||
subprocess.run(["wl-copy"], input=decode_result.stdout, check=True)
|
|
||||||
self.launcher.close_launcher()
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"Error copying clip {clip_id}: {e}")
|
|
||||||
|
|
||||||
def save_image_file(self, clip_id: str) -> str:
|
|
||||||
output_file = f"/tmp/cliphist-{clip_id}.png"
|
|
||||||
os.makedirs("/tmp", exist_ok=True)
|
|
||||||
try:
|
|
||||||
decode_result = subprocess.run(
|
|
||||||
["cliphist", "decode", clip_id], capture_output=True, check=True
|
|
||||||
)
|
|
||||||
with open(output_file, "wb") as f:
|
|
||||||
f.write(decode_result.stdout)
|
|
||||||
return output_file
|
|
||||||
except (subprocess.CalledProcessError, IOError) as e:
|
|
||||||
print(f"Error saving image file for clip {clip_id}: {e}")
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def update_cliphist_history(self):
|
|
||||||
self.cliphist_history = self.get_clip_history()
|
|
||||||
self.arrange_viewport()
|
|
||||||
|
|
||||||
def query_clips(self, query: str = "") -> List[dict]:
|
|
||||||
if not query.strip():
|
|
||||||
return self.cliphist_history
|
|
||||||
return [
|
|
||||||
clip
|
|
||||||
for clip in self.cliphist_history
|
|
||||||
if query.lower() in clip["content"].lower()
|
|
||||||
]
|
|
||||||
|
|
||||||
def _on_clip_clicked(self, clip_id: str, *args):
|
|
||||||
self.copy_clip(clip_id)
|
|
||||||
|
|
||||||
def bake_clip_slot(self, item: dict) -> Button:
|
|
||||||
if "[[ binary data" in item["content"].lower():
|
|
||||||
return self._create_image_button(item)
|
|
||||||
return self._create_text_button(item)
|
|
||||||
|
|
||||||
def _create_image_button(self, item: dict) -> Button:
|
|
||||||
output_file = self.save_image_file(item["id"])
|
|
||||||
if output_file and os.path.exists(output_file):
|
|
||||||
button = Button(
|
|
||||||
h_align="start",
|
|
||||||
name="clip-item-img",
|
|
||||||
on_clicked=lambda _, clip_id=item["id"]: self.copy_clip(clip_id),
|
|
||||||
)
|
|
||||||
button.set_style(
|
|
||||||
f"background-image: url('{output_file}'); background-size: cover; background-position: center;"
|
|
||||||
)
|
|
||||||
return button
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _create_text_button(self, item: dict) -> Button:
|
|
||||||
return Button(
|
|
||||||
child=Label(
|
|
||||||
label=item["content"][:50]
|
|
||||||
+ ("..." if len(item["content"]) > 50 else ""),
|
|
||||||
h_expand=True,
|
|
||||||
v_align="center",
|
|
||||||
h_align="start",
|
|
||||||
),
|
|
||||||
on_clicked=lambda _, clip_id=item["id"]: self.copy_clip(clip_id),
|
|
||||||
name="slot-button",
|
|
||||||
)
|
|
||||||
|
|
||||||
def arrange_viewport(self, query: str = ""):
|
|
||||||
if not self.launcher.viewport:
|
|
||||||
return
|
|
||||||
self.launcher.viewport.children = []
|
|
||||||
filtered_clips = self.query_clips(query)
|
|
||||||
for clip in filtered_clips:
|
|
||||||
button = self.bake_clip_slot(clip)
|
|
||||||
if button:
|
|
||||||
self.launcher.viewport.add(button)
|
|
||||||
Reference in new issue
Block a user