Fix install/uninstall bugs and document both scripts in README

Fix glob matching in install.sh shell detection (use [[ ]] instead of [ ]),
add missing argument check for uninstall.sh --backup flag, and update README
with install/uninstall usage section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-19 00:52:39 +00:00
parent c0ea9ecf0f
commit e42d9ba749
3 changed files with 261 additions and 18 deletions

View File

@@ -26,11 +26,42 @@ Install all packages:
yay -S $(grep -v '^\s*$' ~/scripts/packages.txt | tr '\n' ' ') yay -S $(grep -v '^\s*$' ~/scripts/packages.txt | tr '\n' ' ')
``` ```
## Linking Configs ## Install / Uninstall
Pick a window manager section below, then add the shared configs. `install.sh` symlinks configs, sources shell files, and backs up any existing files it would overwrite. `uninstall.sh` reverses the process, removing symlinks and restoring backups.
### Hyprland ```bash
# Install everything (uses Hyprland as the WM)
~/scripts/install.sh all
# Install specific targets
~/scripts/install.sh hyprland shell nvim tmux
# Uninstall specific targets (restores from most recent backup)
~/scripts/uninstall.sh nvim shell
# Uninstall using a specific backup
~/scripts/uninstall.sh --backup ~/scripts/backups/20260319_120000 all
```
Available targets: `hyprland`, `sway`, `i3`, `cursor`, `shell`, `alacritty`, `tmux`, `nvim`, `vim`, `all`.
### tmux prerequisite
Install the plugin manager before running `install.sh tmux`:
```bash
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
```
### Manual linking
If you prefer to link configs manually instead of using `install.sh`:
<details>
<summary>Manual symlink commands</summary>
#### Hyprland
```bash ```bash
ln -sf ~/scripts/hypr ~/.config/hypr ln -sf ~/scripts/hypr ~/.config/hypr
@@ -38,7 +69,7 @@ ln -sf ~/scripts/waybar ~/.config/waybar
ln -sf ~/scripts/wofi ~/.config/wofi ln -sf ~/scripts/wofi ~/.config/wofi
``` ```
### Sway #### Sway
```bash ```bash
ln -sf ~/scripts/sway ~/.config/sway ln -sf ~/scripts/sway ~/.config/sway
@@ -53,7 +84,7 @@ mv ~/scripts/waybar/config ~/scripts/waybar/config.hypr.json
mv ~/scripts/waybar/waybar_sway_config.json ~/scripts/waybar/config mv ~/scripts/waybar/waybar_sway_config.json ~/scripts/waybar/config
``` ```
### i3 #### i3
```bash ```bash
ln -sf ~/scripts/i3 ~/.config/i3 ln -sf ~/scripts/i3 ~/.config/i3
@@ -61,13 +92,13 @@ ln -sf ~/scripts/i3blocks ~/.config/i3blocks
ln -sf ~/scripts/i3status ~/.config/i3status ln -sf ~/scripts/i3status ~/.config/i3status
``` ```
### Cursor #### Cursor
```bash ```bash
ln -sf ~/scripts/hatsune-miku-windows-linux-cursors/miku-cursor-linux ~/.local/share/icons/"Miku Cursor" ln -sf ~/scripts/hatsune-miku-windows-linux-cursors/miku-cursor-linux ~/.local/share/icons/"Miku Cursor"
``` ```
### Shell #### Shell
Add to `~/.bashrc` or `~/.zshrc`: Add to `~/.bashrc` or `~/.zshrc`:
@@ -76,7 +107,7 @@ source ~/scripts/bashrc # or zshrc
export PATH="~/scripts/sh:$PATH" export PATH="~/scripts/sh:$PATH"
``` ```
### Terminals #### Terminals
**Alacritty** - add to `~/.config/alacritty/alacritty.toml`: **Alacritty** - add to `~/.config/alacritty/alacritty.toml`:
@@ -86,13 +117,7 @@ import = ["~/scripts/alacritty.toml"]
**Kitty** - kitty.conf is used directly by the WM configs. **Kitty** - kitty.conf is used directly by the WM configs.
### tmux #### tmux
Install the plugin manager first:
```bash
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
```
Add to `~/.tmux.conf`: Add to `~/.tmux.conf`:
@@ -100,7 +125,7 @@ Add to `~/.tmux.conf`:
source ~/scripts/tmux.conf source ~/scripts/tmux.conf
``` ```
### Vim #### Vim
Add to `~/.vimrc`: Add to `~/.vimrc`:
@@ -108,6 +133,8 @@ Add to `~/.vimrc`:
source ~/scripts/vimrc source ~/scripts/vimrc
``` ```
</details>
## Keybindings ## Keybindings
All window managers and tmux use vim-style <kbd>h</kbd><kbd>j</kbd><kbd>k</kbd><kbd>l</kbd> navigation. `$mod` is the Super key. All window managers and tmux use vim-style <kbd>h</kbd><kbd>j</kbd><kbd>k</kbd><kbd>l</kbd> navigation. `$mod` is the Super key.

View File

@@ -100,11 +100,11 @@ install_cursor() {
install_shell() { install_shell() {
echo "Installing shell configs..." echo "Installing shell configs..."
if [ -f "$HOME/.zshrc" ] || [ "$SHELL" = *zsh* ]; then if [ -f "$HOME/.zshrc" ] || [[ "$SHELL" == *zsh* ]]; then
append_if_missing "$HOME/.zshrc" "source ~/scripts/zshrc" append_if_missing "$HOME/.zshrc" "source ~/scripts/zshrc"
append_if_missing "$HOME/.zshrc" 'export PATH="$HOME/scripts/sh:$PATH"' append_if_missing "$HOME/.zshrc" 'export PATH="$HOME/scripts/sh:$PATH"'
fi fi
if [ -f "$HOME/.bashrc" ] || [ "$SHELL" = *bash* ]; then if [ -f "$HOME/.bashrc" ] || [[ "$SHELL" == *bash* ]]; then
append_if_missing "$HOME/.bashrc" "source ~/scripts/bashrc" append_if_missing "$HOME/.bashrc" "source ~/scripts/bashrc"
append_if_missing "$HOME/.bashrc" 'export PATH="$HOME/scripts/sh:$PATH"' append_if_missing "$HOME/.bashrc" 'export PATH="$HOME/scripts/sh:$PATH"'
fi fi

216
uninstall.sh Executable file
View File

@@ -0,0 +1,216 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPTS_DIR="$HOME/scripts"
CONFIG_DIR="$HOME/.config"
BACKUP_DIR=""
usage() {
echo "Usage: $(basename "$0") [OPTIONS] <target>..."
echo
echo "Targets:"
echo " hyprland Hyprland + waybar + wofi"
echo " sway Sway + waybar + wofi"
echo " i3 i3 + i3blocks + i3status"
echo " cursor Miku cursor theme"
echo " shell Remove sourced bashrc/zshrc and sh/ from PATH"
echo " alacritty Remove import from alacritty.toml"
echo " tmux Remove sourced tmux.conf"
echo " nvim Neovim (LazyVim) config"
echo " vim Remove sourced vimrc"
echo " all Everything (uses hyprland as WM)"
echo
echo "Options:"
echo " -h, --help Show this help"
echo " --backup <dir> Use specific backup directory for restoring"
echo " (default: most recent in $SCRIPTS_DIR/backups/)"
}
# Find the backup directory to restore from
find_backup() {
if [ -n "$BACKUP_DIR" ]; then
if [ ! -d "$BACKUP_DIR" ]; then
echo "Error: backup directory not found: $BACKUP_DIR"
exit 1
fi
return
fi
local backups_root="$SCRIPTS_DIR/backups"
if [ -d "$backups_root" ]; then
local latest
latest=$(ls -1d "$backups_root"/*/ 2>/dev/null | sort | tail -n1 || true)
if [ -n "$latest" ]; then
BACKUP_DIR="${latest%/}"
echo "Using backup: $BACKUP_DIR"
fi
fi
if [ -z "$BACKUP_DIR" ]; then
echo "No backups found, will only remove without restoring"
fi
}
# Remove a symlink if it points into $SCRIPTS_DIR, then restore from backup if available
restore() {
local dest="$1"
local name
name=$(basename "$dest")
if [ -L "$dest" ]; then
local target
target=$(readlink "$dest")
if [[ "$target" == "$SCRIPTS_DIR"* ]]; then
rm "$dest"
echo " Removed symlink $dest"
else
echo " Skipping $dest (symlink does not point into $SCRIPTS_DIR)"
return
fi
elif [ -e "$dest" ]; then
echo " Skipping $dest (not a symlink, won't remove)"
return
else
echo " $dest does not exist, nothing to remove"
fi
# Restore from backup if available
if [ -n "$BACKUP_DIR" ] && [ -e "$BACKUP_DIR/$name" ]; then
cp -a "$BACKUP_DIR/$name" "$dest"
echo " Restored $dest from backup"
fi
}
# Remove exact matching lines from a file
remove_line() {
local file="$1" line="$2"
if [ ! -f "$file" ]; then
echo " $file does not exist, nothing to remove"
return
fi
if grep -qF "$line" "$file"; then
local tmp
tmp=$(mktemp)
grep -vF "$line" "$file" > "$tmp" || true
mv "$tmp" "$file"
echo " Removed from $file: $line"
# Delete file if only whitespace remains
if [ ! -s "$file" ] || ! grep -q '[^[:space:]]' "$file"; then
rm "$file"
echo " Deleted empty $file"
fi
else
echo " Line not found in $file: $line"
fi
}
uninstall_hyprland() {
echo "Uninstalling Hyprland configs..."
restore "$CONFIG_DIR/hypr"
restore "$CONFIG_DIR/waybar"
restore "$CONFIG_DIR/wofi"
}
uninstall_sway() {
echo "Uninstalling Sway configs..."
restore "$CONFIG_DIR/sway"
restore "$CONFIG_DIR/waybar"
restore "$CONFIG_DIR/wofi"
}
uninstall_i3() {
echo "Uninstalling i3 configs..."
restore "$CONFIG_DIR/i3"
restore "$CONFIG_DIR/i3blocks"
restore "$CONFIG_DIR/i3status"
}
uninstall_cursor() {
echo "Uninstalling cursor theme..."
restore "$HOME/.local/share/icons/Miku Cursor"
}
uninstall_shell() {
echo "Uninstalling shell configs..."
if [ -f "$HOME/.zshrc" ]; then
remove_line "$HOME/.zshrc" "source ~/scripts/zshrc"
remove_line "$HOME/.zshrc" 'export PATH="$HOME/scripts/sh:$PATH"'
fi
if [ -f "$HOME/.bashrc" ]; then
remove_line "$HOME/.bashrc" "source ~/scripts/bashrc"
remove_line "$HOME/.bashrc" 'export PATH="$HOME/scripts/sh:$PATH"'
fi
}
uninstall_alacritty() {
echo "Uninstalling Alacritty config..."
local conf="$CONFIG_DIR/alacritty/alacritty.toml"
remove_line "$conf" 'import = ["~/scripts/alacritty.toml"]'
}
uninstall_tmux() {
echo "Uninstalling tmux config..."
remove_line "$HOME/.tmux.conf" "source ~/scripts/tmux.conf"
}
uninstall_nvim() {
echo "Uninstalling Neovim config..."
restore "$CONFIG_DIR/nvim"
}
uninstall_vim() {
echo "Uninstalling vim config..."
remove_line "$HOME/.vimrc" "source ~/scripts/vimrc"
}
if [ $# -eq 0 ]; then
usage
exit 1
fi
targets=()
while [ $# -gt 0 ]; do
case "$1" in
-h | --help)
usage
exit 0
;;
--backup)
if [ $# -lt 2 ]; then
echo "Error: --backup requires a directory argument"
exit 1
fi
BACKUP_DIR="$2"
shift 2
;;
all)
targets+=(hyprland cursor shell alacritty tmux nvim vim)
shift
;;
*)
targets+=("$1")
shift
;;
esac
done
find_backup
for target in "${targets[@]}"; do
case "$target" in
hyprland) uninstall_hyprland ;;
sway) uninstall_sway ;;
i3) uninstall_i3 ;;
cursor) uninstall_cursor ;;
shell) uninstall_shell ;;
alacritty) uninstall_alacritty ;;
tmux) uninstall_tmux ;;
nvim) uninstall_nvim ;;
vim) uninstall_vim ;;
*)
echo "Unknown target: $target"
usage
exit 1
;;
esac
done
echo "Done!"