dotfiles-rene/bin/toolbox
rene 978065289d toolbox: interaktiver Tool-Launcher mit fzf + iTerm2/Linux-Support
- fzf-basierte Auswahl mit Kategorien und Beschreibungen
- TUI-Tools öffnen in neuem Tab (iTerm2 auf Mac, xfce4-terminal/gnome-terminal auf Linux)
- Output-Tools laufen inline
- Mac-only Tools (temps) werden auf Linux ausgeblendet
- Linux-Binaries (batcat, fdfind) werden automatisch aufgelöst
- tools() → toolbox, tools-ref() behält statische Cheatsheet-Ansicht

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 13:28:11 +01:00

203 lines
9.4 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
toolbox — interaktiver Terminal-Tool-Launcher
Läuft auf macOS (iTerm2) und Linux (Xubuntu/xfce4-terminal, gnome-terminal, …)
"""
import subprocess
import shutil
import sys
import os
import platform
from dataclasses import dataclass, field
IS_MAC = platform.system() == "Darwin"
IS_LINUX = platform.system() == "Linux"
@dataclass
class Tool:
category: str
name: str
description: str
command: str
binary: str # Binary für Verfügbarkeitscheck
new_tab: bool = True # TUI → neuer Tab, Output-Tools → inline
mac: bool = True # auf macOS anzeigen
linux: bool = True # auf Linux anzeigen
TOOLS = [
# --- Git ---
Tool("Git", "lazygit", "Git TUI: stagen, committen, pushen, rebasen", "lazygit", "lazygit"),
Tool("Git", "gitcheck", "Status aller Repos prüfen", "~/git-check-all.sh", "git", new_tab=False),
Tool("Git", "gitsync", "Alle Repos mit Gitea synchronisieren", "~/git-projekte/dotfiles-rene/bin/git-sync-all.sh", "git", new_tab=False),
Tool("Git", "git log", "Commit-History (mit delta, side-by-side)", "git log -p", "git", new_tab=False),
Tool("Git", "git diff", "Änderungen anzeigen (mit delta)", "git diff", "git", new_tab=False),
# --- Navigation & Dateien ---
Tool("Dateien", "yazi", "Terminal-Dateimanager (q = quit)", "yazi", "yazi"),
Tool("Dateien", "fzf", "Fuzzy-Finder (Ctrl+T Dateien, Ctrl+R History)", "fzf", "fzf"),
Tool("Dateien", "ncdu", "Interaktive Festplattennutzung", "ncdu ~", "ncdu"),
Tool("Dateien", "duf", "Übersicht freier Speicherplatz", "duf", "duf", new_tab=False),
Tool("Dateien", "fd", "Schnelles find (Beispiel: fd .py)", "fd", "fd", new_tab=False),
Tool("Dateien", "rg", "Blitzschnelles grep (Beispiel: rg TODO)", "rg", "rg", new_tab=False),
# --- Anzeige ---
Tool("Anzeige", "bat", "cat mit Syntax-Highlighting", "bat", "bat", new_tab=False),
Tool("Anzeige", "eza -la", "Modernes ls mit Details, Farben, Git-Status", "eza -la", "eza", new_tab=False),
Tool("Anzeige", "eza -T", "Verzeichnisbaum", "eza -T", "eza", new_tab=False),
Tool("Anzeige", "delta", "Schöne Git-Diffs (wird automatisch verwendet)", "git diff HEAD~1 | delta", "delta", new_tab=False),
# --- System & Monitoring ---
Tool("System", "btop", "Systemmonitor (CPU/RAM/Netz/Prozesse)", "btop", "btop"),
Tool("System", "fastfetch", "Systeminfo Übersicht", "fastfetch", "fastfetch", new_tab=False),
Tool("System", "temps", "CPU/GPU-Temperatur + Akku (Mac)", "sudo powermetrics -s cpu_power,gpu_power,thermal,battery -i 1000 -n 1",
"sudo", new_tab=False, linux=False),
# --- Netzwerk ---
Tool("Netzwerk", "nmap", "Netzwerk-Scanner (Beispiel: nmap 10.47.11.0/24)", "nmap -sn 10.47.11.0/24", "nmap", new_tab=False),
# --- Berechnung ---
Tool("Rechnen", "units", "Einheitenumrechnung (Beispiel: units '1 kWh' MJ)", "units", "units"),
Tool("Rechnen", "python3", "Python REPL für schnelle Berechnungen", "python3", "python3"),
# --- KI ---
Tool("KI", "ki-chat", "Offline-KI interaktiver Chat", "ki interactive", "ki"),
Tool("KI", "ki-agent", "Offline-KI Agent-Modus (Datei-/Shell-Zugriff)", "ki interactive --agent-mode", "ki"),
Tool("KI", "ki-commit", "Commit-Message mit KI generieren", "ki commit", "ki", new_tab=False),
Tool("KI", "ki-diff", "Git-Diff mit KI erklären lassen", "ki diff", "ki", new_tab=False),
# --- Screensaver / Spass ---
Tool("Spass", "cmatrix", "Matrix-Regen (q = quit)", "cmatrix -sab", "cmatrix"),
Tool("Spass", "asciiquarium", "Aquarium im Terminal (q = quit)", "asciiquarium", "asciiquarium"),
Tool("Spass", "pipes.sh", "Animierte Rohre (q = quit)", "pipes.sh -t 0 -p 4", "pipes.sh"),
Tool("Spass", "cbonsai", "Wachsender Bonsai-Baum (q = quit)", "cbonsai -l", "cbonsai"),
Tool("Spass", "nms", "Sneakers-Entschlüsselungseffekt", "ls -la | nms", "nms", new_tab=False),
]
# --- Binaries die auf Linux anders heissen ---
LINUX_ALIASES = {
"fd": "fdfind",
"bat": "batcat",
}
def is_available(tool: Tool) -> bool:
if IS_MAC and not tool.mac:
return False
if IS_LINUX and not tool.linux:
return False
binary = tool.binary
if IS_LINUX:
binary = LINUX_ALIASES.get(binary, binary)
return shutil.which(binary) is not None
def resolve_command(command: str) -> str:
"""Passt Befehle für Linux an (bat→batcat etc.)."""
if IS_LINUX:
for mac_bin, linux_bin in LINUX_ALIASES.items():
if command.startswith(mac_bin + " ") or command == mac_bin:
command = linux_bin + command[len(mac_bin):]
return command
def detect_linux_terminal() -> list[str]:
"""Findet einen verfügbaren Terminal-Emulator auf Linux."""
candidates = [
(["xfce4-terminal", "--tab", "-e"], "xfce4-terminal"),
(["gnome-terminal", "--tab", "--"], "gnome-terminal"),
(["kitty", "bash", "-c"], "kitty"),
(["alacritty", "-e"], "alacritty"),
(["xterm", "-e"], "xterm"),
]
for args, binary in candidates:
if shutil.which(binary):
return args
return []
def open_new_tab(command: str):
"""Öffnet Befehl in neuem Tab — macOS oder Linux."""
if IS_MAC:
script = f'''
tell application "iTerm2"
activate
tell current window
create tab with default profile
tell current session
write text "{command}"
end tell
end tell
end tell
'''
subprocess.run(["osascript", "-e", script], capture_output=True)
else:
terminal_args = detect_linux_terminal()
if terminal_args:
subprocess.Popen(terminal_args + [f"bash -c '{command}; exec bash'"])
else:
# Fallback: inline
os.system(command)
def run_inline(command: str):
os.system(command)
def main():
available = [t for t in TOOLS if is_available(t)]
if not shutil.which("fzf"):
print("fzf nicht gefunden bitte installieren:")
print(" macOS: brew install fzf")
print(" Linux: sudo apt install fzf")
sys.exit(1)
fzf_lines = [
f"{t.category:<12} {t.name:<20} {t.description}"
for t in available
]
result = subprocess.run(
[
"fzf",
"--ansi",
"--height=70%",
"--layout=reverse",
"--border=rounded",
"--prompt= Tools > ",
"--header= Kategorie Name Beschreibung\n ─────────────────────────────────────────────────────────────",
"--color=header:italic:cyan,prompt:green,pointer:green",
],
input="\n".join(fzf_lines),
text=True,
capture_output=True,
)
if result.returncode != 0 or not result.stdout.strip():
sys.exit(0)
chosen_line = result.stdout.strip()
chosen_tool = None
for i, line in enumerate(fzf_lines):
if line == chosen_line:
chosen_tool = available[i]
break
if not chosen_tool:
sys.exit(0)
command = resolve_command(chosen_tool.command)
print(f"\n{chosen_tool.name}{command}\n")
if chosen_tool.new_tab:
open_new_tab(command)
else:
run_inline(command)
if __name__ == "__main__":
main()