import app from "ags/gtk4/app"; import { Astal, Gtk } from "ags/gtk4"; import { execAsync } from "ags/process"; import css from "./package-manager.css"; const WINDOW_MARGIN_TOP = 48; const ESC_KEYVAL = 65307; type Helper = "pacman" | "paru"; type PackageResult = { repo: string; name: string; version: string; installed: boolean; description: string; }; let helper: Helper = "paru"; let query = ""; let results: PackageResult[] = []; let busy = false; let statusMessage = "Suchbegriff eingeben und Enter druecken."; let errorMessage = ""; function shQuote(value: string) { return `'${value.replace(/'/g, `'\\''`)}'`; } function notify(message: string) { execAsync(["notify-send", "Pakete", message]).catch(console.error); } function runShell(command: string) { return execAsync(["bash", "-lc", command]); } function setBusy(value: boolean) { busy = value; rebuild(); } function helperAvailable(nextHelper: Helper) { return runShell(`command -v ${nextHelper} >/dev/null 2>&1`); } function parseSearch(output: string) { const parsed: PackageResult[] = []; const lines = output.split("\n"); for (let index = 0; index < lines.length; index += 1) { const header = lines[index]; const match = header.match(/^([^/\s]+)\/([^\s]+)\s+([^\s]+)(?:\s+\[(installed[^\]]*)\])?/); if (!match) { continue; } const descriptionLines: string[] = []; let next = index + 1; while (next < lines.length && /^\s+/.test(lines[next])) { descriptionLines.push(lines[next].trim()); next += 1; } parsed.push({ repo: match[1], name: match[2], version: match[3], installed: Boolean(match[4]), description: descriptionLines.join(" ") || "Keine Beschreibung.", }); index = next - 1; } return parsed.slice(0, 80); } function searchPackages() { const term = query.trim(); if (!term) { results = []; statusMessage = "Suchbegriff fehlt."; rebuild(); return; } setBusy(true); errorMessage = ""; statusMessage = `Suche mit ${helper} nach "${term}"...`; helperAvailable(helper) .then(() => runShell(`${helper} -Ss ${shQuote(term)} 2>/dev/null || true`)) .then(output => { results = parseSearch(output); statusMessage = results.length ? `${results.length} Treffer fuer "${term}" mit ${helper}.` : `Keine Treffer fuer "${term}".`; }) .catch(error => { console.error(error); results = []; errorMessage = `${helper} ist nicht verfuegbar oder die Suche ist fehlgeschlagen.`; statusMessage = "Suche fehlgeschlagen."; }) .finally(() => { setBusy(false); }); } function terminalCommand(command: string) { const hold = `${command}; printf '\\n'; read -r -p 'Enter zum Schliessen... ' _`; return `kitty --title ${shQuote("Paketmanager")} sh -lc ${shQuote(hold)} || alacritty -e sh -lc ${shQuote(hold)} || foot sh -lc ${shQuote(hold)} || xterm -e sh -lc ${shQuote(hold)}`; } function installPackage(pkg: PackageResult) { const command = helper === "pacman" ? `sudo pacman -S ${shQuote(pkg.name)}` : `paru -S ${shQuote(pkg.name)}`; notify(`Installation gestartet: ${pkg.name}`); runShell(terminalCommand(command)).catch(error => { console.error(error); notify("Kein Terminal fuer Paketinstallation gefunden."); }); } function updateSystem() { const command = helper === "pacman" ? "sudo pacman -Syu" : "paru -Syu"; notify(`Update gestartet mit ${helper}.`); runShell(terminalCommand(command)).catch(error => { console.error(error); notify("Kein Terminal fuer Updates gefunden."); }); } function HelperButton({ id, label }: { id: Helper; label: string }) { return ( { query = entry.get_text(); }} onActivate={entry => { query = entry.get_text(); searchPackages(); }} /> { query = entry.get_text(); }} onActivate={entry => { query = entry.get_text(); searchPackages(); }} />