feat: split zshrc into a stub and role-aware fragments
Load order is the substance of this change, and two attempts got it wrong in
the same way. oh-my-zsh consumes both the plugins array and the theme while it
is being sourced, so anything set afterwards is silently ignored. The plan had
plugins in the stub but the theme in the role file, which produced a shell
reporting ZSH_THEME=powerlevel10k while running without powerlevel10k at all -
132 of its functions missing and nobody any the wiser. Plugins and prompt are
now both resolved before oh-my-zsh, the latter in 05-prompt.zsh.
Portability is handled by asking whether a command exists rather than by
duplicating files per role. "alias ls='lsd'" turns ls into a broken command on
a machine without lsd, and the Mac is such a machine; the yay aliases and
helpers are gated the same way. That keeps one shared base instead of three
diverging copies.
The plan also guessed the plugin list as (git fzf). It is actually seven
entries, so five would have vanished - among them signal-keyring, which turned
out to be a local custom plugin present on this machine only. Naming it
elsewhere means an oh-my-zsh warning at every login, and its content is a
verbatim copy of the gnome-keyring block already in .zshrc, so it ran twice.
The inline block stays, in the desktop role; the plugin is dropped.
Dead code removed rather than carried over:
- PYTHONPATH pointed at /usr/lib/python3.9/site-packages. Python here is
3.14 and that directory does not exist.
- XDG_SESSION_TYPE was forced to x11 and then tested for "wayland" six lines
below, so that branch could never be taken. The variable belongs to the
session; overriding it lies to everything that reads it.
- drm() was defined twice, the first losing to the second on every start.
- PATH carried ~/bin, ~/.scripts and /usr/X11R6/bin, none of which exist.
Entries are added only if the directory is there.
Verified against the live configuration in an isolated ZDOTDIR: 277 aliases and
263 functions on both sides, none missing, and powerlevel10k loading for all
three roles with the intended colour.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
49357eced4
commit
ce560c315d
@@ -0,0 +1,176 @@
|
||||
# Functions shared by every machine.
|
||||
#
|
||||
# The fzf-based ones are the bulk of it. They are defined unconditionally: a
|
||||
# function that is never called costs nothing, and guarding each one would be
|
||||
# more noise than the guard is worth. Only the docker group is gated, because
|
||||
# those names are short enough to shadow something else on a machine without
|
||||
# docker.
|
||||
|
||||
# Which hosts are holding the most connections open.
|
||||
detect-ddos() {
|
||||
sudo netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n
|
||||
}
|
||||
|
||||
# cd into a directory picked with fzf.
|
||||
fdir() {
|
||||
local dir
|
||||
dir=$(find "${1:-.}" -path '*/\.*' -prune \
|
||||
-o -type d -print 2> /dev/null | fzf +m) &&
|
||||
cd "$dir"
|
||||
}
|
||||
|
||||
# Pick a command out of history and put it on the command line rather than
|
||||
# running it, so it can still be edited.
|
||||
fhist() {
|
||||
print -z $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s --tac | sed -E 's/ *[0-9]*\*? *//' | sed -E 's/\\/\\\\/g')
|
||||
}
|
||||
|
||||
# Kill a process picked with fzf. Non-root sees only its own processes, which
|
||||
# is also all it could kill.
|
||||
fkill() {
|
||||
local pid
|
||||
if [ "$UID" != "0" ]; then
|
||||
pid=$(ps -f -u "$UID" | sed 1d | fzf -m | awk '{print $2}')
|
||||
else
|
||||
pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}')
|
||||
fi
|
||||
|
||||
if [ "x$pid" != "x" ]; then
|
||||
echo "$pid" | xargs kill -"${1:-9}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Kill tmux sessions picked with fzf. Needs zsh's =~ operator.
|
||||
tmuxkillf () {
|
||||
local sessions
|
||||
sessions="$(tmux ls|fzf --exit-0 --multi)" || return $?
|
||||
local i
|
||||
for i in "${(f@)sessions}"
|
||||
do
|
||||
[[ $i =~ '([^:]*):.*' ]] && {
|
||||
echo "Killing $match[1]"
|
||||
tmux kill-session -t "$match[1]"
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
# tm pick a session with fzf
|
||||
# tm <name> attach to it, creating it if needed
|
||||
# Works from inside tmux too, where attaching would fail.
|
||||
tm() {
|
||||
[[ -n "$TMUX" ]] && change="switch-client" || change="attach-session"
|
||||
if [ "$1" ]; then
|
||||
tmux $change -t "$1" 2>/dev/null || (tmux new-session -d -s "$1" && tmux $change -t "$1"); return
|
||||
fi
|
||||
session=$(tmux list-sessions -F "#{session_name}" 2>/dev/null | fzf --exit-0) && tmux $change -t "$session" || echo "No sessions found."
|
||||
}
|
||||
|
||||
# Leave yazi in the directory it was left in, rather than where it started.
|
||||
(( $+commands[yazi] )) && y() {
|
||||
local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd
|
||||
yazi "$@" --cwd-file="$tmp"
|
||||
IFS= read -r -d '' cwd < "$tmp"
|
||||
[ -n "$cwd" ] && [ "$cwd" != "$PWD" ] && builtin cd -- "$cwd"
|
||||
rm -f -- "$tmp"
|
||||
}
|
||||
|
||||
# Docker helpers, all fzf pickers. Present on all three machines today, but
|
||||
# "ds" and "da" are short enough to be worth gating rather than defining blind.
|
||||
if (( $+commands[docker] )); then
|
||||
# start a stopped container and attach to it
|
||||
da() {
|
||||
local cid
|
||||
cid=$(docker ps -a | sed 1d | fzf -1 -q "$1" | awk '{print $1}')
|
||||
[ -n "$cid" ] && docker start "$cid" && docker attach "$cid"
|
||||
}
|
||||
|
||||
# stop a running container
|
||||
ds() {
|
||||
local cid
|
||||
cid=$(docker ps | sed 1d | fzf -q "$1" | awk '{print $1}')
|
||||
[ -n "$cid" ] && docker stop "$cid"
|
||||
}
|
||||
|
||||
# remove containers, multi-select. The single-select version that used to sit
|
||||
# above this one was dead code: it had the same name and was overwritten on
|
||||
# every shell start.
|
||||
drm() {
|
||||
docker ps -a | sed 1d | fzf -q "$1" --no-sort -m --tac | awk '{ print $1 }' | xargs -r docker rm
|
||||
}
|
||||
|
||||
# remove images, multi-select
|
||||
drmi() {
|
||||
docker images | sed 1d | fzf -q "$1" --no-sort -m --tac | awk '{ print $3 }' | xargs -r docker rmi
|
||||
}
|
||||
fi
|
||||
|
||||
# Arch package hygiene: remove orphans, but write down what was removed first
|
||||
# so the decision can be undone.
|
||||
if (( $+commands[yay] )); then
|
||||
yay_remove_orphans() {
|
||||
local backup_dir="$HOME/.config/yay"
|
||||
local date_str backup_file orphans
|
||||
|
||||
date_str="$(date +%Y-%m-%d_%H-%M-%S)"
|
||||
backup_file="$backup_dir/remove_orph_${date_str}.bak"
|
||||
mkdir -p "$backup_dir"
|
||||
|
||||
orphans=("${(@f)$(yay -Qtdq)}")
|
||||
|
||||
if [[ ${#orphans[@]} -eq 0 || -z "${orphans[1]}" ]]; then
|
||||
echo "✔ Keine verwaisten Pakete gefunden."
|
||||
return 0
|
||||
fi
|
||||
|
||||
print -l -- "${orphans[@]}" > "$backup_file"
|
||||
|
||||
echo "📦 Backup der verwaisten Pakete erstellt:"
|
||||
echo " $backup_file"
|
||||
echo
|
||||
echo "🧹 Entferne folgende Pakete:"
|
||||
print -l -- "${orphans[@]}"
|
||||
echo
|
||||
|
||||
yay -Rns "${orphans[@]}"
|
||||
}
|
||||
|
||||
yay_restore_orphans() {
|
||||
local backup_dir="$HOME/.config/yay"
|
||||
local backup_file packages selected
|
||||
|
||||
backup_file=$(ls -1 "$backup_dir"/remove_orph_*.bak 2>/dev/null | fzf \
|
||||
--prompt="Backup auswählen: " \
|
||||
--height=40% \
|
||||
--reverse)
|
||||
|
||||
[[ -z "$backup_file" ]] && {
|
||||
echo "✖ Kein Backup ausgewählt."
|
||||
return 1
|
||||
}
|
||||
|
||||
packages=("${(@f)$(cat "$backup_file")}")
|
||||
|
||||
if [[ ${#packages[@]} -eq 0 ]]; then
|
||||
echo "✖ Backup ist leer."
|
||||
return 1
|
||||
fi
|
||||
|
||||
selected=("${(@f)$(printf "%s\n" "${packages[@]}" | fzf \
|
||||
--multi \
|
||||
--prompt="Pakete auswählen (TAB): " \
|
||||
--height=60% \
|
||||
--reverse)}")
|
||||
|
||||
[[ ${#selected[@]} -eq 0 ]] && {
|
||||
echo "✖ Keine Pakete ausgewählt."
|
||||
return 1
|
||||
}
|
||||
|
||||
echo
|
||||
echo "📦 Installiere folgende Pakete:"
|
||||
printf " - %s\n" "${selected[@]}"
|
||||
echo
|
||||
|
||||
yay -S "${selected[@]}"
|
||||
}
|
||||
fi
|
||||
Reference in New Issue
Block a user