Port desktop integration to Omarchy 4 (Quickshell/Lua)
The backup engine was unaffected, but every piece of desktop integration was written against Omarchy 3 and had gone silently dead on Omarchy 4. - Keybinding: Hyprland 0.56 uses the Lua config provider, so ~/.config/hypr/ *.conf is never read. Detect the flavour and write bindings.lua / autostart.lua (o.window, o.bind, o.launch_on_start) or the old .conf syntax, and strip our stale .conf block on upgraded machines. - Match the window by app-id TUI.redpill rather than the title "RED PILL": an unspaced id survives a Lua string, a Hyprland exec and a .desktop Exec without quoting bugs. - Live-apply via hyprctl reload on Lua; `hyprctl keyword` is rejected by the non-legacy parser. - Terminal: resolve through xdg-terminal-exec instead of hardcoding alacritty, which is no longer an Omarchy dependency. - Theme: record the active theme in backup.log (and a .theme sidecar for local tarballs). Omarchy 4 keeps it in ~/.local/state/omarchy, which the default excludes skip, so restores were silently losing the theme. - Gate the Walker blocks on Walker actually being installed. - Uninstaller cleans both the .lua and .conf layouts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
12b792144a
commit
0a2cb6aee8
3 changed files with 355 additions and 162 deletions
22
README.md
22
README.md
|
|
@ -18,15 +18,17 @@ A unified backup and restore system for [Omarchy](https://omarchy.com). Backs up
|
||||||
- **Backup verification**: checksum manifests (xxh128 or sha256) with integrity checking
|
- **Backup verification**: checksum manifests (xxh128 or sha256) with integrity checking
|
||||||
- **New machine restore**: standalone `restore.sh` written to the backup drive - works without Red Pill installed
|
- **New machine restore**: standalone `restore.sh` written to the backup drive - works without Red Pill installed
|
||||||
- **Username migration**: automatically fixes paths when restoring to a different username/home directory
|
- **Username migration**: automatically fixes paths when restoring to a different username/home directory
|
||||||
- **Theme restoration**: reapplies Omarchy theme after restore
|
- **Theme restoration**: records the active Omarchy theme in the snapshot and reapplies it after restore
|
||||||
- **Login notifications**: reminds you if no backup in 7+ days
|
- **Login notifications**: reminds you if no backup in 7+ days
|
||||||
- **Walker integration**: searchable from the Omarchy launcher
|
- **Launcher integration**: searchable from the Omarchy launcher (`Super+Space`)
|
||||||
- **Hyprland keybind**: `Super+Alt+B` opens a floating TUI window
|
- **Hyprland keybind**: `Super+Alt+B` opens a floating TUI window
|
||||||
|
- **Omarchy 3 and 4**: detects the Lua config (Omarchy 4 / Quickshell) or the older `.conf` layout and writes whichever the machine actually reads
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- **OS**: [Omarchy](https://omarchy.com) (Arch Linux)
|
- **OS**: [Omarchy](https://omarchy.com) 3 or 4 (Arch Linux)
|
||||||
- **Dependencies**: `rsync`, `libnewt` (whiptail), `zstd`, `alacritty`, `desktop-file-utils` (all ship with Omarchy)
|
- **Dependencies**: `rsync`, `libnewt` (whiptail), `zstd`, `desktop-file-utils` (all ship with Omarchy)
|
||||||
|
- **Terminal**: whichever one you use — the TUI is launched through `xdg-terminal-exec`, falling back to ghostty/kitty/alacritty/foot
|
||||||
- **Backup destination**: any external drive (ext4, NTFS, btrfs, exFAT, etc.)
|
- **Backup destination**: any external drive (ext4, NTFS, btrfs, exFAT, etc.)
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
@ -114,9 +116,11 @@ Shows the Matrix quote, then restores from the latest snapshot on your external
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| `~/.local/share/applications/redpill.desktop` | User application menu entry |
|
| `~/.local/share/applications/redpill.desktop` | User application menu entry |
|
||||||
| `/usr/share/applications/redpill.desktop` | System application menu entry |
|
| `/usr/share/applications/redpill.desktop` | System application menu entry |
|
||||||
| `~/.config/walker/config.toml` | Walker launcher custom command entry |
|
| `~/.config/hypr/bindings.lua` | Hyprland keybind (`Super+Alt+B`) + window rules — Omarchy 4 |
|
||||||
| `~/.config/hypr/bindings.conf` | Hyprland keybind (`Super+Alt+B`) + window rules |
|
| `~/.config/hypr/autostart.lua` | Login notification autostart — Omarchy 4 |
|
||||||
| `~/.config/hypr/autostart.conf` | Login notification autostart |
|
| `~/.config/hypr/bindings.conf` | Keybind + window rules — Omarchy 3 |
|
||||||
|
| `~/.config/hypr/autostart.conf` | Login notification autostart — Omarchy 3 |
|
||||||
|
| `~/.config/walker/config.toml` | Walker custom command entry — Omarchy 3 only |
|
||||||
|
|
||||||
### Systemd Service
|
### Systemd Service
|
||||||
|
|
||||||
|
|
@ -228,9 +232,9 @@ bash Redpill_uninstall.sh
|
||||||
The uninstaller removes:
|
The uninstaller removes:
|
||||||
- All binaries from `/usr/local/bin/`
|
- All binaries from `/usr/local/bin/`
|
||||||
- Desktop entries (user + system)
|
- Desktop entries (user + system)
|
||||||
- Hyprland keybinding and window rules
|
- Hyprland keybinding and window rules (`.lua` and `.conf` layouts)
|
||||||
- Hyprland autostart entry
|
- Hyprland autostart entry
|
||||||
- Walker custom command entry
|
- Walker custom command entry (Omarchy 3)
|
||||||
- Systemd auto-backup service
|
- Systemd auto-backup service
|
||||||
- Optionally: config and state directories
|
- Optionally: config and state directories
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,37 +97,55 @@ fi
|
||||||
update-desktop-database "$HOME/.local/share/applications" >/dev/null 2>&1 || true
|
update-desktop-database "$HOME/.local/share/applications" >/dev/null 2>&1 || true
|
||||||
sudo update-desktop-database /usr/share/applications >/dev/null 2>&1 || true
|
sudo update-desktop-database /usr/share/applications >/dev/null 2>&1 || true
|
||||||
|
|
||||||
# 4) Remove Hyprland keybinding block from bindings.conf
|
# 4) Remove Hyprland keybinding block.
|
||||||
BINDINGS_FILE="$HOME/.config/hypr/bindings.conf"
|
# Omarchy 4 keeps bindings in bindings.lua, Omarchy 3 in bindings.conf — an
|
||||||
if [[ -f "$BINDINGS_FILE" ]] && grep -q '# Red Pill Backup TUI' "$BINDINGS_FILE"; then
|
# upgraded machine can have both, so clean whichever carries our marker.
|
||||||
# Remove the block between "# Red Pill Backup TUI" and "# End Red Pill Backup TUI" (inclusive)
|
_removed_bind=0
|
||||||
sed -i '/# Red Pill Backup TUI/,/# End Red Pill Backup TUI/d' "$BINDINGS_FILE"
|
_removed_lua=0
|
||||||
|
for BINDINGS_FILE in "$HOME/.config/hypr/bindings.lua" "$HOME/.config/hypr/bindings.conf"; do
|
||||||
|
[[ -f "$BINDINGS_FILE" ]] || continue
|
||||||
|
grep -q 'Red Pill Backup TUI' "$BINDINGS_FILE" || continue
|
||||||
|
[[ "$BINDINGS_FILE" == *.lua ]] && _removed_lua=1
|
||||||
|
# Remove the block between the start and end markers (inclusive), in either
|
||||||
|
# comment syntax
|
||||||
|
sed -i '/^[-#]* *Red Pill Backup TUI/,/^[-#]* *End Red Pill Backup TUI/d' "$BINDINGS_FILE"
|
||||||
# Clean up any resulting double blank lines
|
# Clean up any resulting double blank lines
|
||||||
sed -i '/^$/N;/^\n$/d' "$BINDINGS_FILE"
|
sed -i '/^$/N;/^\n$/d' "$BINDINGS_FILE"
|
||||||
_ok "Removed Red Pill keybinding and window rules from $BINDINGS_FILE"
|
_ok "Removed Red Pill keybinding and window rules from $BINDINGS_FILE"
|
||||||
|
_removed_bind=1
|
||||||
|
done
|
||||||
|
|
||||||
# Remove live Hyprland bindings if running
|
if (( _removed_bind )); then
|
||||||
|
# Remove live Hyprland bindings if running. The Lua parser rejects
|
||||||
|
# `hyprctl keyword`, so reload the config there instead.
|
||||||
if command -v hyprctl >/dev/null 2>&1 && hyprctl monitors -j &>/dev/null; then
|
if command -v hyprctl >/dev/null 2>&1 && hyprctl monitors -j &>/dev/null; then
|
||||||
|
if (( _removed_lua )); then
|
||||||
|
hyprctl reload >/dev/null 2>&1 || true
|
||||||
|
else
|
||||||
hyprctl keyword unbind "SUPER ALT, B" >/dev/null 2>&1 || true
|
hyprctl keyword unbind "SUPER ALT, B" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
_ok "Removed live Hyprland keybinding"
|
_ok "Removed live Hyprland keybinding"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
_skip "Hyprland keybinding in bindings.conf"
|
_skip "Hyprland keybinding (not found in bindings.lua or bindings.conf)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 5) Remove redpill-notify from Hyprland autostart
|
# 5) Remove redpill-notify from Hyprland autostart (both flavours)
|
||||||
AUTOSTART_FILE="$HOME/.config/hypr/autostart.conf"
|
_removed_autostart=0
|
||||||
if [[ -f "$AUTOSTART_FILE" ]] && grep -q 'redpill-notify' "$AUTOSTART_FILE"; then
|
for AUTOSTART_FILE in "$HOME/.config/hypr/autostart.lua" "$HOME/.config/hypr/autostart.conf"; do
|
||||||
sed -i '/# Red Pill backup reminder on login/d' "$AUTOSTART_FILE"
|
[[ -f "$AUTOSTART_FILE" ]] || continue
|
||||||
sed -i '/exec-once = redpill-notify/d' "$AUTOSTART_FILE"
|
grep -q 'redpill-notify' "$AUTOSTART_FILE" || continue
|
||||||
|
sed -i '/Red Pill backup reminder on login/d' "$AUTOSTART_FILE"
|
||||||
|
sed -i '/End Red Pill backup reminder/d' "$AUTOSTART_FILE"
|
||||||
|
sed -i '/redpill-notify/d' "$AUTOSTART_FILE"
|
||||||
# Clean up any resulting double blank lines
|
# Clean up any resulting double blank lines
|
||||||
sed -i '/^$/N;/^\n$/d' "$AUTOSTART_FILE"
|
sed -i '/^$/N;/^\n$/d' "$AUTOSTART_FILE"
|
||||||
_ok "Removed redpill-notify from $AUTOSTART_FILE"
|
_ok "Removed redpill-notify from $AUTOSTART_FILE"
|
||||||
else
|
_removed_autostart=1
|
||||||
_skip "redpill-notify in autostart.conf"
|
done
|
||||||
fi
|
(( _removed_autostart )) || _skip "redpill-notify in Hyprland autostart"
|
||||||
|
|
||||||
# 6) Remove Walker custom command entry for RED PILL
|
# 6) Remove Walker custom command entry for RED PILL (Omarchy 3 only)
|
||||||
WCONF="$HOME/.config/walker/config.toml"
|
WCONF="$HOME/.config/walker/config.toml"
|
||||||
if [[ -f "$WCONF" ]] && grep -q 'label = "RED PILL"' "$WCONF"; then
|
if [[ -f "$WCONF" ]] && grep -q 'label = "RED PILL"' "$WCONF"; then
|
||||||
# Remove the [[builtins.custom_commands.entries]] block for RED PILL
|
# Remove the [[builtins.custom_commands.entries]] block for RED PILL
|
||||||
|
|
@ -159,8 +177,8 @@ else
|
||||||
_skip "RED PILL in Walker config"
|
_skip "RED PILL in Walker config"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 7) Kill walker to refresh
|
# 7) Kill walker to refresh (Omarchy 3 only — Omarchy 4 has no Walker)
|
||||||
pkill -x walker >/dev/null 2>&1 || true
|
command -v walker >/dev/null 2>&1 && pkill -x walker >/dev/null 2>&1 || true
|
||||||
|
|
||||||
# 8) Ask about config and state directories
|
# 8) Ask about config and state directories
|
||||||
echo
|
echo
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,10 @@ set -euo pipefail
|
||||||
# Never edits icons or your System menu.
|
# Never edits icons or your System menu.
|
||||||
|
|
||||||
# 0) Deps — check only, these all ship with omarchy
|
# 0) Deps — check only, these all ship with omarchy
|
||||||
|
# NB: no terminal is listed here. Omarchy 4 lets the user pick their terminal
|
||||||
|
# (xdg-terminal-exec resolves it), so pulling in a specific one would be wrong.
|
||||||
missing=()
|
missing=()
|
||||||
for pkg in rsync libnewt zstd alacritty desktop-file-utils; do
|
for pkg in rsync libnewt zstd desktop-file-utils; do
|
||||||
pacman -Q "$pkg" &>/dev/null || missing+=("$pkg")
|
pacman -Q "$pkg" &>/dev/null || missing+=("$pkg")
|
||||||
done
|
done
|
||||||
if (( ${#missing[@]} > 0 )); then
|
if (( ${#missing[@]} > 0 )); then
|
||||||
|
|
@ -96,6 +98,47 @@ timestamp(){ date +"%Y-%m-%d_%H-%M-%S"; }
|
||||||
hosttag(){ hostnamectl --static 2>/dev/null || hostname; }
|
hosttag(){ hostnamectl --static 2>/dev/null || hostname; }
|
||||||
choose_comp(){ have zstd && echo zstd || echo gzip; }
|
choose_comp(){ have zstd && echo zstd || echo gzip; }
|
||||||
|
|
||||||
|
# ── Omarchy theme name ──
|
||||||
|
# Omarchy 4 moved current-theme state to ~/.local/state/omarchy (which is
|
||||||
|
# excluded from backups), Omarchy 3 kept it in ~/.config/omarchy.
|
||||||
|
current_theme_name(){
|
||||||
|
local f
|
||||||
|
for f in "$HOME/.local/state/omarchy/current/theme.name" \
|
||||||
|
"$HOME/.config/omarchy/current/theme.name"; do
|
||||||
|
if [[ -f "$f" ]]; then
|
||||||
|
head -n1 "$f" 2>/dev/null | tr -d '[:space:]'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Theme recorded in a snapshot's backup.log, falling back to the Omarchy 3
|
||||||
|
# location inside the just-restored $HOME (older backups have no Theme: line).
|
||||||
|
snapshot_theme_name(){
|
||||||
|
local log="${1:-}" t=""
|
||||||
|
if [[ -f "$log" ]]; then
|
||||||
|
t="$(grep -oP '^Theme:\s+\K.*' "$log" 2>/dev/null | head -n1)" || t=""
|
||||||
|
fi
|
||||||
|
if [[ -z "$t" && -f "$HOME/.config/omarchy/current/theme.name" ]]; then
|
||||||
|
t="$(head -n1 "$HOME/.config/omarchy/current/theme.name" 2>/dev/null)" || t=""
|
||||||
|
fi
|
||||||
|
printf '%s' "$(printf '%s' "$t" | tr -d '[:space:]')"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Reapply a theme to the running session. Silent no-op if we don't know one.
|
||||||
|
reapply_theme(){
|
||||||
|
local t="${1:-}"
|
||||||
|
[[ -n "$t" ]] || return 0
|
||||||
|
have omarchy-theme-set || return 0
|
||||||
|
_info "Reapplying theme" "$t"
|
||||||
|
if omarchy-theme-set "$t" >/dev/null 2>&1; then
|
||||||
|
_ok "Theme '$t' applied to running session"
|
||||||
|
else
|
||||||
|
_warn "Could not apply theme '$t' — is it installed on this machine?"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ── Prompt to reboot after restore ──
|
# ── Prompt to reboot after restore ──
|
||||||
prompt_reboot(){
|
prompt_reboot(){
|
||||||
echo
|
echo
|
||||||
|
|
@ -573,6 +616,9 @@ mk_backup(){
|
||||||
echo "Hostname: $(hosttag)"
|
echo "Hostname: $(hosttag)"
|
||||||
echo "User: $USER"
|
echo "User: $USER"
|
||||||
echo "Home: $HOME"
|
echo "Home: $HOME"
|
||||||
|
# Recorded here because Omarchy 4 keeps the current theme in
|
||||||
|
# ~/.local/state/omarchy, which the default excludes skip.
|
||||||
|
echo "Theme: $(current_theme_name 2>/dev/null || echo unknown)"
|
||||||
echo
|
echo
|
||||||
} > "$logfile"
|
} > "$logfile"
|
||||||
|
|
||||||
|
|
@ -805,14 +851,29 @@ if [[ -n "$OLD_HOME" && "$OLD_HOME" != "$HOME" ]]; then
|
||||||
echo " ${_green}✓${_reset} Paths updated for new home directory"
|
echo " ${_green}✓${_reset} Paths updated for new home directory"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Reapply omarchy theme if available
|
# Reapply omarchy theme if available.
|
||||||
THEME_NAME_FILE="$HOME/.config/omarchy/current/theme.name"
|
# Omarchy 4 keeps the current theme in ~/.local/state/omarchy (not backed up),
|
||||||
if command -v omarchy-theme-set >/dev/null 2>&1 && [[ -f "$THEME_NAME_FILE" ]]; then
|
# so the snapshot's backup.log is the source of truth; fall back to the
|
||||||
RESTORED_THEME="$(cat "$THEME_NAME_FILE")"
|
# Omarchy 3 path for snapshots taken before that line existed.
|
||||||
if [[ -n "$RESTORED_THEME" ]]; then
|
RESTORED_THEME=""
|
||||||
|
if [[ -f "$BACKUP_LOG" ]]; then
|
||||||
|
RESTORED_THEME="$(grep -oP '^Theme:\s+\K.*' "$BACKUP_LOG" 2>/dev/null | head -n1)" || RESTORED_THEME=""
|
||||||
|
fi
|
||||||
|
if [[ -z "$RESTORED_THEME" || "$RESTORED_THEME" == "unknown" ]]; then
|
||||||
|
if [[ -f "$HOME/.config/omarchy/current/theme.name" ]]; then
|
||||||
|
RESTORED_THEME="$(head -n1 "$HOME/.config/omarchy/current/theme.name" 2>/dev/null)" || RESTORED_THEME=""
|
||||||
|
else
|
||||||
|
RESTORED_THEME=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
RESTORED_THEME="$(printf '%s' "$RESTORED_THEME" | tr -d '[:space:]')"
|
||||||
|
|
||||||
|
if command -v omarchy-theme-set >/dev/null 2>&1 && [[ -n "$RESTORED_THEME" ]]; then
|
||||||
echo " Applying theme: $RESTORED_THEME"
|
echo " Applying theme: $RESTORED_THEME"
|
||||||
omarchy-theme-set "$RESTORED_THEME" >/dev/null 2>&1 || true
|
if omarchy-theme-set "$RESTORED_THEME" >/dev/null 2>&1; then
|
||||||
echo " ${_green}✓${_reset} Theme applied"
|
echo " ${_green}✓${_reset} Theme applied"
|
||||||
|
else
|
||||||
|
echo " ${_yellow}⚠${_reset} Could not apply theme '$RESTORED_THEME' — is it installed?"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -894,6 +955,11 @@ config_backup(){
|
||||||
tar -czpf "$out" "${rels[@]}"
|
tar -czpf "$out" "${rels[@]}"
|
||||||
fi
|
fi
|
||||||
popd >/dev/null
|
popd >/dev/null
|
||||||
|
|
||||||
|
# Sidecar with the active theme — the tarball itself can't carry it on
|
||||||
|
# Omarchy 4, where theme state lives outside ~/.config.
|
||||||
|
current_theme_name > "${out}.theme" 2>/dev/null || rm -f "${out}.theme"
|
||||||
|
|
||||||
_ok "Config backup written: $out"
|
_ok "Config backup written: $out"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1299,18 +1365,7 @@ restore_snapshot(){
|
||||||
fix_restored_paths "$source/backup.log"
|
fix_restored_paths "$source/backup.log"
|
||||||
|
|
||||||
# Reapply omarchy theme so the restored theme takes effect in the running session
|
# Reapply omarchy theme so the restored theme takes effect in the running session
|
||||||
if have omarchy-theme-set; then
|
reapply_theme "$(snapshot_theme_name "$source/backup.log")"
|
||||||
local theme_name_file="$HOME/.config/omarchy/current/theme.name"
|
|
||||||
if [[ -f "$theme_name_file" ]]; then
|
|
||||||
local restored_theme
|
|
||||||
restored_theme="$(cat "$theme_name_file")"
|
|
||||||
if [[ -n "$restored_theme" ]]; then
|
|
||||||
_info "Reapplying theme" "$restored_theme"
|
|
||||||
omarchy-theme-set "$restored_theme" >/dev/null 2>&1 || true
|
|
||||||
_ok "Theme '$restored_theme' applied to running session"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
prompt_reboot
|
prompt_reboot
|
||||||
}
|
}
|
||||||
|
|
@ -1346,19 +1401,14 @@ restore_local(){
|
||||||
rm -f "$tmp_log"
|
rm -f "$tmp_log"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Reapply omarchy theme so the restored theme takes effect in the running session
|
# Reapply omarchy theme — prefer the sidecar written alongside the tarball,
|
||||||
if have omarchy-theme-set; then
|
# else whatever the Omarchy 3 config tree carried
|
||||||
local theme_name_file="$HOME/.config/omarchy/current/theme.name"
|
local local_theme=""
|
||||||
if [[ -f "$theme_name_file" ]]; then
|
if [[ -f "${a}.theme" ]]; then
|
||||||
local restored_theme
|
local_theme="$(head -n1 "${a}.theme" 2>/dev/null | tr -d '[:space:]')" || local_theme=""
|
||||||
restored_theme="$(cat "$theme_name_file")"
|
|
||||||
if [[ -n "$restored_theme" ]]; then
|
|
||||||
_info "Reapplying theme" "$restored_theme"
|
|
||||||
omarchy-theme-set "$restored_theme" >/dev/null 2>&1 || true
|
|
||||||
_ok "Theme '$restored_theme' applied to running session"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
[[ -n "$local_theme" ]] || local_theme="$(snapshot_theme_name "")"
|
||||||
|
reapply_theme "$local_theme"
|
||||||
|
|
||||||
prompt_reboot
|
prompt_reboot
|
||||||
}
|
}
|
||||||
|
|
@ -1721,48 +1771,82 @@ if ! sudo chmod +x /usr/local/bin/bluepill; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 3) Applications entry — write to BOTH system & user dirs
|
# 3) Work out how to open the TUI in a terminal window.
|
||||||
|
# Omarchy 4 resolves the user's chosen terminal through xdg-terminal-exec, so
|
||||||
|
# prefer that and only fall back to probing individual terminals.
|
||||||
|
#
|
||||||
|
# The window is identified by app-id/class rather than title: the same string
|
||||||
|
# has to survive a Lua string, a Hyprland exec (which goes through /bin/sh) and
|
||||||
|
# a .desktop Exec key, and an unspaced app-id needs no quoting in any of them.
|
||||||
|
# It must contain a dot — ghostty rejects app-ids that don't look like an ID.
|
||||||
|
REDPILL_APPID="TUI.redpill"
|
||||||
|
|
||||||
|
REDPILL_LAUNCH=""
|
||||||
|
if command -v xdg-terminal-exec >/dev/null 2>&1; then
|
||||||
|
REDPILL_LAUNCH="xdg-terminal-exec --app-id=$REDPILL_APPID -e redpill"
|
||||||
|
elif command -v ghostty >/dev/null 2>&1; then
|
||||||
|
REDPILL_LAUNCH="ghostty --class=$REDPILL_APPID -e redpill"
|
||||||
|
elif command -v kitty >/dev/null 2>&1; then
|
||||||
|
REDPILL_LAUNCH="kitty --class=$REDPILL_APPID redpill"
|
||||||
|
elif command -v alacritty >/dev/null 2>&1; then
|
||||||
|
REDPILL_LAUNCH="alacritty --class $REDPILL_APPID -e redpill"
|
||||||
|
elif command -v foot >/dev/null 2>&1; then
|
||||||
|
REDPILL_LAUNCH="foot --app-id=$REDPILL_APPID redpill"
|
||||||
|
else
|
||||||
|
echo "Warning: no supported terminal found — run 'redpill' from a shell instead" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# With no terminal available, fall back to a Terminal=true desktop entry so the
|
||||||
|
# launcher still has something to run.
|
||||||
|
if [[ -n "$REDPILL_LAUNCH" ]]; then
|
||||||
|
REDPILL_EXEC="$REDPILL_LAUNCH"
|
||||||
|
REDPILL_TERMINAL_FIELD="false"
|
||||||
|
else
|
||||||
|
REDPILL_EXEC="redpill"
|
||||||
|
REDPILL_TERMINAL_FIELD="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4) Applications entry — write to BOTH system & user dirs
|
||||||
USER_DESK="$HOME/.local/share/applications/redpill.desktop"
|
USER_DESK="$HOME/.local/share/applications/redpill.desktop"
|
||||||
SYS_DESK="/usr/share/applications/redpill.desktop"
|
SYS_DESK="/usr/share/applications/redpill.desktop"
|
||||||
|
|
||||||
mkdir -p "$(dirname "$USER_DESK")"
|
write_desktop_entry(){
|
||||||
cat > "$USER_DESK" <<'DESK'
|
cat <<DESK
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=RED PILL
|
Name=RED PILL
|
||||||
Comment=Unified backup & restore for Hyprland configs and user data
|
Comment=Unified backup & restore for Hyprland configs and user data
|
||||||
Exec=alacritty --title "RED PILL" -e redpill
|
Exec=${REDPILL_EXEC}
|
||||||
Terminal=false
|
Terminal=${REDPILL_TERMINAL_FIELD}
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=System;Utility;
|
Categories=System;Utility;
|
||||||
NoDisplay=false
|
NoDisplay=false
|
||||||
StartupNotify=false
|
StartupNotify=false
|
||||||
Keywords=hyprland;backup;restore;configs;redpill;bluepill;rsync;
|
Keywords=hyprland;backup;restore;configs;redpill;bluepill;rsync;
|
||||||
DESK
|
DESK
|
||||||
|
}
|
||||||
|
|
||||||
if ! sudo tee "$SYS_DESK" >/dev/null <<'DESK'; then
|
mkdir -p "$(dirname "$USER_DESK")"
|
||||||
[Desktop Entry]
|
write_desktop_entry > "$USER_DESK"
|
||||||
Name=RED PILL
|
|
||||||
Comment=Unified backup & restore for Hyprland configs and user data
|
if ! write_desktop_entry | sudo tee "$SYS_DESK" >/dev/null; then
|
||||||
Exec=alacritty --title "RED PILL" -e redpill
|
|
||||||
Terminal=false
|
|
||||||
Type=Application
|
|
||||||
Categories=System;Utility;
|
|
||||||
NoDisplay=false
|
|
||||||
StartupNotify=false
|
|
||||||
Keywords=hyprland;backup;restore;configs;redpill;bluepill;rsync;
|
|
||||||
DESK
|
|
||||||
echo "Warning: Failed to create system desktop entry" >&2
|
echo "Warning: Failed to create system desktop entry" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
update-desktop-database "$HOME/.local/share/applications" >/dev/null 2>&1 || true
|
update-desktop-database "$HOME/.local/share/applications" >/dev/null 2>&1 || true
|
||||||
sudo update-desktop-database /usr/share/applications >/dev/null 2>&1 || true
|
sudo update-desktop-database /usr/share/applications >/dev/null 2>&1 || true
|
||||||
|
|
||||||
# 4) Walker: unhide Applications (sed-only) + add custom command safety net
|
# 5) Walker: unhide Applications (sed-only) + add custom command safety net.
|
||||||
|
# Omarchy 4 dropped Walker for the Quickshell menu, which reads .desktop files
|
||||||
|
# directly — so this whole block only applies where Walker is actually present.
|
||||||
WCONF="$HOME/.config/walker/config.toml"
|
WCONF="$HOME/.config/walker/config.toml"
|
||||||
|
|
||||||
|
if ! command -v walker >/dev/null 2>&1; then
|
||||||
|
echo "Walker not installed — skipping launcher config (Omarchy 4 indexes .desktop entries directly)"
|
||||||
|
else
|
||||||
mkdir -p "$(dirname "$WCONF")"
|
mkdir -p "$(dirname "$WCONF")"
|
||||||
|
|
||||||
if [ ! -f "$WCONF" ]; then
|
if [ ! -f "$WCONF" ]; then
|
||||||
cat >"$WCONF" <<'TOML'
|
cat >"$WCONF" <<TOML
|
||||||
[builtins.applications]
|
[builtins.applications]
|
||||||
launch_prefix = "uwsm app -- "
|
launch_prefix = "uwsm app -- "
|
||||||
hidden = false
|
hidden = false
|
||||||
|
|
@ -1772,7 +1856,7 @@ hidden = false
|
||||||
|
|
||||||
[[builtins.custom_commands.entries]]
|
[[builtins.custom_commands.entries]]
|
||||||
label = "RED PILL"
|
label = "RED PILL"
|
||||||
command = "alacritty --title 'RED PILL' -e redpill"
|
command = "${REDPILL_EXEC}"
|
||||||
keywords = ["redpill","backup","restore","hyprland"]
|
keywords = ["redpill","backup","restore","hyprland"]
|
||||||
icon = ""
|
icon = ""
|
||||||
TOML
|
TOML
|
||||||
|
|
@ -1802,62 +1886,117 @@ hidden = false
|
||||||
TOML
|
TOML
|
||||||
fi
|
fi
|
||||||
if ! grep -q 'label = "RED PILL"' "$WCONF"; then
|
if ! grep -q 'label = "RED PILL"' "$WCONF"; then
|
||||||
cat >>"$WCONF" <<'TOML'
|
cat >>"$WCONF" <<TOML
|
||||||
|
|
||||||
[[builtins.custom_commands.entries]]
|
[[builtins.custom_commands.entries]]
|
||||||
label = "RED PILL"
|
label = "RED PILL"
|
||||||
command = "alacritty --title 'RED PILL' -e redpill"
|
command = "${REDPILL_EXEC}"
|
||||||
keywords = ["redpill","backup","restore","hyprland"]
|
keywords = ["redpill","backup","restore","hyprland"]
|
||||||
icon = ""
|
icon = ""
|
||||||
TOML
|
TOML
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 5) Hyprland keybinding: Super+Alt+B → floating RED PILL window
|
|
||||||
BINDINGS_FILE="$HOME/.config/hypr/bindings.conf"
|
|
||||||
|
|
||||||
# Detect preferred terminal with --title support
|
|
||||||
REDPILL_TERM=""
|
|
||||||
if command -v ghostty >/dev/null 2>&1; then
|
|
||||||
REDPILL_TERM="ghostty --title='RED PILL' -e"
|
|
||||||
elif command -v kitty >/dev/null 2>&1; then
|
|
||||||
REDPILL_TERM="kitty --title='RED PILL' -e"
|
|
||||||
elif command -v alacritty >/dev/null 2>&1; then
|
|
||||||
REDPILL_TERM="alacritty --title='RED PILL' -e"
|
|
||||||
elif command -v foot >/dev/null 2>&1; then
|
|
||||||
REDPILL_TERM="foot --title='RED PILL' --"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$REDPILL_TERM" && -f "$BINDINGS_FILE" ]]; then
|
# 6) Hyprland keybinding: Super+Alt+B → floating RED PILL window
|
||||||
if ! grep -q "# Red Pill Backup TUI" "$BINDINGS_FILE"; then
|
#
|
||||||
echo "Adding keybinding (Super+Alt+B) to $BINDINGS_FILE"
|
# Omarchy 4 / Hyprland 0.56 use the Lua config provider: ~/.config/hypr/*.conf
|
||||||
|
# is never read, so the binding has to go into bindings.lua. Omarchy 3 boxes
|
||||||
|
# still use bindings.conf. Detect which, and write the matching syntax.
|
||||||
|
BINDINGS_LUA="$HOME/.config/hypr/bindings.lua"
|
||||||
|
BINDINGS_CONF="$HOME/.config/hypr/bindings.conf"
|
||||||
|
|
||||||
|
hypr_config_flavour(){
|
||||||
|
if [[ -f "$BINDINGS_LUA" ]]; then
|
||||||
|
echo lua
|
||||||
|
elif [[ -f "$BINDINGS_CONF" ]]; then
|
||||||
|
echo conf
|
||||||
|
elif hyprctl systeminfo 2>/dev/null | grep -q 'configProvider:[[:space:]]*lua'; then
|
||||||
|
# Lua session that has no personal bindings file yet — create one
|
||||||
|
echo lua
|
||||||
|
else
|
||||||
|
echo none
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
HYPR_FLAVOUR="$(hypr_config_flavour)"
|
||||||
|
|
||||||
|
# The keybinding needs a terminal; the autostart entry further down doesn't.
|
||||||
|
BIND_FLAVOUR="$HYPR_FLAVOUR"
|
||||||
|
if [[ -z "$REDPILL_LAUNCH" ]]; then
|
||||||
|
echo "Skipping Hyprland keybinding — no terminal to launch the TUI in" >&2
|
||||||
|
BIND_FLAVOUR="none"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Machines upgraded from Omarchy 3 keep an inert bindings.conf. Strip any block
|
||||||
|
# we left there so the binding isn't defined in two places.
|
||||||
|
if [[ "$HYPR_FLAVOUR" == "lua" && -f "$BINDINGS_CONF" ]] && \
|
||||||
|
grep -q '# Red Pill Backup TUI' "$BINDINGS_CONF"; then
|
||||||
|
sed -i '/# Red Pill Backup TUI/,/# End Red Pill Backup TUI/d' "$BINDINGS_CONF"
|
||||||
|
sed -i '/^$/N;/^\n$/d' "$BINDINGS_CONF"
|
||||||
|
echo "Removed stale Red Pill block from $BINDINGS_CONF (Hyprland no longer reads it)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$BIND_FLAVOUR" in
|
||||||
|
lua)
|
||||||
|
mkdir -p "$(dirname "$BINDINGS_LUA")"
|
||||||
|
[[ -f "$BINDINGS_LUA" ]] || : > "$BINDINGS_LUA"
|
||||||
|
if ! grep -q -- "-- Red Pill Backup TUI" "$BINDINGS_LUA"; then
|
||||||
|
echo "Adding keybinding (Super+Alt+B) to $BINDINGS_LUA"
|
||||||
|
# One property per o.window() call, matching Omarchy's own style
|
||||||
|
{
|
||||||
|
echo ""
|
||||||
|
echo "-- Red Pill Backup TUI"
|
||||||
|
echo "o.window({ class = \"^${REDPILL_APPID}\$\" }, { float = true })"
|
||||||
|
echo "o.window({ class = \"^${REDPILL_APPID}\$\" }, { center = true })"
|
||||||
|
echo "o.window({ class = \"^${REDPILL_APPID}\$\" }, { size = { 800, 600 } })"
|
||||||
|
echo "o.window({ class = \"^${REDPILL_APPID}\$\" }, { pin = true })"
|
||||||
|
echo "o.bind(\"SUPER + ALT + B\", \"Red Pill Backup\", \"${REDPILL_LAUNCH}\")"
|
||||||
|
echo "-- End Red Pill Backup TUI"
|
||||||
|
} >> "$BINDINGS_LUA"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
conf)
|
||||||
|
if ! grep -q "# Red Pill Backup TUI" "$BINDINGS_CONF"; then
|
||||||
|
echo "Adding keybinding (Super+Alt+B) to $BINDINGS_CONF"
|
||||||
{
|
{
|
||||||
echo ""
|
echo ""
|
||||||
echo "# Red Pill Backup TUI"
|
echo "# Red Pill Backup TUI"
|
||||||
echo "windowrule = match:title RED PILL, float on"
|
echo "windowrule = match:class ^${REDPILL_APPID}\$, float on"
|
||||||
echo "windowrule = match:title RED PILL, size 800 600"
|
echo "windowrule = match:class ^${REDPILL_APPID}\$, size 800 600"
|
||||||
echo "windowrule = match:title RED PILL, center on"
|
echo "windowrule = match:class ^${REDPILL_APPID}\$, center on"
|
||||||
echo "windowrule = match:title RED PILL, pin on"
|
echo "windowrule = match:class ^${REDPILL_APPID}\$, pin on"
|
||||||
echo "bindd = SUPER ALT, B, Red Pill Backup, exec, $REDPILL_TERM redpill"
|
echo "bindd = SUPER ALT, B, Red Pill Backup, exec, $REDPILL_LAUNCH"
|
||||||
echo "# End Red Pill Backup TUI"
|
echo "# End Red Pill Backup TUI"
|
||||||
} >> "$BINDINGS_FILE"
|
} >> "$BINDINGS_CONF"
|
||||||
fi
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "No Hyprland bindings file found — skipping Super+Alt+B keybinding" >&2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
# Apply dynamically so no Hyprland reload needed
|
# Apply to the running session so the binding works without a logout.
|
||||||
if command -v hyprctl >/dev/null 2>&1 && hyprctl monitors -j &>/dev/null; then
|
if [[ "$BIND_FLAVOUR" != "none" ]] && command -v hyprctl >/dev/null 2>&1 && hyprctl monitors -j &>/dev/null; then
|
||||||
|
if [[ "$BIND_FLAVOUR" == "lua" ]]; then
|
||||||
|
# The Lua parser rejects `hyprctl keyword` ("can't work with non-legacy
|
||||||
|
# parsers"), so re-read the config instead. Hyprland usually autoreloads on
|
||||||
|
# write anyway; this just makes it deterministic.
|
||||||
|
hyprctl reload >/dev/null 2>&1 || true
|
||||||
|
else
|
||||||
hyprctl keyword unbind "SUPER ALT, B" >/dev/null 2>&1 || true
|
hyprctl keyword unbind "SUPER ALT, B" >/dev/null 2>&1 || true
|
||||||
hyprctl keyword windowrule "match:title RED PILL, float on" >/dev/null 2>&1 || true
|
hyprctl keyword windowrule "match:class ^${REDPILL_APPID}\$, float on" >/dev/null 2>&1 || true
|
||||||
hyprctl keyword windowrule "match:title RED PILL, size 800 600" >/dev/null 2>&1 || true
|
hyprctl keyword windowrule "match:class ^${REDPILL_APPID}\$, size 800 600" >/dev/null 2>&1 || true
|
||||||
hyprctl keyword windowrule "match:title RED PILL, center on" >/dev/null 2>&1 || true
|
hyprctl keyword windowrule "match:class ^${REDPILL_APPID}\$, center on" >/dev/null 2>&1 || true
|
||||||
hyprctl keyword windowrule "match:title RED PILL, pin on" >/dev/null 2>&1 || true
|
hyprctl keyword windowrule "match:class ^${REDPILL_APPID}\$, pin on" >/dev/null 2>&1 || true
|
||||||
hyprctl keyword bindd "SUPER ALT, B, Red Pill Backup, exec, $REDPILL_TERM redpill" >/dev/null 2>&1 || true
|
hyprctl keyword bindd "SUPER ALT, B, Red Pill Backup, exec, $REDPILL_LAUNCH" >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 6) Config directory (no custom theming - uses system defaults)
|
# 7) Config directory (no custom theming - uses system defaults)
|
||||||
mkdir -p "$HOME/.config/redpill"
|
mkdir -p "$HOME/.config/redpill"
|
||||||
|
|
||||||
# 7) Create RECOVERY.txt guide
|
# 8) Create RECOVERY.txt guide
|
||||||
cat > "$HOME/.config/redpill/RECOVERY.txt" <<'RECOVERY'
|
cat > "$HOME/.config/redpill/RECOVERY.txt" <<'RECOVERY'
|
||||||
RED PILL - Recovery Guide
|
RED PILL - Recovery Guide
|
||||||
==============================
|
==============================
|
||||||
|
|
@ -1939,7 +2078,7 @@ SNAPSHOT STRUCTURE (on external drive):
|
||||||
You can browse any snapshot directly in a file manager.
|
You can browse any snapshot directly in a file manager.
|
||||||
RECOVERY
|
RECOVERY
|
||||||
|
|
||||||
# 8) Auto-backup on shutdown — systemd service + wrapper script
|
# 9) Auto-backup on shutdown — systemd service + wrapper script
|
||||||
# Wrapper: checks preconditions silently, runs full backup if ready
|
# Wrapper: checks preconditions silently, runs full backup if ready
|
||||||
sudo tee /usr/local/bin/redpill-autobackup >/dev/null <<'AUTOBACKUP'
|
sudo tee /usr/local/bin/redpill-autobackup >/dev/null <<'AUTOBACKUP'
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
@ -2041,12 +2180,14 @@ EOF
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
# Don't enable here — user opts in via TUI menu option 11
|
# Don't enable here — user opts in via TUI menu option 11
|
||||||
|
|
||||||
# 9) Login notification checker — reminds user to plug in backup drive
|
# 10) Login notification checker — reminds user to plug in backup drive
|
||||||
sudo tee /usr/local/bin/redpill-notify >/dev/null <<'NOTIFY'
|
sudo tee /usr/local/bin/redpill-notify >/dev/null <<'NOTIFY'
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Wait for notification daemon (mako) to be ready
|
# Wait for the notification daemon to claim the bus name.
|
||||||
|
# (mako on Omarchy 3, omarchy-shell/Quickshell on Omarchy 4 — either way it's
|
||||||
|
# org.freedesktop.Notifications, and either way it isn't up instantly.)
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/redpill"
|
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/redpill"
|
||||||
|
|
@ -2077,24 +2218,54 @@ fi
|
||||||
NOTIFY
|
NOTIFY
|
||||||
sudo chmod +x /usr/local/bin/redpill-notify
|
sudo chmod +x /usr/local/bin/redpill-notify
|
||||||
|
|
||||||
# Add redpill-notify to Hyprland autostart (once only)
|
# Add redpill-notify to Hyprland autostart (once only).
|
||||||
AUTOSTART_FILE="$HOME/.config/hypr/autostart.conf"
|
# Same .conf-vs-.lua split as the keybinding above.
|
||||||
if [[ -f "$AUTOSTART_FILE" ]]; then
|
AUTOSTART_LUA="$HOME/.config/hypr/autostart.lua"
|
||||||
if ! grep -q 'redpill-notify' "$AUTOSTART_FILE"; then
|
AUTOSTART_CONF="$HOME/.config/hypr/autostart.conf"
|
||||||
echo "Adding redpill-notify to $AUTOSTART_FILE"
|
|
||||||
|
# Same cleanup as the bindings: drop our line from the now-inert .conf
|
||||||
|
if [[ "$HYPR_FLAVOUR" == "lua" && -f "$AUTOSTART_CONF" ]] && \
|
||||||
|
grep -q 'redpill-notify' "$AUTOSTART_CONF"; then
|
||||||
|
sed -i '/# Red Pill backup reminder on login/d;/redpill-notify/d' "$AUTOSTART_CONF"
|
||||||
|
sed -i '/^$/N;/^\n$/d' "$AUTOSTART_CONF"
|
||||||
|
echo "Removed stale redpill-notify line from $AUTOSTART_CONF (Hyprland no longer reads it)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$HYPR_FLAVOUR" in
|
||||||
|
lua)
|
||||||
|
mkdir -p "$(dirname "$AUTOSTART_LUA")"
|
||||||
|
[[ -f "$AUTOSTART_LUA" ]] || : > "$AUTOSTART_LUA"
|
||||||
|
if ! grep -q 'redpill-notify' "$AUTOSTART_LUA"; then
|
||||||
|
echo "Adding redpill-notify to $AUTOSTART_LUA"
|
||||||
|
{
|
||||||
|
echo ""
|
||||||
|
echo "-- Red Pill backup reminder on login"
|
||||||
|
echo 'o.launch_on_start("redpill-notify")'
|
||||||
|
echo "-- End Red Pill backup reminder"
|
||||||
|
} >> "$AUTOSTART_LUA"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
conf)
|
||||||
|
if [[ -f "$AUTOSTART_CONF" ]] && ! grep -q 'redpill-notify' "$AUTOSTART_CONF"; then
|
||||||
|
echo "Adding redpill-notify to $AUTOSTART_CONF"
|
||||||
{
|
{
|
||||||
echo ""
|
echo ""
|
||||||
echo "# Red Pill backup reminder on login"
|
echo "# Red Pill backup reminder on login"
|
||||||
echo "exec-once = redpill-notify"
|
echo "exec-once = redpill-notify"
|
||||||
} >> "$AUTOSTART_FILE"
|
} >> "$AUTOSTART_CONF"
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "No Hyprland autostart file found — login reminders won't run" >&2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
# 10) Reindex and restart Walker so the new entry is searchable immediately
|
# 11) Reindex launcher entries so RED PILL is searchable immediately
|
||||||
update-desktop-database "$HOME/.local/share/applications" >/dev/null 2>&1 || true
|
update-desktop-database "$HOME/.local/share/applications" >/dev/null 2>&1 || true
|
||||||
sudo update-desktop-database /usr/share/applications >/dev/null 2>&1 || true
|
sudo update-desktop-database /usr/share/applications >/dev/null 2>&1 || true
|
||||||
# Kill walker more safely - only exact process name match
|
# Omarchy 3: nudge Walker to re-read its index. Omarchy 4's menu watches
|
||||||
pkill -x walker >/dev/null 2>&1 || true
|
# .desktop dirs itself, so there's nothing to restart there.
|
||||||
|
command -v walker >/dev/null 2>&1 && pkill -x walker >/dev/null 2>&1 || true
|
||||||
|
|
||||||
echo "Installed:"
|
echo "Installed:"
|
||||||
echo " - redpill (TUI) at /usr/local/bin/redpill"
|
echo " - redpill (TUI) at /usr/local/bin/redpill"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue