added sh runner

This commit is contained in:
sankalp committed 2025-01-11 22:05:02 +05:45
1 parent 0152c689e6
commit 27d7aed6b9
5 files changed
+169 -4

No files matched your search

+1 -1
View File
@@ -41,7 +41,7 @@ ttf-font-awesome, otf-font-awesome, ttf-material-symbols-variable-git, ttf-googl
# ToDo
- [x] Add bluetooth widget
- [ ] Add shrunner widget
- [x] Add shrunner widget
- [ ] Add wifi widget
- [ ] Dashboard
- [ ] Notification panel
+15 -3
View File
@@ -10,6 +10,7 @@ from modules.launcher.widgets import (
Cliphist,
Emoji,
PowerMenu,
Sh,
TodoManager,
WallpaperSelector,
)
@@ -31,12 +32,14 @@ class Launcher(Window):
self.cliphist = Cliphist()
self.todo = TodoManager()
self.bluetooth = BluetoothManager()
self.sh = Sh()
# Initialize viewports as None
self._emoji_viewport = None
self._cliphist_viewport = None
self._todo_viewport = None
self._bluetooth_viewport = None
self._sh_viewport = None
self.stack = Stack(
name="launcher-content",
@@ -52,6 +55,7 @@ class Launcher(Window):
self.cliphist,
self.todo,
self.bluetooth,
self.sh,
],
)
@@ -104,19 +108,17 @@ class Launcher(Window):
self.cliphist,
self.todo,
self.bluetooth,
self.sh,
]:
widget.remove_style_class("open")
# Handle wallpaper viewport
if widget == self.wallpapers:
self.wallpapers.viewport.hide()
self.wallpapers.viewport.set_property("name", None)
# Handle emoji viewport safely
if widget == self.emoji and hasattr(widget, "viewport") and widget.viewport:
widget.viewport.hide()
# Handle cliphist viewport safely
if (
widget == self.cliphist
and hasattr(widget, "viewport")
@@ -132,6 +134,9 @@ class Launcher(Window):
widget.viewport.children = []
widget.is_active = False
if widget == self.sh and widget.viewport:
widget.viewport.hide()
style_classes = [
"launcher",
"wallpapers",
@@ -140,6 +145,7 @@ class Launcher(Window):
"cliphist",
"todo",
"bluetooth",
"sh",
]
for style_class in style_classes:
if self.stack.get_style_context().has_class(style_class):
@@ -159,6 +165,7 @@ class Launcher(Window):
"cliphist": self.cliphist,
"todo": self.todo,
"bluetooth": self.bluetooth,
"sh": self.sh,
}
style_classes = list(widgets.keys())
@@ -213,6 +220,11 @@ class Launcher(Window):
self.bluetooth.search_entry.grab_focus()
self.bluetooth.device_manager.arrange_viewport()
elif widget == "sh":
self.sh.open_launcher()
self.sh.search_entry.set_text("")
self.sh.search_entry.grab_focus()
else:
if hasattr(self.wallpapers, "viewport"):
self.wallpapers.viewport.hide()
@@ -4,5 +4,6 @@ from .cliphist import *
from .dashboard import *
from .emoji import *
from .power import *
from .sh import *
from .todo import *
from .wallpapers import *
@@ -0,0 +1,152 @@
import os
import subprocess
from typing import List
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
from snippets import MaterialIcon
CACHE_DIR = os.getenv(
"XDG_CACHE_HOME", os.path.join(os.path.expanduser("~"), ".cache", "fabric")
)
BINS = os.path.join(CACHE_DIR, "binaries")
class Sh(Box):
def __init__(self, **kwargs):
super().__init__(
name="shell-command-launcher",
all_visible=False,
visible=False,
**kwargs,
)
self._arranger_handler: int = 0
self.shell_command_manager = ShellCommandManager(self)
self.viewport = None
self.search_entry = Entry(
name="search-entry",
placeholder="Search Commands...",
h_expand=True,
notify_text=lambda entry, *_: self.handle_search_input(entry.get_text()),
on_activate=lambda entry, *_: self.handle_search_input(entry.get_text()),
)
self.header_box = Box(
name="header-box",
spacing=10,
orientation="h",
children=[
self.search_entry,
Button(
name="close-button",
child=MaterialIcon("close"),
tooltip_text="Exit",
on_clicked=lambda *_: self.close_launcher(),
),
],
)
self.launcher_box = Box(
name="shell-command-launcher-box",
spacing=10,
orientation="v",
h_expand=True,
children=[self.header_box],
)
self.add(self.launcher_box)
def open_launcher(self):
if not self.viewport:
self.viewport = Box(name="viewport", spacing=10, orientation="v")
self.scrolled_window = ScrolledWindow(
name="scrolled-window",
spacing=10,
h_scrollbar_policy="never",
v_scrollbar_policy="never",
child=self.viewport,
)
self.launcher_box.add(self.scrolled_window)
self.viewport.children = []
self.shell_command_manager.show_shell_commands(self.viewport, "")
self.viewport.show()
self.search_entry.grab_focus()
def close_launcher(self):
GLib.spawn_command_line_async("fabric-cli exec quickbar 'launcher.close()'")
def handle_search_input(self, text: str):
self.shell_command_manager.show_shell_commands(self.viewport, text)
class ShellCommandManager:
def __init__(self, launcher):
self.launcher = launcher
self.binaries = set()
self.reload_binaries()
def reload_binaries(self):
paths = os.getenv("PATH", "").split(":")
self.binaries = set()
for path in paths:
self.binaries.update(self.list_binaries_in_path(path))
with open(BINS, "w") as f:
f.write("\n".join(self.binaries))
def list_binaries_in_path(self, path):
if not os.path.exists(path):
return []
try:
return [
entry
for entry in os.listdir(path)
if os.access(os.path.join(path, entry), os.X_OK)
]
except OSError:
return []
def show_shell_commands(self, viewport, search_query: str):
if not search_query:
return
viewport.children = []
results = self.query_binaries(search_query)
self.display_results(viewport, results)
def query_binaries(self, filter_str: str) -> List[str]:
filter_str = filter_str.lower()
filtered_bins = (cmd for cmd in self.binaries if filter_str in cmd)
return list(dict.fromkeys(filtered_bins))[:16]
def display_results(self, viewport, results: List[str]):
for command in results:
button = Button(
child=Label(
label=command,
v_align="center",
h_align="start",
),
on_clicked=lambda _, cmd=command: self.execute_command(cmd),
name="sh-item",
)
viewport.add(button)
def execute_command(self, cmd: str):
try:
output = subprocess.check_output(cmd, shell=True, text=True)
print(output)
except subprocess.CalledProcessError as e:
print(e.output)
finally:
self.launcher.set_visible(False)
Whitespace-only changes.