toolbox: 65 Tools, Install/Uninstall, Ctrl-N, ausführliche Beschreibungen
- Tool-Dataclass um details, brew, apt Felder erweitert - ~65 Tools in 12 Kategorien (neu: Text/Daten, Dokumente, Bilder, Produktiv) - Nicht installierte Tools gedimmt mit Install-Angebot (brew/apt) - Ctrl-X: Deinstallation mit Bestätigung - Ctrl-N: Wizard zum Hinzufügen eigener Tools (custom_tools.json) - Kategorie-Header zeigt installiert/gesamt-Zähler - Preview-Pane rechts mit ausführlichen Beschreibungen und Beispielen - heic2jpg und h2j korrekt aus Scripts dokumentiert
This commit is contained in:
parent
cc2971fdd7
commit
831fe62de7
2 changed files with 839 additions and 110 deletions
71
README.md
71
README.md
|
|
@ -58,16 +58,33 @@ gitupdate # alle Repos pullen
|
||||||
|
|
||||||
### toolbox / tools - interaktiver Tool-Launcher
|
### toolbox / tools - interaktiver Tool-Launcher
|
||||||
|
|
||||||
Zweistufiges fzf-Menü: erst Kategorie wählen, dann Tool — mit Preview-Pane für Beschreibung und Befehl.
|
Zweistufiges fzf-Menü: erst Kategorie wählen, dann Tool — mit Preview-Pane für ausführliche
|
||||||
Öffnet immer in einem neuen Fenster mit aktuellem Profil im aktuellen Verzeichnis.
|
Beschreibung und Beispiele. Öffnet immer in einem neuen Tab (macOS: iTerm2, Linux: xfce4-terminal,
|
||||||
Funktioniert auf macOS (iTerm2) und Linux (xfce4-terminal, gnome-terminal, kitty, alacritty).
|
gnome-terminal, kitty, alacritty) im aktuellen Verzeichnis.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tools # interaktiver Launcher
|
tools # interaktiver Launcher
|
||||||
tools-ref # statisches Cheatsheet (Kurzform: tr)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Mac-only Tools (z.B. `temps`) werden auf Linux automatisch ausgeblendet.
|
Tastenbelegung im Tool-Menü:
|
||||||
|
|
||||||
|
| Taste | Funktion |
|
||||||
|
|-------|----------|
|
||||||
|
| `Enter` | Tool in neuem Tab starten |
|
||||||
|
| `Ctrl-X` | Installiertes Tool deinstallieren |
|
||||||
|
| `Ctrl-N` | Neues Tool hinzufügen (Wizard) |
|
||||||
|
| `Esc` | Zurück zur Kategorieauswahl |
|
||||||
|
|
||||||
|
Nicht installierte Tools werden **gedimmt** angezeigt — `Enter` bietet die Installation an
|
||||||
|
(`brew install …` / `sudo apt install …`). Der Kategorie-Header zeigt `(installiert/gesamt)`.
|
||||||
|
|
||||||
|
Kategorien: Git, Dateien, Anzeige, System, Netzwerk, Text/Daten, Rechnen, Produktiv,
|
||||||
|
Dokumente, Bilder, KI, Spass — insgesamt ~65 vorkonfigurierte Tools.
|
||||||
|
|
||||||
|
**Eigene Tools** werden in `~/.config/toolbox/custom_tools.json` gespeichert und
|
||||||
|
beim Start automatisch geladen. Die JSON-Datei ist auch manuell editierbar.
|
||||||
|
|
||||||
|
Mac-only Tools (z.B. `temps`, `dog`) werden auf Linux automatisch ausgeblendet.
|
||||||
Linux-Binaries (`batcat`, `fdfind`) werden automatisch aufgelöst.
|
Linux-Binaries (`batcat`, `fdfind`) werden automatisch aufgelöst.
|
||||||
|
|
||||||
### git-notify - Update-Benachrichtigung beim Shell-Start
|
### git-notify - Update-Benachrichtigung beim Shell-Start
|
||||||
|
|
@ -93,27 +110,31 @@ Verwendet `pbpaste`/`pbcopy` auf macOS und `xclip` auf Linux.
|
||||||
|
|
||||||
## Terminal-Tools (installiert & konfiguriert)
|
## Terminal-Tools (installiert & konfiguriert)
|
||||||
|
|
||||||
| Tool | Zweck | Alias |
|
Alle Tools sind über `tools` (toolbox) erreichbar. Hier eine Auswahl der wichtigsten:
|
||||||
|------|-------|-------|
|
|
||||||
| **lazygit** | Git TUI: stagen, committen, rebasen | `lg` |
|
|
||||||
| **delta** | Schöne Git-Diffs (side-by-side, automatisch aktiv) | — |
|
|
||||||
| **atuin** | Fuzzy History-Suche mit Zeitstempel | `Ctrl+R` |
|
|
||||||
| **mise** | Tool-Versionen pro Projekt verwalten | `mise use` |
|
|
||||||
| **btop** | Systemmonitor (CPU/RAM/Netz/Prozesse) | `btop` |
|
|
||||||
| **yazi** | Terminal-Dateimanager | `yazi` |
|
|
||||||
| **bat** | cat mit Syntax-Highlighting | `bat` |
|
|
||||||
| **eza** | Modernes ls | `eza -la`, `eza -T` |
|
|
||||||
| **fzf** | Fuzzy-Finder | `Ctrl+T`, `Ctrl+R` |
|
|
||||||
| **zoxide** | Smart cd (lernt häufige Pfade) | `z` |
|
|
||||||
| **nmap** | Netzwerk-Scanner | `nmap` |
|
|
||||||
| **units** | Einheitenumrechnung | `units` |
|
|
||||||
| **cmatrix** | Matrix-Screensaver | `cmatrix` |
|
|
||||||
| **asciiquarium** | Aquarium-Screensaver | `asciiquarium` |
|
|
||||||
| **pipes.sh** | Rohre-Screensaver | `pipes.sh` |
|
|
||||||
| **cbonsai** | Bonsai-Screensaver | `cbonsai` |
|
|
||||||
| **nms** | Sneakers-Entschlüsselungseffekt | `ls \| nms` |
|
|
||||||
|
|
||||||
Screensaver rotieren automatisch nach 5 Minuten Idle.
|
| Tool | Kategorie | Zweck |
|
||||||
|
|------|-----------|-------|
|
||||||
|
| **lazygit** | Git | Git TUI: stagen, committen, rebasen |
|
||||||
|
| **tig** | Git | Git-Log TUI: History, Blame, Branches |
|
||||||
|
| **gh** | Git | GitHub CLI: PRs, Issues, Repos |
|
||||||
|
| **delta** | Anzeige | Schöne Git-Diffs (side-by-side) |
|
||||||
|
| **yazi** | Dateien | TUI-Dateimanager mit Bildvorschau |
|
||||||
|
| **fzf** | Dateien | Universeller Fuzzy-Finder |
|
||||||
|
| **fd** | Dateien | Schnelles find |
|
||||||
|
| **rg** | Dateien | Blitzschnelles grep (ripgrep) |
|
||||||
|
| **bat** | Anzeige | cat mit Syntax-Highlighting |
|
||||||
|
| **eza** | Anzeige | Modernes ls mit Git-Status |
|
||||||
|
| **btop** | System | Systemmonitor (CPU/RAM/Netz/Prozesse) |
|
||||||
|
| **jq** | Text/Daten | JSON-Prozessor |
|
||||||
|
| **yq** | Text/Daten | YAML/JSON-Prozessor |
|
||||||
|
| **pandoc** | Dokumente | Dokument-Konverter (md↔pdf↔docx) |
|
||||||
|
| **heic2jpg / h2j** | Bilder | HEIC → JPG konvertieren |
|
||||||
|
| **ffmpeg** | Bilder | Video/Audio konvertieren |
|
||||||
|
| **tldr** | Produktiv | Vereinfachte Manpages mit Beispielen |
|
||||||
|
| **nmap** | Netzwerk | Netzwerk-Scanner |
|
||||||
|
| **zoxide** | Dateien | Smart cd (lernt häufige Pfade) |
|
||||||
|
|
||||||
|
Screensaver (cmatrix, asciiquarium, pipes.sh, cbonsai) rotieren automatisch nach 5 Minuten Idle.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
|
||||||
872
bin/toolbox
872
bin/toolbox
|
|
@ -10,72 +10,600 @@ import sys
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import shlex
|
import shlex
|
||||||
|
import json
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
IS_MAC = platform.system() == "Darwin"
|
IS_MAC = platform.system() == "Darwin"
|
||||||
IS_LINUX = platform.system() == "Linux"
|
IS_LINUX = platform.system() == "Linux"
|
||||||
|
|
||||||
CURRENT_DIR = os.getcwd()
|
CURRENT_DIR = os.getcwd()
|
||||||
|
CUSTOM_TOOLS_FILE = os.path.expanduser("~/.config/toolbox/custom_tools.json")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Tool:
|
class Tool:
|
||||||
category: str
|
category: str
|
||||||
name: str
|
name: str
|
||||||
description: str
|
description: str # Kurztext für die Listenansicht
|
||||||
|
details: str # Ausführliche Beschreibung + Beispiele für den Preview
|
||||||
command: str
|
command: str
|
||||||
binary: str
|
binary: str
|
||||||
mac: bool = True
|
mac: bool = True
|
||||||
linux: bool = True
|
linux: bool = True
|
||||||
|
brew: str = "" # Paketname für brew install (falls ≠ binary)
|
||||||
|
apt: str = "" # Paketname für apt install (falls ≠ binary)
|
||||||
|
|
||||||
|
|
||||||
TOOLS = [
|
TOOLS = [
|
||||||
# --- Git ---
|
# ── Git ──────────────────────────────────────────────────────────────────
|
||||||
Tool("Git", "lazygit", "Git TUI: stagen, committen, pushen, rebasen", "lazygit", "lazygit"),
|
Tool("Git", "lazygit",
|
||||||
Tool("Git", "gitcheck", "Status aller Repos prüfen", "~/git-check-all.sh", "git"),
|
"Git TUI: stagen, committen, pushen, rebasen",
|
||||||
Tool("Git", "gitsync", "Alle Repos mit Gitea synchronisieren", "~/git-projekte/dotfiles-rene/bin/git-sync-all.sh", "git"),
|
"Vollständige Git-Oberfläche im Terminal: Dateien interaktiv stagen, "
|
||||||
Tool("Git", "git log", "Commit-History (mit delta, side-by-side)", "git log -p", "git"),
|
"committen, pushen, Branches wechseln, interaktives Rebase, Stash verwalten, "
|
||||||
Tool("Git", "git diff", "Änderungen anzeigen (mit delta)", "git diff", "git"),
|
"Merge-Konflikte lösen — alles ohne git-Befehle tippen.",
|
||||||
|
"lazygit", "lazygit"),
|
||||||
|
|
||||||
# --- Navigation & Dateien ---
|
Tool("Git", "tig",
|
||||||
Tool("Dateien", "yazi", "Terminal-Dateimanager (q = quit)", "yazi", "yazi"),
|
"Git-Log TUI: Commits durchsuchen und Blame anzeigen",
|
||||||
Tool("Dateien", "fzf", "Fuzzy-Finder: Dateien und History durchsuchen", "fzf", "fzf"),
|
"Interaktiver Git-Log-Browser: Commit-History navigieren, vollständige Diffs "
|
||||||
Tool("Dateien", "ncdu", "Interaktive Festplattennutzung", "ncdu ~", "ncdu"),
|
"anzeigen, Branches vergleichen, Blame-Ansicht, Stash und Refs erkunden.\n"
|
||||||
Tool("Dateien", "duf", "Übersicht freier Speicherplatz", "duf", "duf"),
|
"Bsp: tig / tig blame src/main.py / tig HEAD..origin/main",
|
||||||
Tool("Dateien", "fd", "Schnelles find (Beispiel: fd .py)", "fd", "fd"),
|
"tig", "tig"),
|
||||||
Tool("Dateien", "rg", "Blitzschnelles grep (Beispiel: rg TODO)", "rg", "rg"),
|
|
||||||
|
|
||||||
# --- Anzeige ---
|
Tool("Git", "gh",
|
||||||
Tool("Anzeige", "bat", "cat mit Syntax-Highlighting", "bat", "bat"),
|
"GitHub CLI: PRs, Issues und Repos im Terminal",
|
||||||
Tool("Anzeige", "eza -la", "Modernes ls mit Details, Farben, Git-Status", "eza -la", "eza"),
|
"Offizielle GitHub CLI: Pull Requests erstellen und reviewen, Issues verwalten, "
|
||||||
Tool("Anzeige", "eza -T", "Verzeichnisbaum", "eza -T", "eza"),
|
"Repos klonen, Actions-Logs abrufen, Releases erstellen.\n"
|
||||||
Tool("Anzeige", "delta", "Schöne Git-Diffs (wird automatisch verwendet)", "git diff HEAD~1 | delta", "delta"),
|
"Bsp: gh pr create / gh pr list / gh issue list / gh repo clone owner/repo "
|
||||||
|
"/ gh run list",
|
||||||
|
"gh pr list", "gh"),
|
||||||
|
|
||||||
# --- System & Monitoring ---
|
Tool("Git", "gitcheck",
|
||||||
Tool("System", "btop", "Systemmonitor: CPU, RAM, Netz, Prozesse", "btop", "btop"),
|
"Status aller lokalen Repos auf einen Blick prüfen",
|
||||||
Tool("System", "fastfetch", "Systeminfo-Übersicht", "fastfetch", "fastfetch"),
|
"Durchläuft alle Git-Repos im Home-Verzeichnis und zeigt an, welche "
|
||||||
Tool("System", "temps", "CPU/GPU-Temperatur + Akku (Mac)", "sudo powermetrics -s cpu_power,gpu_power,thermal,battery -i 1000 -n 1",
|
"uncommittete Änderungen, unpushed Commits oder fetch-fähige Updates haben.",
|
||||||
|
"~/git-check-all.sh", "git"),
|
||||||
|
|
||||||
|
Tool("Git", "gitsync",
|
||||||
|
"Alle Repos mit Gitea synchronisieren",
|
||||||
|
"Führt für alle konfigurierten Git-Repos ein fetch, pull und ggf. push "
|
||||||
|
"gegen den Gitea-Server durch — hält alle lokalen Klone aktuell.",
|
||||||
|
"~/git-projekte/dotfiles-rene/bin/git-sync-all.sh", "git"),
|
||||||
|
|
||||||
|
Tool("Git", "git log",
|
||||||
|
"Commit-History mit vollem Diff (delta, side-by-side)",
|
||||||
|
"Zeigt die vollständige Commit-History inklusive Diffs — nutzt delta für "
|
||||||
|
"Syntax-Highlighting und optionalen Side-by-Side-Vergleich.\n"
|
||||||
|
"Bsp: git log -p / git log --oneline / git log -p --since=1.week "
|
||||||
|
"/ git log --author='Name'",
|
||||||
|
"git log -p", "git"),
|
||||||
|
|
||||||
|
Tool("Git", "git diff",
|
||||||
|
"Änderungen zum letzten Commit anzeigen (delta)",
|
||||||
|
"Zeigt alle nicht gestagten Änderungen mit Syntax-Highlighting via delta.\n"
|
||||||
|
"Bsp: git diff / git diff HEAD~1 / git diff main..feature "
|
||||||
|
"/ git diff -- src/foo.py",
|
||||||
|
"git diff", "git"),
|
||||||
|
|
||||||
|
Tool("Git", "onefetch",
|
||||||
|
"Repo-Übersicht: Sprachen, Commits, Autoren",
|
||||||
|
"Zeigt eine kompakte Zusammenfassung des aktuellen Git-Repos: "
|
||||||
|
"Top-Programmiersprachen nach Anteil, Anzahl Commits, aktivste Autoren, "
|
||||||
|
"Lizenz, letzter Commit, Repo-Größe — wie neofetch für Git-Repos.",
|
||||||
|
"onefetch", "onefetch"),
|
||||||
|
|
||||||
|
# ── Dateien ──────────────────────────────────────────────────────────────
|
||||||
|
Tool("Dateien", "yazi",
|
||||||
|
"TUI-Dateimanager mit Bildvorschau und Plugins",
|
||||||
|
"Moderner Dateimanager mit Vorschau für Bilder, Videos, PDFs und Code, "
|
||||||
|
"Bulk-Rename, Plugin-System, Async-Operationen und vi-Keybindings.\n"
|
||||||
|
"Steuerung: hjkl navigieren / Enter öffnen / y kopieren / d ausschneiden "
|
||||||
|
"/ p einfügen / r umbenennen / q beenden",
|
||||||
|
"yazi", "yazi"),
|
||||||
|
|
||||||
|
Tool("Dateien", "lf",
|
||||||
|
"Schneller Vim-artiger Dateimanager",
|
||||||
|
"Schlanker, schneller Dateimanager mit vi-Keybindings und Shell-Integration. "
|
||||||
|
"Vollständig konfigurierbar über ~/.config/lf/lfrc — unterstützt Vorschauen, "
|
||||||
|
"benutzerdefinierte Befehle und Lesezeichen.\n"
|
||||||
|
"Steuerung: hjkl navigieren / Enter öffnen / q beenden",
|
||||||
|
"lf", "lf"),
|
||||||
|
|
||||||
|
Tool("Dateien", "broot",
|
||||||
|
"Navigierbarer Verzeichnisbaum mit Inline-Fuzzy-Suche",
|
||||||
|
"Zeigt den Verzeichnisbaum und sucht gleichzeitig während man tippt. "
|
||||||
|
"Öffnet Dateien im Editor, unterstützt Kopieren/Verschieben und zeigt "
|
||||||
|
"Größen an. Alias 'br' für komfortablen Start.\n"
|
||||||
|
"Bsp: broot / broot /etc / bsp: 'br' dann '.py' tippen zum Filtern",
|
||||||
|
"broot", "broot"),
|
||||||
|
|
||||||
|
Tool("Dateien", "fzf",
|
||||||
|
"Universeller interaktiver Fuzzy-Finder",
|
||||||
|
"Filtert beliebige Listen interaktiv mit Fuzzy-Matching. Integration in "
|
||||||
|
"Shell-History (Ctrl-R), Dateisuche und als Filter in Pipelines.\n"
|
||||||
|
"Bsp: fzf / vim $(fzf) / history | fzf / git checkout $(git branch | fzf)",
|
||||||
|
"fzf", "fzf"),
|
||||||
|
|
||||||
|
Tool("Dateien", "fd",
|
||||||
|
"Schnelles find mit intuitiver Syntax",
|
||||||
|
"Findet Dateien schneller als find, ignoriert standardmäßig .gitignore-Einträge "
|
||||||
|
"und versteckte Verzeichnisse, unterstützt reguläre Ausdrücke und Typenfilter.\n"
|
||||||
|
"Bsp: fd .py / fd -e rs src/ / fd -H .env / fd --type d / fd -x cp {} backup/",
|
||||||
|
"fd", "fd", apt="fd-find"),
|
||||||
|
|
||||||
|
Tool("Dateien", "rg",
|
||||||
|
"Blitzschnelles grep mit PCRE-Regex und gitignore-Support",
|
||||||
|
"Durchsucht Verzeichnisbäume nach Muster — deutlich schneller als grep/ag, "
|
||||||
|
"respektiert .gitignore, unterstützt PCRE2-Regex und zeigt Kontext.\n"
|
||||||
|
"Bsp: rg TODO / rg -t py 'def main' / rg -l pattern / rg -C 3 'Error' "
|
||||||
|
"/ rg --hidden '.env'",
|
||||||
|
"rg", "rg", brew="ripgrep", apt="ripgrep"),
|
||||||
|
|
||||||
|
Tool("Dateien", "ncdu",
|
||||||
|
"Interaktive Festplattennutzung verwalten",
|
||||||
|
"Zeigt Verzeichnisgrößen interaktiv und lässt Dateien/Ordner direkt löschen. "
|
||||||
|
"Ideal zum Aufspüren von Platzverschwendern.\n"
|
||||||
|
"Steuerung: Pfeiltasten navigieren / d löschen / i Info / q beenden",
|
||||||
|
"ncdu ~", "ncdu"),
|
||||||
|
|
||||||
|
Tool("Dateien", "dust",
|
||||||
|
"Verzeichnisgrößen als farbiges Balkendiagramm",
|
||||||
|
"Zeigt Verzeichnisgrößen als Balken, automatisch nach Größe sortiert — "
|
||||||
|
"schneller und übersichtlicher als 'du -sh *'.\n"
|
||||||
|
"Bsp: dust / dust ~ / dust -d 2 /var / dust -n 20",
|
||||||
|
"dust ~", "dust", apt="du-dust"),
|
||||||
|
|
||||||
|
Tool("Dateien", "duf",
|
||||||
|
"Freier Speicherplatz aller Laufwerke auf einen Blick",
|
||||||
|
"Zeigt alle Laufwerke, Partitionen und Netzwerk-Mounts mit belegtem und "
|
||||||
|
"freiem Speicherplatz in einer übersichtlichen Tabelle.\n"
|
||||||
|
"Bsp: duf / duf /home /var / duf --only local",
|
||||||
|
"duf", "duf"),
|
||||||
|
|
||||||
|
Tool("Dateien", "zoxide",
|
||||||
|
"Intelligentes cd — merkt sich häufig besuchte Verzeichnisse",
|
||||||
|
"Lernt welche Verzeichnisse man häufig besucht und springt mit 'z <teilname>' "
|
||||||
|
"direkt dorthin — ohne den vollen Pfad zu tippen.\n"
|
||||||
|
"Bsp: z proj (springt zu ~/git-projekte/…) / z dot (springt zu dotfiles) "
|
||||||
|
"/ zi (interaktive Auswahl mit fzf)",
|
||||||
|
"zoxide query --list", "zoxide"),
|
||||||
|
|
||||||
|
# ── Anzeige ──────────────────────────────────────────────────────────────
|
||||||
|
Tool("Anzeige", "bat",
|
||||||
|
"cat mit Syntax-Highlighting und Git-Markierungen",
|
||||||
|
"cat-Ersatz mit automatischem Syntax-Highlighting für hunderte Sprachen, "
|
||||||
|
"Zeilennummern, Git-Änderungsmarkierungen am Rand und automatischem Paging.\n"
|
||||||
|
"Bsp: bat README.md / bat src/main.py / bat --language json data "
|
||||||
|
"/ cat large.log | bat",
|
||||||
|
"bat", "bat", apt="batcat"),
|
||||||
|
|
||||||
|
Tool("Anzeige", "eza -la",
|
||||||
|
"Modernes ls mit Farben, Icons und Git-Status",
|
||||||
|
"Ersatz für ls mit Farben, optionalen Icons, Git-Status pro Datei, "
|
||||||
|
"Berechtigungen, Größen und Zeitstempeln — übersichtlicher als ls -la.\n"
|
||||||
|
"Bsp: eza -la / eza -la --git / eza -la --icons / eza --sort=size",
|
||||||
|
"eza -la", "eza"),
|
||||||
|
|
||||||
|
Tool("Anzeige", "eza -T",
|
||||||
|
"Farbiger Verzeichnisbaum mit Git-Status",
|
||||||
|
"Zeigt einen Verzeichnisbaum in Farbe mit Git-Status, Icons und "
|
||||||
|
"konfigurierbarer Tiefe — besser als tree.\n"
|
||||||
|
"Bsp: eza -T / eza -T --level=2 / eza -T --git-ignore / eza -T src/",
|
||||||
|
"eza -T", "eza"),
|
||||||
|
|
||||||
|
Tool("Anzeige", "delta",
|
||||||
|
"Schöne farbige Git-Diffs mit Syntax-Highlighting",
|
||||||
|
"Verschönert Git-Diffs mit Syntax-Highlighting, Zeilennummern, "
|
||||||
|
"Side-by-Side-Vergleich und konfigurierbaren Themes — wird automatisch von "
|
||||||
|
"git diff/log/show verwendet wenn konfiguriert.\n"
|
||||||
|
"Bsp: git diff HEAD~1 | delta / git show abc1234 | delta",
|
||||||
|
"git diff HEAD~1 | delta", "delta"),
|
||||||
|
|
||||||
|
Tool("Anzeige", "glow",
|
||||||
|
"Markdown schön gerendert im Terminal",
|
||||||
|
"Rendert Markdown-Dateien mit Überschriften, Tabellen, Code-Blöcken und "
|
||||||
|
"Hervorhebungen direkt im Terminal — ideal für READMEs und Dokumentation.\n"
|
||||||
|
"Bsp: glow README.md / glow -p CHANGELOG.md / glow docs/ "
|
||||||
|
"/ curl -s raw-url | glow -",
|
||||||
|
"glow", "glow"),
|
||||||
|
|
||||||
|
Tool("Anzeige", "hexyl",
|
||||||
|
"Hex-Viewer mit farbiger ASCII-Darstellung",
|
||||||
|
"Zeigt Binärdateien als Hex-Dump mit farbiger Markierung verschiedener "
|
||||||
|
"Byte-Typen (NULL, ASCII, nicht-druckbar) und paralleler ASCII-Darstellung.\n"
|
||||||
|
"Bsp: hexyl /bin/ls / hexyl -n 256 file.bin / hexyl --skip 512 img.raw",
|
||||||
|
"hexyl", "hexyl"),
|
||||||
|
|
||||||
|
Tool("Anzeige", "tokei",
|
||||||
|
"Codezeilen-Statistik nach Programmiersprache",
|
||||||
|
"Zählt Codezeilen, Kommentare und Leerzeilen aufgeteilt nach "
|
||||||
|
"Programmiersprache — schnell auch bei großen Repos.\n"
|
||||||
|
"Bsp: tokei / tokei src/ / tokei --sort lines / tokei -e vendor/",
|
||||||
|
"tokei", "tokei"),
|
||||||
|
|
||||||
|
# ── System ───────────────────────────────────────────────────────────────
|
||||||
|
Tool("System", "btop",
|
||||||
|
"Systemmonitor TUI: CPU, RAM, Netz, Prozesse",
|
||||||
|
"Vollständiger Ressourcenmonitor: CPU-Auslastung pro Kern, RAM- und Swap-Nutzung, "
|
||||||
|
"Netzwerkdurchsatz, Disk-I/O und Prozessliste mit Baumansicht und Filter.\n"
|
||||||
|
"Steuerung: Maus oder Tastatur / f filtern / k beenden / q quit",
|
||||||
|
"btop", "btop"),
|
||||||
|
|
||||||
|
Tool("System", "htop",
|
||||||
|
"Klassischer interaktiver Prozess-Monitor",
|
||||||
|
"Interaktiver Prozess-Monitor mit Baumansicht, Sortierung nach CPU/RAM, "
|
||||||
|
"Filter-Funktion und der Möglichkeit Prozesse direkt zu beenden oder zu renicen.\n"
|
||||||
|
"Steuerung: F6 sortieren / F4 filtern / F9 beenden / t Baumansicht",
|
||||||
|
"htop", "htop"),
|
||||||
|
|
||||||
|
Tool("System", "procs",
|
||||||
|
"Modernes ps mit Farben und Baumansicht",
|
||||||
|
"Prozessliste mit Farben, Baumansicht, Suchfilter nach Name/PID/Port und "
|
||||||
|
"übersichtlicher Darstellung von CPU, RAM und Laufzeit.\n"
|
||||||
|
"Bsp: procs / procs nginx / procs --tree / procs 8080 (nach Port)",
|
||||||
|
"procs", "procs"),
|
||||||
|
|
||||||
|
Tool("System", "fastfetch",
|
||||||
|
"Systeminfo-Übersicht mit ASCII-Logo",
|
||||||
|
"Zeigt Systeminformationen schnell und übersichtlich: OS, Kernel-Version, "
|
||||||
|
"CPU, RAM, GPU, Shell, Terminal, Uptime, IP-Adresse — mit ASCII-Logo des OS.\n"
|
||||||
|
"Bsp: fastfetch / fastfetch --logo none / fastfetch -c all",
|
||||||
|
"fastfetch", "fastfetch"),
|
||||||
|
|
||||||
|
Tool("System", "hyperfine",
|
||||||
|
"Präzises Benchmarking für Shell-Befehle",
|
||||||
|
"Misst die Ausführungszeit von Befehlen mit statistischer Auswertung "
|
||||||
|
"(Mittelwert, Standardabweichung), Warmup-Runs und direktem Vergleich.\n"
|
||||||
|
"Bsp: hyperfine 'ls -la' 'eza -la' / hyperfine --warmup 5 'grep -r TODO .' "
|
||||||
|
"/ hyperfine --export-markdown bench.md 'cmd1' 'cmd2'",
|
||||||
|
"hyperfine --help", "hyperfine"),
|
||||||
|
|
||||||
|
Tool("System", "lsof ports",
|
||||||
|
"Offene TCP-Ports und zugehörige Prozesse anzeigen",
|
||||||
|
"Zeigt alle Prozesse, die aktuell auf TCP-Ports lauschen — nützlich zum "
|
||||||
|
"Debuggen von Port-Konflikten und zum Überprüfen aktiver Services.\n"
|
||||||
|
"Bsp: lsof -nP -iTCP -sTCP:LISTEN / lsof -i :8080 / lsof -p 1234",
|
||||||
|
"lsof -nP -iTCP -sTCP:LISTEN", "lsof"),
|
||||||
|
|
||||||
|
Tool("System", "temps",
|
||||||
|
"CPU/GPU-Temperatur und Akku-Status (Mac)",
|
||||||
|
"Liest CPU- und GPU-Temperatur, Leistungsaufnahme und Akku-Status via "
|
||||||
|
"powermetrics aus — nur auf macOS verfügbar, benötigt sudo.",
|
||||||
|
"sudo powermetrics -s cpu_power,gpu_power,thermal,battery -i 1000 -n 1",
|
||||||
"sudo", linux=False),
|
"sudo", linux=False),
|
||||||
|
|
||||||
# --- Netzwerk ---
|
# ── Netzwerk ─────────────────────────────────────────────────────────────
|
||||||
Tool("Netzwerk", "nmap", "Netzwerk-Scanner (Beispiel: nmap 10.47.11.0/24)", "nmap -sn 10.47.11.0/24", "nmap"),
|
Tool("Netzwerk", "nmap",
|
||||||
|
"Netzwerk-Scanner: Hosts und Ports entdecken",
|
||||||
|
"Scannt Netzwerke nach aktiven Hosts, offenen Ports und laufenden Services. "
|
||||||
|
"Unverzichtbar für Netzwerk-Diagnose und Sicherheitsüberprüfungen.\n"
|
||||||
|
"Bsp: nmap -sn 192.168.1.0/24 (Ping-Scan) / nmap -p 22,80,443 host "
|
||||||
|
"/ nmap -sV host (Service-Versionen) / nmap -A host (aggressiv)",
|
||||||
|
"nmap -sn 10.47.11.0/24", "nmap"),
|
||||||
|
|
||||||
# --- Berechnung ---
|
Tool("Netzwerk", "mtr",
|
||||||
Tool("Rechnen", "units", "Einheitenumrechnung (Beispiel: units 1kWh MJ)", "units", "units"),
|
"Live-Traceroute mit Ping-Statistik pro Hop",
|
||||||
Tool("Rechnen", "python3", "Python REPL für schnelle Berechnungen", "python3", "python3"),
|
"Kombiniert traceroute und ping: zeigt jeden Hop auf dem Weg zum Ziel "
|
||||||
|
"mit Latenz, Jitter und Paketverlust in Echtzeit — ideal zur Netzwerkdiagnose.\n"
|
||||||
|
"Bsp: mtr 8.8.8.8 / mtr --report google.com / mtr -n 192.168.1.1",
|
||||||
|
"mtr 8.8.8.8", "mtr"),
|
||||||
|
|
||||||
# --- KI ---
|
Tool("Netzwerk", "gping",
|
||||||
Tool("KI", "ki-chat", "Offline-KI interaktiver Chat", "ki interactive", "ki"),
|
"Grafischer Ping mit Live-Kurve für mehrere Hosts",
|
||||||
Tool("KI", "ki-agent", "Offline-KI Agent-Modus: Datei- und Shell-Zugriff", "ki interactive --agent-mode", "ki"),
|
"Pingt einen oder mehrere Hosts gleichzeitig und zeigt die Latenz als "
|
||||||
Tool("KI", "ki-commit", "Commit-Message mit KI generieren", "ki commit", "ki"),
|
"Live-Kurve im Terminal — sofort sichtbar wenn ein Host langsam oder ausgefallen ist.\n"
|
||||||
Tool("KI", "ki-diff", "Git-Diff mit KI erklären lassen", "ki diff", "ki"),
|
"Bsp: gping 1.1.1.1 / gping 1.1.1.1 8.8.8.8 google.com",
|
||||||
|
"gping 1.1.1.1", "gping"),
|
||||||
|
|
||||||
# --- Screensaver / Spass ---
|
Tool("Netzwerk", "bandwhich",
|
||||||
Tool("Spass", "cmatrix", "Matrix-Regen (q = quit)", "cmatrix -sab", "cmatrix"),
|
"Netzwerkauslastung nach Prozess in Echtzeit",
|
||||||
Tool("Spass", "asciiquarium", "Aquarium im Terminal (q = quit)", "asciiquarium", "asciiquarium"),
|
"Zeigt welche Prozesse und Verbindungen aktuell wie viel Netzwerkbandbreite "
|
||||||
Tool("Spass", "pipes.sh", "Animierte Rohre (q = quit)", "pipes.sh -t 0 -p 4", "pipes.sh"),
|
"verbrauchen — aufgeteilt nach Remote-Host und lokalem Prozess.\n"
|
||||||
Tool("Spass", "cbonsai", "Wachsender Bonsai-Baum (q = quit)", "cbonsai -l", "cbonsai"),
|
"Benötigt sudo für vollständige Prozessinfos.",
|
||||||
Tool("Spass", "nms", "Sneakers-Entschlüsselungseffekt", "ls -la | nms", "nms"),
|
"sudo bandwhich", "bandwhich"),
|
||||||
|
|
||||||
|
Tool("Netzwerk", "xh",
|
||||||
|
"Moderner HTTP-Client mit schöner Ausgabe",
|
||||||
|
"HTTP-Requests senden wie HTTPie aber schneller — intuitiver als curl, "
|
||||||
|
"farbige JSON-Ausgabe, Session-Support, automatisches Setzen von Content-Type.\n"
|
||||||
|
"Bsp: xh get httpbin.org/ip / xh post api.example.com name=Alice age:=30 "
|
||||||
|
"/ xh -d get example.com/file.zip / xh --auth user:pass get api.example.com",
|
||||||
|
"xh get httpbin.org/ip", "xh"),
|
||||||
|
|
||||||
|
Tool("Netzwerk", "dog",
|
||||||
|
"Modernes dig mit farbiger strukturierter Ausgabe",
|
||||||
|
"DNS-Lookups mit farbiger Ausgabe, strukturierten Ergebnissen und Unterstützung "
|
||||||
|
"für alle Record-Typen — intuitiver als dig.\n"
|
||||||
|
"Bsp: dog example.com / dog example.com A MX / dog @1.1.1.1 example.com "
|
||||||
|
"/ dog --json example.com | jq",
|
||||||
|
"dog example.com", "dog", linux=False),
|
||||||
|
|
||||||
|
# ── Text & Daten ─────────────────────────────────────────────────────────
|
||||||
|
Tool("Text/Daten", "jq",
|
||||||
|
"JSON-Prozessor für Kommandozeile",
|
||||||
|
"Filtert, transformiert und formatiert JSON — unverzichtbar beim Arbeiten "
|
||||||
|
"mit APIs und JSON-Dateien. Unterstützt komplexe Abfragen und Transformationen.\n"
|
||||||
|
"Bsp: curl api.x.com | jq '.name' / jq '.[] | select(.active)' file.json "
|
||||||
|
"/ jq -r '.users[].email' data.json / jq '{name, age}' input.json",
|
||||||
|
"jq", "jq"),
|
||||||
|
|
||||||
|
Tool("Text/Daten", "yq",
|
||||||
|
"YAML/JSON/XML-Prozessor (jq-Syntax für YAML)",
|
||||||
|
"Verarbeitet YAML, JSON und XML mit jq-ähnlicher Syntax — ideal für "
|
||||||
|
"Kubernetes-Manifeste, Docker Compose und Konfigurationsdateien.\n"
|
||||||
|
"Bsp: yq '.version' app.yaml / yq -i '.replicas = 3' deploy.yaml "
|
||||||
|
"/ yq -o json config.yaml / yq '.services | keys' docker-compose.yml",
|
||||||
|
"yq", "yq"),
|
||||||
|
|
||||||
|
Tool("Text/Daten", "fx",
|
||||||
|
"Interaktiver JSON-Viewer mit Navigation",
|
||||||
|
"Öffnet JSON interaktiv: Felder auf- und zuklappen, navigieren, mit "
|
||||||
|
"JavaScript-Ausdrücken filtern und transformieren.\n"
|
||||||
|
"Bsp: echo '{\"a\":1}' | fx / curl api.x.com | fx / fx data.json .users",
|
||||||
|
r"""echo '{"name":"Alice","items":[1,2,3]}' | fx""", "fx"),
|
||||||
|
|
||||||
|
Tool("Text/Daten", "miller (mlr)",
|
||||||
|
"CSV/TSV/JSON-Verarbeitung für tabellarische Daten",
|
||||||
|
"Schweizer Taschenmesser für strukturierte Daten: sortieren, filtern, "
|
||||||
|
"gruppieren, aggregieren — unterstützt CSV, TSV, JSON, NIDX.\n"
|
||||||
|
"Bsp: mlr --csv head -n 5 data.csv / mlr --csv sort-f name data.csv "
|
||||||
|
"/ mlr --csv filter '$age > 30' data.csv / mlr --csv stats1 -a mean -f price",
|
||||||
|
"mlr --help", "mlr", brew="miller", apt="miller"),
|
||||||
|
|
||||||
|
Tool("Text/Daten", "gron",
|
||||||
|
"Macht JSON grep-fähig durch Abflachung",
|
||||||
|
"Konvertiert verschachteltes JSON in flache Pfad=Wert-Zeilen — "
|
||||||
|
"danach mit grep/rg durchsuchbar, danach mit 'gron --ungron' zurückkonvertierbar.\n"
|
||||||
|
"Bsp: gron file.json | grep email / curl api.x.com | gron | grep '\\[0\\]' "
|
||||||
|
"/ gron data.json | grep name | gron --ungron",
|
||||||
|
r"""echo '{"user":{"name":"Alice","email":"a@b.com"}}' | gron""", "gron"),
|
||||||
|
|
||||||
|
# ── Rechnen ──────────────────────────────────────────────────────────────
|
||||||
|
Tool("Rechnen", "qalc",
|
||||||
|
"Wissenschaftlicher Rechner mit Einheiten und Währungen",
|
||||||
|
"Vollständiger Taschenrechner mit physikalischen Einheiten, Einheitenumrechnung "
|
||||||
|
"und Live-Wechselkursen — versteht natürliche Ausdrücke.\n"
|
||||||
|
"Bsp: qalc '100 USD to EUR' / qalc '5 km/h to mph' / qalc 'sin(pi/4)' "
|
||||||
|
"/ qalc '1 lightyear to km' / qalc '100 MiB to MB'",
|
||||||
|
"qalc", "qalc", brew="qalculate", apt="qalc"),
|
||||||
|
|
||||||
|
Tool("Rechnen", "units",
|
||||||
|
"Präzise Einheitenumrechnung für hunderte Einheiten",
|
||||||
|
"Konvertiert zwischen physikalischen Einheiten mit hoher Genauigkeit — "
|
||||||
|
"kennt SI, imperiale, historische und zusammengesetzte Einheiten.\n"
|
||||||
|
"Bsp: units '1kWh' 'MJ' / units '1 mile' km / units '5 acres' 'm^2' "
|
||||||
|
"/ units '100 km/h' 'miles/hour'",
|
||||||
|
"units", "units"),
|
||||||
|
|
||||||
|
Tool("Rechnen", "python3",
|
||||||
|
"Python REPL für Berechnungen und Skripte",
|
||||||
|
"Interaktiver Python-Interpreter — ideal für schnelle Berechnungen, "
|
||||||
|
"String-Manipulation, JSON-Parsing und kleine Skripte.\n"
|
||||||
|
"Bsp: python3 dann: import math; math.pi / 2**32 / hex(255) "
|
||||||
|
"/ import json; json.loads('{\"a\":1}')",
|
||||||
|
"python3", "python3"),
|
||||||
|
|
||||||
|
Tool("Rechnen", "bc",
|
||||||
|
"Taschenrechner für große Zahlen und hohe Präzision",
|
||||||
|
"Mathematische Skriptsprache für beliebig genaue Berechnungen — "
|
||||||
|
"gut für große Zahlen, Binär/Hex und trigonometrische Funktionen.\n"
|
||||||
|
"Bsp: echo '2^64' | bc / echo 'scale=20; 4*a(1)' | bc -l (Pi) "
|
||||||
|
"/ echo 'obase=16; 255' | bc (→ FF) / echo 'obase=2; 42' | bc (→ Binär)",
|
||||||
|
"bc -l", "bc"),
|
||||||
|
|
||||||
|
# ── Produktivität ────────────────────────────────────────────────────────
|
||||||
|
Tool("Produktiv", "tldr",
|
||||||
|
"Vereinfachte Manpages mit Praxis-Beispielen",
|
||||||
|
"Community-gepflegte Kurzreferenz für hunderte Befehle — zeigt nur die "
|
||||||
|
"wichtigsten Optionen mit echten Anwendungsbeispielen.\n"
|
||||||
|
"Bsp: tldr tar / tldr git commit / tldr find / tldr ffmpeg "
|
||||||
|
"/ tldr --update (Datenbank aktualisieren)",
|
||||||
|
"tldr", "tldr", brew="tealdeer"),
|
||||||
|
|
||||||
|
Tool("Produktiv", "navi",
|
||||||
|
"Interaktive Spickzettel mit ausfüllbaren Platzhaltern",
|
||||||
|
"Sucht in Community-Spickzetteln nach Befehlen und lässt Platzhalter "
|
||||||
|
"interaktiv ausfüllen — nie wieder lange Optionen vergessen.\n"
|
||||||
|
"Bsp: navi (Suche öffnen) / navi --query docker / navi repo add <github-url>",
|
||||||
|
"navi", "navi"),
|
||||||
|
|
||||||
|
Tool("Produktiv", "thefuck",
|
||||||
|
"Korrigiert den letzten fehlgeschlagenen Befehl",
|
||||||
|
"Analysiert Fehlermeldungen und schlägt die korrekte Version des letzten "
|
||||||
|
"Befehls vor — Tippfehler, fehlende sudo, falsche Flags werden erkannt.\n"
|
||||||
|
"Nutzung: nach einem Fehler einfach 'fuck' (oder 'f') tippen.",
|
||||||
|
"thefuck --help", "thefuck"),
|
||||||
|
|
||||||
|
Tool("Produktiv", "just",
|
||||||
|
"Moderner Make-Ersatz mit einfacherer Syntax",
|
||||||
|
"Führt Aufgaben aus einer 'justfile' aus — einfacher und mächtiger als Makefile, "
|
||||||
|
"unterstützt Variablen, Argumente, Abhängigkeiten und Shell-Auswahl.\n"
|
||||||
|
"Bsp: just build / just test / just --list / just deploy staging",
|
||||||
|
"just --help", "just"),
|
||||||
|
|
||||||
|
Tool("Produktiv", "direnv",
|
||||||
|
"Umgebungsvariablen automatisch pro Verzeichnis laden",
|
||||||
|
"Lädt automatisch Umgebungsvariablen aus einer .envrc Datei wenn man "
|
||||||
|
"in ein Verzeichnis wechselt — ideal für Projekt-spezifische API-Keys, "
|
||||||
|
"PATH-Erweiterungen und Konfigurationen.\n"
|
||||||
|
"Bsp: echo 'export API_KEY=xxx' > .envrc / direnv allow / direnv status",
|
||||||
|
"direnv status", "direnv"),
|
||||||
|
|
||||||
|
# ── Dokumente ────────────────────────────────────────────────────────────
|
||||||
|
Tool("Dokumente", "pandoc",
|
||||||
|
"Universeller Dokument-Konverter für über 40 Formate",
|
||||||
|
"Konvertiert zwischen Markdown, PDF, DOCX, HTML, EPUB, LaTeX und vielen "
|
||||||
|
"weiteren Formaten — unverzichtbar für technische Dokumentation.\n"
|
||||||
|
"Bsp: pandoc README.md -o out.pdf / pandoc in.docx -t markdown "
|
||||||
|
"/ pandoc slides.md -t beamer -o slides.pdf / pandoc -f html -t markdown url",
|
||||||
|
"pandoc --help", "pandoc"),
|
||||||
|
|
||||||
|
Tool("Dokumente", "pdfinfo",
|
||||||
|
"PDF-Metadaten auf einen Blick anzeigen",
|
||||||
|
"Zeigt Metadaten einer PDF-Datei: Seitenanzahl, Seitenformat, "
|
||||||
|
"Autor, Titel, Erstellungsdatum, PDF-Version und Verschlüsselungsstatus.\n"
|
||||||
|
"Bsp: pdfinfo dokument.pdf / pdfinfo -f 1 -l 5 dokument.pdf",
|
||||||
|
"pdfinfo", "pdfinfo", brew="poppler", apt="poppler-utils"),
|
||||||
|
|
||||||
|
Tool("Dokumente", "pdftotext",
|
||||||
|
"Text aus PDF-Dateien extrahieren",
|
||||||
|
"Extrahiert den Textinhalt aus PDFs — behält das Seitenlayout bei, "
|
||||||
|
"ideal für schnelle Textsuche oder Weiterverarbeitung.\n"
|
||||||
|
"Bsp: pdftotext doc.pdf - (→ stdout) / pdftotext -layout doc.pdf "
|
||||||
|
"/ pdftotext doc.pdf - | grep Suchwort / pdftotext -f 2 -l 5 doc.pdf",
|
||||||
|
"pdftotext", "pdftotext", brew="poppler", apt="poppler-utils"),
|
||||||
|
|
||||||
|
Tool("Dokumente", "qpdf",
|
||||||
|
"PDF zusammenführen, aufteilen und verschlüsseln",
|
||||||
|
"Manipuliert PDFs ohne Qualitätsverlust: Seiten zusammenführen, einzelne "
|
||||||
|
"Seiten extrahieren, verschlüsseln, entschlüsseln, linearisieren.\n"
|
||||||
|
"Bsp: qpdf --empty --pages a.pdf b.pdf -- out.pdf (zusammenführen) "
|
||||||
|
"/ qpdf --pages doc.pdf 1-3 -- out.pdf / qpdf --decrypt --password=pw in.pdf out.pdf",
|
||||||
|
"qpdf --help", "qpdf"),
|
||||||
|
|
||||||
|
Tool("Dokumente", "gs",
|
||||||
|
"Ghostscript: PDF komprimieren und reparieren",
|
||||||
|
"Verarbeitet und konvertiert PDFs und PostScript: Dateien komprimieren, "
|
||||||
|
"reparieren, Seiten extrahieren, in Bilder umwandeln.\n"
|
||||||
|
"Komprimieren: gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 "
|
||||||
|
"-dPDFSETTINGS=/ebook -sOutputFile=out.pdf in.pdf\n"
|
||||||
|
"/ebook ≈ 150dpi / /printer ≈ 300dpi / /prepress = maximale Qualität",
|
||||||
|
"gs --help", "gs", brew="ghostscript", apt="ghostscript"),
|
||||||
|
|
||||||
|
# ── Bilder ───────────────────────────────────────────────────────────────
|
||||||
|
Tool("Bilder", "heic2jpg",
|
||||||
|
"Alle HEIC im aktuellen Verzeichnis nach JPG konvertieren",
|
||||||
|
"Konvertiert alle *.heic/*.HEIC im aktuellen Verzeichnis nach JPG (Qualität 90%) "
|
||||||
|
"via heif-convert. Optional mit --resize auf max. 1920px verkleinern.\n"
|
||||||
|
"Varianten:\n"
|
||||||
|
" heic2jpg — nur konvertieren\n"
|
||||||
|
" heic2jpg --resize — konvertieren + auf 1920px verkleinern\n"
|
||||||
|
" heic2jpg_delete — konvertieren + HEIC-Originale löschen\n"
|
||||||
|
" heic2jpg_resize_delete — konvertieren + verkleinern + löschen\n"
|
||||||
|
"Tipp: h2j ist die modernere Version mit Flags (-r -d -rd)",
|
||||||
|
"heic2jpg", "heic2jpg"),
|
||||||
|
|
||||||
|
Tool("Bilder", "h2j",
|
||||||
|
"HEIC → JPG mit Flags für Resize und Löschen",
|
||||||
|
"Modernere All-in-One-Version der heic2jpg-Familie — konvertiert alle "
|
||||||
|
"*.heic/*.HEIC im aktuellen Verzeichnis mit konfigurierbaren Optionen.\n"
|
||||||
|
"Flags:\n"
|
||||||
|
" h2j — nur konvertieren (Qualität 90%)\n"
|
||||||
|
" h2j -r — + auf max. 1920px verkleinern\n"
|
||||||
|
" h2j -d — + HEIC-Originale löschen\n"
|
||||||
|
" h2j -rd — + verkleinern und löschen\n"
|
||||||
|
" h2j -h — Hilfe anzeigen",
|
||||||
|
"h2j -h", "h2j"),
|
||||||
|
|
||||||
|
Tool("Bilder", "convert",
|
||||||
|
"ImageMagick: Bilder konvertieren, skalieren und bearbeiten",
|
||||||
|
"Mächtiges Bildverarbeitungswerkzeug: Formate konvertieren, skalieren, "
|
||||||
|
"zuschneiden, drehen, Helligkeit/Kontrast anpassen, Wasserzeichen hinzufügen.\n"
|
||||||
|
"Bsp: convert in.png -resize 50% out.jpg / convert -quality 85 in.png out.jpg "
|
||||||
|
"/ convert in.jpg -rotate 90 out.jpg / convert *.jpg -delay 50 animation.gif",
|
||||||
|
"convert --help", "convert", brew="imagemagick", apt="imagemagick"),
|
||||||
|
|
||||||
|
Tool("Bilder", "exiftool",
|
||||||
|
"EXIF-Metadaten lesen, bearbeiten und entfernen",
|
||||||
|
"Liest und bearbeitet Metadaten in Foto-, Video- und Audiodateien: "
|
||||||
|
"GPS-Koordinaten, Kameramodell, Aufnahmedatum, Copyright, Belichtung.\n"
|
||||||
|
"Bsp: exiftool foto.jpg / exiftool -GPS* foto.jpg (nur GPS) "
|
||||||
|
"/ exiftool -all= foto.jpg (alle Metadaten entfernen) "
|
||||||
|
"/ exiftool '-DateTimeOriginal+=1:0:0' *.jpg (Datum korrigieren)",
|
||||||
|
"exiftool", "exiftool", brew="exiftool", apt="libimage-exiftool-perl"),
|
||||||
|
|
||||||
|
Tool("Bilder", "ffmpeg",
|
||||||
|
"Video und Audio konvertieren, schneiden, komprimieren",
|
||||||
|
"Das Schweizer Taschenmesser für Medien: praktisch jedes Video- und "
|
||||||
|
"Audioformat konvertieren, schneiden, komprimieren, GIFs erstellen.\n"
|
||||||
|
"Bsp: ffmpeg -i in.mp4 out.gif / ffmpeg -i in.mov -crf 28 out.mp4 "
|
||||||
|
"/ ffmpeg -i in.mp4 -ss 00:01:00 -t 30 clip.mp4 (schneiden) "
|
||||||
|
"/ ffmpeg -i in.mp4 -vn -acodec mp3 audio.mp3 (nur Audio)",
|
||||||
|
"ffmpeg -version", "ffmpeg"),
|
||||||
|
|
||||||
|
Tool("Bilder", "img2pdf",
|
||||||
|
"Bilder verlustfrei zu einer PDF-Datei zusammenführen",
|
||||||
|
"Kombiniert mehrere Bilder zu einer PDF-Datei ohne Qualitätsverlust — "
|
||||||
|
"im Gegensatz zu convert/ImageMagick wird das Bild nicht re-enkodiert.\n"
|
||||||
|
"Bsp: img2pdf *.jpg -o out.pdf / img2pdf scan1.png scan2.png -o book.pdf "
|
||||||
|
"/ img2pdf --pagesize A4 *.jpg -o out.pdf",
|
||||||
|
"img2pdf --help", "img2pdf"),
|
||||||
|
|
||||||
|
# ── KI ───────────────────────────────────────────────────────────────────
|
||||||
|
Tool("KI", "ki-chat",
|
||||||
|
"Offline-KI: interaktiver Chat",
|
||||||
|
"Startet einen interaktiven Chat mit dem lokalen KI-Modell — "
|
||||||
|
"läuft vollständig offline ohne Cloud-Anbindung.",
|
||||||
|
"ki interactive", "ki"),
|
||||||
|
|
||||||
|
Tool("KI", "ki-agent",
|
||||||
|
"Offline-KI Agent-Modus mit Datei- und Shell-Zugriff",
|
||||||
|
"KI im Agent-Modus: kann Dateien lesen/schreiben und Shell-Befehle "
|
||||||
|
"ausführen — für komplexere Aufgaben mit Systemzugriff.",
|
||||||
|
"ki interactive --agent-mode", "ki"),
|
||||||
|
|
||||||
|
Tool("KI", "ki-commit",
|
||||||
|
"Commit-Message mit KI generieren",
|
||||||
|
"Analysiert den aktuellen Git-Diff und schlägt eine passende "
|
||||||
|
"Commit-Message vor — spart Zeit bei aussagekräftigen Commits.",
|
||||||
|
"ki commit", "ki"),
|
||||||
|
|
||||||
|
Tool("KI", "ki-diff",
|
||||||
|
"Git-Diff mit KI erklären lassen",
|
||||||
|
"Übergibt den aktuellen Git-Diff an die KI und erhält eine "
|
||||||
|
"verständliche Erklärung der Änderungen.",
|
||||||
|
"ki diff", "ki"),
|
||||||
|
|
||||||
|
# ── Spass ────────────────────────────────────────────────────────────────
|
||||||
|
Tool("Spass", "cmatrix",
|
||||||
|
"Matrix-Digital-Regen im Terminal",
|
||||||
|
"Klassischer grüner Matrix-Regen — Geschwindigkeit und Farbe einstellbar.\n"
|
||||||
|
"Steuerung: q beenden / a/A Geschwindigkeit / b/B Helligkeit",
|
||||||
|
"cmatrix -sab", "cmatrix"),
|
||||||
|
|
||||||
|
Tool("Spass", "asciiquarium",
|
||||||
|
"Animiertes Aquarium mit Fischen und Haien",
|
||||||
|
"Ein buntes ASCII-Aquarium mit schwimmenden Fischen, Haien, Blasen "
|
||||||
|
"und gelegentlichen Überraschungsgästen — entspannender Bildschirmschoner.\n"
|
||||||
|
"Steuerung: q beenden",
|
||||||
|
"asciiquarium", "asciiquarium"),
|
||||||
|
|
||||||
|
Tool("Spass", "pipes.sh",
|
||||||
|
"Animierte Rohre als Bildschirmschoner",
|
||||||
|
"Zeichnet zufällig wachsende Rohre in verschiedenen Farben und Stilen — "
|
||||||
|
"hypnotisierender Terminal-Bildschirmschoner.\n"
|
||||||
|
"Steuerung: q beenden / Parameter: -t Stil (0-8) / -p Anzahl Rohre",
|
||||||
|
"pipes.sh -t 0 -p 4", "pipes.sh"),
|
||||||
|
|
||||||
|
Tool("Spass", "cbonsai",
|
||||||
|
"Wachsender ASCII-Bonsai-Baum",
|
||||||
|
"Lässt einen Bonsai-Baum mit zufälliger Struktur wachsen — jedes Mal "
|
||||||
|
"ein anderes Ergebnis. Mit -l läuft die Animation bis q gedrückt wird.\n"
|
||||||
|
"Bsp: cbonsai -l (Live) / cbonsai -p (sofort fertig) / cbonsai -S 42 (seed)",
|
||||||
|
"cbonsai -l", "cbonsai"),
|
||||||
|
|
||||||
|
Tool("Spass", "nms",
|
||||||
|
"Sneakers-Entschlüsselungsanimation",
|
||||||
|
"Simuliert den Entschlüsselungseffekt aus dem Film 'Sneakers' (1992): "
|
||||||
|
"Text erscheint zuerst als zufällige Zeichen und enthüllt sich dann.\n"
|
||||||
|
"Bsp: ls -la | nms / cat secret.txt | nms / echo 'Hello World' | nms -a",
|
||||||
|
"ls -la | nms", "nms"),
|
||||||
|
|
||||||
|
Tool("Spass", "lolcat",
|
||||||
|
"Regenbogenfarben für beliebige Terminal-Ausgabe",
|
||||||
|
"Gibt jede Ausgabe in animierten Regenbogenfarben aus — als Pipe verwendbar.\n"
|
||||||
|
"Bsp: ls -la | lolcat / fortune | lolcat / echo 'Hello' | lolcat -a "
|
||||||
|
"/ cat /etc/passwd | lolcat",
|
||||||
|
"ls -la | lolcat", "lolcat"),
|
||||||
|
|
||||||
|
Tool("Spass", "fortune|cowsay",
|
||||||
|
"Weiser Spruch vom Kuh-Orakel",
|
||||||
|
"Zufälliger weiser (oder alberner) Spruch, vorgetragen von einer ASCII-Kuh — "
|
||||||
|
"Terminal-Klassiker seit den 90ern. Häufig in .bashrc/.zshrc zu finden.\n"
|
||||||
|
"Bsp: fortune | cowsay / fortune | cowsay -f tux (Pinguin) "
|
||||||
|
"/ fortune | cowsay | lolcat (bunt)",
|
||||||
|
"fortune | cowsay", "fortune",
|
||||||
|
brew="fortune cowsay", apt="fortune-mod cowsay"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -100,6 +628,24 @@ def is_available(tool: Tool) -> bool:
|
||||||
return shutil.which(binary) is not None
|
return shutil.which(binary) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def get_install_cmd(tool: Tool) -> str:
|
||||||
|
if IS_MAC:
|
||||||
|
pkg = tool.brew or tool.binary
|
||||||
|
return f"brew install {pkg}"
|
||||||
|
else:
|
||||||
|
pkg = tool.apt or tool.binary
|
||||||
|
return f"sudo apt install {pkg}"
|
||||||
|
|
||||||
|
|
||||||
|
def get_uninstall_cmd(tool: Tool) -> str:
|
||||||
|
if IS_MAC:
|
||||||
|
pkg = tool.brew or tool.binary
|
||||||
|
return f"brew uninstall {pkg}"
|
||||||
|
else:
|
||||||
|
pkg = tool.apt or tool.binary
|
||||||
|
return f"sudo apt remove {pkg}"
|
||||||
|
|
||||||
|
|
||||||
def resolve_command(cmd: str) -> str:
|
def resolve_command(cmd: str) -> str:
|
||||||
if IS_LINUX:
|
if IS_LINUX:
|
||||||
for mac_bin, linux_bin in LINUX_ALIASES.items():
|
for mac_bin, linux_bin in LINUX_ALIASES.items():
|
||||||
|
|
@ -108,22 +654,29 @@ def resolve_command(cmd: str) -> str:
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
def open_new_window(command: str) -> None:
|
def open_new_tab(command: str) -> None:
|
||||||
"""Öffnet den Befehl in einem neuen Fenster im aktuellen Verzeichnis."""
|
"""Öffnet den Befehl in einem neuen Tab im aktuellen Verzeichnis."""
|
||||||
full_cmd = f"cd {shlex.quote(CURRENT_DIR)} && {command}"
|
full_cmd = f"cd {shlex.quote(CURRENT_DIR)} && {command}"
|
||||||
|
|
||||||
if IS_MAC:
|
if IS_MAC:
|
||||||
|
import tempfile
|
||||||
escaped = full_cmd.replace("\\", "\\\\").replace('"', '\\"')
|
escaped = full_cmd.replace("\\", "\\\\").replace('"', '\\"')
|
||||||
script = (
|
script = (
|
||||||
'tell application "iTerm2"\n'
|
'tell application "iTerm2"\n'
|
||||||
' activate\n'
|
' activate\n'
|
||||||
' set w to (create window with current profile)\n'
|
' tell front window\n'
|
||||||
' tell current session of w\n'
|
' create tab with default profile\n'
|
||||||
|
' end tell\n'
|
||||||
|
' tell current session of front window\n'
|
||||||
f' write text "{escaped}"\n'
|
f' write text "{escaped}"\n'
|
||||||
' end tell\n'
|
' end tell\n'
|
||||||
'end tell\n'
|
'end tell\n'
|
||||||
)
|
)
|
||||||
subprocess.run(["osascript", "-e", script], capture_output=True)
|
with tempfile.NamedTemporaryFile(suffix=".scpt", mode="w", delete=False) as f:
|
||||||
|
f.write(script)
|
||||||
|
tmp = f.name
|
||||||
|
subprocess.run(["osascript", tmp], capture_output=True)
|
||||||
|
os.unlink(tmp)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Linux: Terminal-Emulator nach Verfügbarkeit
|
# Linux: Terminal-Emulator nach Verfügbarkeit
|
||||||
|
|
@ -131,12 +684,12 @@ def open_new_window(command: str) -> None:
|
||||||
candidates = [
|
candidates = [
|
||||||
("xfce4-terminal", ["xfce4-terminal",
|
("xfce4-terminal", ["xfce4-terminal",
|
||||||
f"--working-directory={CURRENT_DIR}",
|
f"--working-directory={CURRENT_DIR}",
|
||||||
"-e", f"bash -c {shlex.quote(bash_cmd)}"]),
|
"--tab", "-e", f"bash -c {shlex.quote(bash_cmd)}"]),
|
||||||
("gnome-terminal", ["gnome-terminal",
|
("gnome-terminal", ["gnome-terminal",
|
||||||
f"--working-directory={CURRENT_DIR}",
|
f"--working-directory={CURRENT_DIR}",
|
||||||
"--", "bash", "-c", bash_cmd]),
|
"--tab", "--", "bash", "-c", bash_cmd]),
|
||||||
("kitty", ["kitty", "--directory", CURRENT_DIR,
|
("kitty", ["kitty", "--directory", CURRENT_DIR,
|
||||||
"bash", "-c", bash_cmd]),
|
"--new-tab", "bash", "-c", bash_cmd]),
|
||||||
("alacritty", ["alacritty", "--working-directory", CURRENT_DIR,
|
("alacritty", ["alacritty", "--working-directory", CURRENT_DIR,
|
||||||
"-e", "bash", "-c", bash_cmd]),
|
"-e", "bash", "-c", bash_cmd]),
|
||||||
("xterm", ["xterm", "-e",
|
("xterm", ["xterm", "-e",
|
||||||
|
|
@ -150,7 +703,74 @@ def open_new_window(command: str) -> None:
|
||||||
os.system(full_cmd) # Fallback: inline
|
os.system(full_cmd) # Fallback: inline
|
||||||
|
|
||||||
|
|
||||||
|
def load_custom_tools() -> list[Tool]:
|
||||||
|
if not os.path.exists(CUSTOM_TOOLS_FILE):
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
with open(CUSTOM_TOOLS_FILE) as f:
|
||||||
|
return [Tool(**entry) for entry in json.load(f)]
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def save_custom_tool(tool: Tool) -> None:
|
||||||
|
os.makedirs(os.path.dirname(CUSTOM_TOOLS_FILE), exist_ok=True)
|
||||||
|
existing: list = []
|
||||||
|
if os.path.exists(CUSTOM_TOOLS_FILE):
|
||||||
|
try:
|
||||||
|
with open(CUSTOM_TOOLS_FILE) as f:
|
||||||
|
existing = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
existing.append({
|
||||||
|
"category": tool.category, "name": tool.name,
|
||||||
|
"description": tool.description, "details": tool.details,
|
||||||
|
"command": tool.command, "binary": tool.binary,
|
||||||
|
"mac": tool.mac, "linux": tool.linux,
|
||||||
|
"brew": tool.brew, "apt": tool.apt,
|
||||||
|
})
|
||||||
|
with open(CUSTOM_TOOLS_FILE, "w") as f:
|
||||||
|
json.dump(existing, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
def add_tool_interactive(existing_categories: list[str]) -> Tool | None:
|
||||||
|
"""Fragt interaktiv nach Tool-Daten und gibt ein neues Tool zurück."""
|
||||||
|
print("\n ── Neues Tool hinzufügen ──────────────────────────────────────\n")
|
||||||
|
print(" Bestehende Kategorien: " + ", ".join(existing_categories) + "\n")
|
||||||
|
|
||||||
|
def ask(prompt: str, default: str = "") -> str | None:
|
||||||
|
hint = f" [{default}]" if default else ""
|
||||||
|
try:
|
||||||
|
val = input(f" {prompt}{hint}: ").strip()
|
||||||
|
return val if val else (default if default else None)
|
||||||
|
except (EOFError, KeyboardInterrupt):
|
||||||
|
return None
|
||||||
|
|
||||||
|
category = ask("Kategorie (bestehend oder neu)")
|
||||||
|
if not category: return None
|
||||||
|
name = ask("Name")
|
||||||
|
if not name: return None
|
||||||
|
description = ask("Kurzbeschreibung (für Listenansicht)")
|
||||||
|
if not description: return None
|
||||||
|
details_raw = ask("Details + Beispiele (\\n für Zeilenumbruch)", "")
|
||||||
|
if details_raw is None: return None
|
||||||
|
details = details_raw.replace("\\n", "\n")
|
||||||
|
command = ask("Befehl")
|
||||||
|
if not command: return None
|
||||||
|
binary = ask("Binary (für Verfügbarkeitscheck)", command.split()[0])
|
||||||
|
if not binary: return None
|
||||||
|
brew = ask("brew-Paketname (leer = wie binary)", "") or ""
|
||||||
|
apt_pkg = ask("apt-Paketname (leer = wie binary)", "") or ""
|
||||||
|
|
||||||
|
return Tool(
|
||||||
|
category=category, name=name, description=description,
|
||||||
|
details=details, command=command, binary=binary,
|
||||||
|
brew=brew, apt=apt_pkg,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def fzf_run(items: list[str], extra_args: list[str]) -> str | None:
|
def fzf_run(items: list[str], extra_args: list[str]) -> str | None:
|
||||||
|
"""Einfacher fzf-Aufruf, gibt die gewählte Zeile zurück."""
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
_FZF_BASE + extra_args,
|
_FZF_BASE + extra_args,
|
||||||
input="\n".join(items),
|
input="\n".join(items),
|
||||||
|
|
@ -160,6 +780,23 @@ def fzf_run(items: list[str], extra_args: list[str]) -> str | None:
|
||||||
return result.stdout.strip() if result.returncode == 0 and result.stdout.strip() else None
|
return result.stdout.strip() if result.returncode == 0 and result.stdout.strip() else None
|
||||||
|
|
||||||
|
|
||||||
|
def fzf_run_keyed(items: list[str], extra_args: list[str],
|
||||||
|
expect: str) -> tuple[str, str | None]:
|
||||||
|
"""fzf-Aufruf mit --expect. Gibt (taste, zeile) zurück; taste='' für Enter."""
|
||||||
|
result = subprocess.run(
|
||||||
|
_FZF_BASE + [f"--expect={expect}"] + extra_args,
|
||||||
|
input="\n".join(items),
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
if result.returncode != 0 or not result.stdout.strip():
|
||||||
|
return ("", None)
|
||||||
|
lines = result.stdout.split("\n", 1)
|
||||||
|
key = lines[0].strip()
|
||||||
|
item = lines[1].strip() if len(lines) > 1 and lines[1].strip() else None
|
||||||
|
return (key, item)
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
if not shutil.which("fzf"):
|
if not shutil.which("fzf"):
|
||||||
print("fzf nicht gefunden – bitte installieren:")
|
print("fzf nicht gefunden – bitte installieren:")
|
||||||
|
|
@ -167,24 +804,24 @@ def main() -> None:
|
||||||
print(" Linux: sudo apt install fzf")
|
print(" Linux: sudo apt install fzf")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
available = [t for t in TOOLS if is_available(t)]
|
# Benutzerdefinierte Tools aus JSON laden und anhängen
|
||||||
categories = list(dict.fromkeys(t.category for t in available))
|
TOOLS.extend(load_custom_tools())
|
||||||
ALL = "★ Alle Tools"
|
|
||||||
|
|
||||||
# Kategorie-Vorschau: Anzahl verfügbarer Tools pro Kategorie
|
|
||||||
cat_counts = {c: sum(1 for t in available if t.category == c) for c in categories}
|
|
||||||
cat_items = [f"{ALL} ({len(available)})"] + [
|
|
||||||
f"{c} ({cat_counts[c]})" for c in categories
|
|
||||||
]
|
|
||||||
|
|
||||||
# Preview für Kategorien: Tools der markierten Kategorie anzeigen
|
|
||||||
# {1} = Kategoriename (erstes Wort), fzf-Feldreferenz
|
|
||||||
cat_preview = (
|
|
||||||
"cat << 'CATEOF'\n" # Dummy — wir nutzen awk auf die Eingabeliste
|
|
||||||
)
|
|
||||||
# Einfacherer Ansatz: kein Preview auf Kategorie-Ebene, nur auf Tool-Ebene
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
# Bei jedem Schleifendurchlauf neu berechnen (damit neue Tools sofort erscheinen)
|
||||||
|
platform_tools = [t for t in TOOLS if (IS_MAC and t.mac) or (IS_LINUX and t.linux)]
|
||||||
|
categories = list(dict.fromkeys(t.category for t in platform_tools))
|
||||||
|
ALL = "★ Alle Tools"
|
||||||
|
|
||||||
|
total_installed = sum(1 for t in platform_tools if is_available(t))
|
||||||
|
cat_total = {c: sum(1 for t in platform_tools if t.category == c) for c in categories}
|
||||||
|
cat_installed = {c: sum(1 for t in platform_tools if t.category == c and is_available(t))
|
||||||
|
for c in categories}
|
||||||
|
|
||||||
|
cat_items = [f"{ALL} ({total_installed}/{len(platform_tools)})"] + [
|
||||||
|
f"{c} ({cat_installed[c]}/{cat_total[c]})" for c in categories
|
||||||
|
]
|
||||||
|
|
||||||
# ── Schritt 1: Kategorie wählen ──────────────────────────────────────
|
# ── Schritt 1: Kategorie wählen ──────────────────────────────────────
|
||||||
cat_choice = fzf_run(
|
cat_choice = fzf_run(
|
||||||
cat_items,
|
cat_items,
|
||||||
|
|
@ -197,44 +834,115 @@ def main() -> None:
|
||||||
if not cat_choice:
|
if not cat_choice:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if cat_choice.startswith(ALL[:3]): # "★ Alle …"
|
if cat_choice.startswith(ALL[:3]):
|
||||||
filtered, cat_label = available, "Alle Tools"
|
filtered, cat_label = platform_tools, "Alle Tools"
|
||||||
else:
|
else:
|
||||||
cat_label = cat_choice.split(" (")[0] # Name ohne "(N)"
|
cat_label = cat_choice.split(" (")[0]
|
||||||
filtered = [t for t in available if t.category == cat_label]
|
filtered = [t for t in platform_tools if t.category == cat_label]
|
||||||
|
|
||||||
# ── Schritt 2: Tool wählen ───────────────────────────────────────────
|
# ── Schritt 2: Tool wählen ───────────────────────────────────────────
|
||||||
# Felder TAB-getrennt: name \t description \t command
|
DIM = "\033[2m"
|
||||||
tool_lines = [f"{t.name}\t{t.description}\t{t.command}" for t in filtered]
|
YEL = "\033[33m"
|
||||||
|
RST = "\033[0m"
|
||||||
|
BADGE = f" {YEL}[nicht installiert]{RST}"
|
||||||
|
|
||||||
# Preview zeigt Beschreibung + Befehl für das markierte Tool.
|
tool_lines = []
|
||||||
# {2} und {3} sind fzf-Feldreferenzen (TAB-Delimiter), werden von fzf
|
for i, t in enumerate(filtered):
|
||||||
# korrekt gequotet, bevor sie in den Shell-Befehl eingefügt werden.
|
avail = is_available(t)
|
||||||
preview = r"printf '\n \033[1m%s\033[0m\n\n \033[33m$\033[0m %s\n' {2} {3}"
|
if avail:
|
||||||
|
name_col = t.name
|
||||||
|
desc_col = t.description
|
||||||
|
raw_preview = f"$ {t.command}"
|
||||||
|
else:
|
||||||
|
name_col = f"{DIM}{t.name}{RST}"
|
||||||
|
desc_col = f"{DIM}{t.description}{RST}{BADGE}"
|
||||||
|
raw_preview = f"⚠ {get_install_cmd(t)}"
|
||||||
|
|
||||||
chosen = fzf_run(
|
# Felder: display_name | display_desc | raw_name | raw_preview | idx:status | details
|
||||||
|
line = (f"{name_col}\t{desc_col}\t{t.name}\t{raw_preview}"
|
||||||
|
f"\t{i}:{'avail' if avail else 'missing'}\t{t.details}")
|
||||||
|
tool_lines.append(line)
|
||||||
|
|
||||||
|
# Preview: Name (bold) + Details + Befehl/Install (gelb)
|
||||||
|
preview = (
|
||||||
|
r"printf '\n \033[1m%s\033[0m\n\n%s\n\n \033[33m%s\033[0m\n' "
|
||||||
|
r"'{3}' '{6}' '{4}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
key, chosen = fzf_run_keyed(
|
||||||
tool_lines,
|
tool_lines,
|
||||||
[
|
[
|
||||||
f"--prompt= {cat_label} > ",
|
f"--prompt= {cat_label} > ",
|
||||||
f"--header= ‹ {cat_label} (Esc = zurück zur Kategorie)",
|
(f"--header= ‹ {cat_label}"
|
||||||
|
" · Enter=Starten Ctrl-X=Deinstallieren Ctrl-N=Neu Esc=zurück"),
|
||||||
"--delimiter=\t",
|
"--delimiter=\t",
|
||||||
"--with-nth=1,2",
|
"--with-nth=1,2",
|
||||||
f"--preview={preview}",
|
f"--preview={preview}",
|
||||||
"--preview-window=bottom:5:wrap",
|
"--preview-window=right:45%:wrap",
|
||||||
],
|
],
|
||||||
|
expect="ctrl-x,ctrl-n",
|
||||||
)
|
)
|
||||||
|
|
||||||
if not chosen:
|
# ── Ctrl-N: Neues Tool hinzufügen ────────────────────────────────────
|
||||||
|
if key == "ctrl-n":
|
||||||
|
cats = list(dict.fromkeys(t.category for t in TOOLS))
|
||||||
|
new_tool = add_tool_interactive(cats)
|
||||||
|
if new_tool:
|
||||||
|
save_custom_tool(new_tool)
|
||||||
|
TOOLS.append(new_tool)
|
||||||
|
print(f"\n ✓ '{new_tool.name}' wurde gespeichert in {CUSTOM_TOOLS_FILE}\n")
|
||||||
|
try:
|
||||||
|
input(" Enter drücken zum Fortfahren…")
|
||||||
|
except (EOFError, KeyboardInterrupt):
|
||||||
|
pass
|
||||||
|
continue
|
||||||
|
|
||||||
|
if chosen is None:
|
||||||
continue # Esc → zurück zur Kategorie-Auswahl
|
continue # Esc → zurück zur Kategorie-Auswahl
|
||||||
|
|
||||||
parts = chosen.split("\t")
|
parts = chosen.split("\t")
|
||||||
if len(parts) < 3:
|
if len(parts) < 5:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
tool_name, _, tool_cmd = parts[0], parts[1], parts[2]
|
idx, status = parts[4].split(":", 1)
|
||||||
command = resolve_command(tool_cmd)
|
t = filtered[int(idx)]
|
||||||
print(f"\n▶ {tool_name} — {command}\n")
|
avail = (status == "avail")
|
||||||
open_new_window(command)
|
|
||||||
|
# ── Ctrl-X: Deinstallieren ────────────────────────────────────────────
|
||||||
|
if key == "ctrl-x":
|
||||||
|
if not avail:
|
||||||
|
print(f"\n {t.name} ist nicht installiert.\n")
|
||||||
|
else:
|
||||||
|
uninstall_cmd = get_uninstall_cmd(t)
|
||||||
|
print(f"\n {t.name} deinstallieren mit: {uninstall_cmd}\n")
|
||||||
|
try:
|
||||||
|
ans = input(" Wirklich deinstallieren? [j/N] ").strip().lower()
|
||||||
|
except (EOFError, KeyboardInterrupt):
|
||||||
|
print()
|
||||||
|
sys.exit(0)
|
||||||
|
if ans == "j":
|
||||||
|
print()
|
||||||
|
os.system(uninstall_cmd)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# ── Enter: Starten oder Installieren ────────────────────────────────
|
||||||
|
if avail:
|
||||||
|
command = resolve_command(t.command)
|
||||||
|
print(f"\n▶ {t.name} — {command}\n")
|
||||||
|
open_new_tab(command)
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
install_cmd = get_install_cmd(t)
|
||||||
|
print(f"\n ⚠ {t.name} ist nicht installiert.")
|
||||||
|
print(f" Installieren mit: {install_cmd}\n")
|
||||||
|
try:
|
||||||
|
ans = input(" Jetzt installieren? [j/N] ").strip().lower()
|
||||||
|
except (EOFError, KeyboardInterrupt):
|
||||||
|
print()
|
||||||
|
sys.exit(0)
|
||||||
|
if ans == "j":
|
||||||
|
print()
|
||||||
|
os.system(install_cmd)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue