Compare commits

..

26 Commits

Author SHA1 Message Date
dissimulo 48814c5d42 tmux-net: trailing space after the ✕ offline glyph for status-bar padding 2026-06-30 16:57:22 -07:00
dissimulo 0eb605a835 tmux statusline: directly-held WAN/LAN IP, offline ✕, native window-status
- tmux-ip: show the first directly-held public/WAN IP on a non-tunnel interface,
  else the LAN/private IP. No external 'what's my IP' lookup and no DigitalOcean
  special-case (a droplet's eth0 public IP is found by the same interface scan);
  RFC1918/link-local/CGNAT classed as not-WAN, so a NAT'd box shows its LAN IP.
- tmux-net: show ✕ when there's no local IP and no VPN tunnel (offline). VPN ⇡
  overlay unchanged.
- .tmux.conf: window-status icon + path now native tmux formats (no per-redraw
  #() forks); tmux-window-icon kept as fallback.
2026-06-30 16:39:52 -07:00
dissimulo c32dbb92ac claude: fullscreen tui 2026-06-30 16:32:46 -07:00
dissimulo 8c3dcacafc claude: dark-daltonized theme 2026-06-30 15:23:32 -07:00
dissimulo c680be4817 lolcat: revert to busyloop (Debian) active; jaseg removed from PATH (too coarse) 2026-06-24 09:40:27 -07:00
dissimulo 13f43c3c5f lolcat: jaseg C build now active at /usr/local/bin (ahead of busyloop) 2026-06-24 09:35:35 -07:00
dissimulo aafdc3a119 lolcat: correct attribution to busyloop Ruby build (Debian pkg upstream) 2026-06-24 09:29:33 -07:00
dissimulo 4053acbbc0 Add zsh/lolcat.zsh rainbow helpers + document in README 2026-06-24 09:12:17 -07:00
dissimulo 2906352220 tmux: lowercase am/pm in statusline clock 2026-06-16 17:12:10 -07:00
dissimulo 1d2a823750 tmux: drop space between time and AM/PM in statusline 2026-06-16 17:11:44 -07:00
dissimulo 8400ddf6a8 tmux: 12-hour clock in statusline (%-I:%M %p) 2026-06-16 17:08:27 -07:00
dissimulo 11bf7ecaa4 zsh: eagerly define diff() to avoid prezto autoload-stub error
Pretzo's modules/utility/functions/diff registers an autoload stub that
emits '(eval):1: diff: function definition file not found' in non-
interactive eval contexts where $fpath doesn't include the utility
module's functions directory. Define diff as a real function up front so
the stub never has to look itself up.
2026-05-17 04:02:13 -07:00
dissimulo 3d6f13b2bc tmux-net: always prefix local IP with home symbol
Show ⌂ before the local IP whether or not a VPN is up. The VPN branch
already prefixes ⌂; the non-VPN branch was emitting the bare IP.
2026-05-17 03:58:11 -07:00
dissimulo e2a1e3b784 tmux status: use short hostname (#h) instead of FQDN (#H) 2026-05-17 03:23:55 -07:00
dissimulo e38a6b3166 tmux status: show VPN IP when tunnel is active
Add tmux-vpn-ip helper (parses ifconfig for utun* on macOS, falls back
to tun/wg/ppp on Linux) and a tmux-net wrapper that conditionally
emits "⌂ <local> / ⇡ <vpn>" when a VPN tunnel is up, or just "<local>"
when it's not. status-right now calls tmux-net.
2026-05-17 03:19:26 -07:00
dissimulo 467b967ced tmux-ip: portable local-IP fallback for macOS
`hostname -I` is GNU-only and errors on BSD/macOS, so when the public-IP
curl couldn't reach api.ipify.org the script printed nothing and the
tmux status bar showed an empty IP. Try `ipconfig getifaddr` for common
interfaces first, fall back to `hostname -I` on Linux, then `ifconfig`
as a last resort. Also guard against empty-but-zero-exit curl output.
2026-05-17 03:12:11 -07:00
dissimulo 474fdd028c Rakefile: handle non-interactive stdin in ask()
STDIN.gets returns nil when stdin is closed/EOF (e.g. after vim/vundle
runs during install), causing `nil.chomp` to abort rake install during
install_term_theme. Return nil from ask() on EOF and have callers bail
out of the iTerm theme prompts gracefully.
2026-05-17 02:14:29 -07:00
dissimulo a45f89b187 .claude/settings.json: prune server-specific entries; consolidate redundant ones
The previous snapshot of settings.json was a verbatim dump from one
Mastodon-server install — it carried allowlist entries that won't
match anywhere else and a lot of narrow rules already subsumed by
broader wildcards.

Removed (server-specific, dead weight on other hosts):
- /home/mastodon/* paths and Mastodon .env.production sed/chmod/chown
- signers.online and auto.signers.online curl/openssl probes
- mastodon-web / mastodon-streaming / mastodon-sidekiq journalctl
- n8n journalctl, windmill journalctl + binary
- /usr/local/bin/fail2ban-ignoreip and the hardcoded IP 76.95.82.63
- nslookup signers.live, nginx site-availables grep with literal paths
- /var/log/nginx/access.log* zcat probes (path-specific)
- StatusReactions / status_quoted grep over Mastodon's frontend tree

Removed (redundant, covered by broader wildcard already in the list):
- All narrow Bash(systemctl <verb>:*) entries — Bash(systemctl:*) covers
- All narrow Bash(git ...) entries — Bash(git:*) covers
- All narrow Bash(curl ...) probes — Bash(curl:*) covers
- Bash(rkhunter --update), Bash(rkhunter --propupd) — Bash(rkhunter:*) covers
- Bash(sysctl -a) — Bash(sysctl:*) covers

Kept: tmux/git/curl/sudo/find/ls/cat plus generic system-admin verbs
(systemctl, sysctl, crontab, iptables, ufw, firewall-cmd, fail2ban-client,
apt/apt-get/dpkg, mount, netstat, openssl, lsmod, last, nginx, redis-cli,
rkhunter, aideinit, getent, sqlite3, dig, ulimit, getenforce, aa-status)
plus Read(//home/**), Read(//opt/**), Read(//etc/nginx/sites-{enabled,available}/**).

Net: 5004 -> 1434 bytes (57 lines), still valid JSON, behavior on a
fresh host is identical for the kept verbs and tighter for the dropped
ones (host-specific allows just won't match anything anyway).

If you re-run install.sh on this host, the slim version replaces the
fat one; the fat one survives in ~/.drunkendotfiles.bak.<ts>/ for
recovery.
2026-05-06 10:10:21 +00:00
dissimulo 1b60a9364d Add portable Claude Code config
Saves ~/.claude/settings.json (user-level prefs + Bash/Read permissions
allowlist) so the same Claude Code config can be replicated on other
hosts via install.sh.

What gets deployed:
- .claude/settings.json — theme, verbose, defaultMode, skipAutoPermissionPrompt
  and the cumulative "approve once" allowlist for common ops (systemctl,
  iptables, journalctl, git, curl, etc.). Server-specific allow entries
  (e.g. /home/mastodon/* paths) are dead weight elsewhere but harmless.
- .claude/.gitignore — explicit deny-list so a future `git add .claude`
  doesn't accidentally pull in credentials, session logs, project
  memories, file-history, telemetry, caches, or settings.local.json.

What is NOT tracked (by design):
- .credentials.json (auth)
- history.jsonl, sessions/, projects/ (chat data, project memories)
- settings.local.json (per-machine overrides — by Claude Code convention)
- file-history/, plans/, paste-cache/, shell-snapshots/, session-env/,
  telemetry/, downloads/, cache/, backups/, mcp-needs-auth-cache.json
- plugins/ (marketplace install paths are absolute and host-specific)

deploy_dir's merge semantics mean: on a host that already has
~/.claude/.credentials.json or ~/.claude/projects/, those stay untouched
because the repo doesn't track them. Only the files we explicitly
include get installed.

Existing settings.json on the target host is moved aside to
~/.drunkendotfiles.bak.<timestamp>/ before being replaced.
2026-05-06 10:06:36 +00:00
dissimulo 5208e9a5bb install.sh: repoint dangling claude symlink to latest installed version
The committed ~/.local/bin/claude symlink targets a specific Claude Code
version path (whatever was current when this snapshot was taken). On any
host that has Claude Code installed at a different version, that symlink
arrives dangling.

Old behavior: just delete the dangling link and rely on the Claude
installer to recreate it. That doesn't help when the host has Claude
installed but at a version other than the one in the snapshot, and we
also support skipping the installer via DRUNKENDOTFILES_SKIP_CLAUDE=1
(used when the binary is already on disk but at a different version).

New behavior: when the deployed symlink is dangling, scan
~/.local/share/claude/versions/ and repoint the symlink to the highest
installed version (semver sort). Only fall back to deleting the link if
no version is installed at all.
2026-05-06 09:45:52 +00:00
dissimulo 6188583ee9 tmux: enable truecolor + focus-events for TUI apps
- Switch default-terminal from screen-256color to tmux-256color
  (better italics/undercurl/SGR support for nvim, Claude Code, etc.)
- Add terminal-features RGB for the common outer terminals so
  truecolor escape sequences pass through cleanly
- Enable focus-events so inner programs can redraw when the pane
  regains focus
2026-05-06 09:37:20 +00:00
dissimulo f27ba2710e Pin git identity to dissimulo / connect+gitea@dustin-williams.com
Identity was previously deferred to ~/.gitconfig.user via the include
at the bottom of this file. Per the dotfiles owner, identity should
travel with the dotfiles regardless of host or local user — every
machine where this repo is deployed commits as dissimulo.

Per-machine bits (safe.directory, etc.) still belong in
~/.gitconfig.user, which the existing [include] at the bottom picks
up after this block.
2026-05-06 02:26:08 -07:00
dissimulo c0e4a88d70 Add ~/.local/bin to PATH from prezto-override zshrc
The Claude Code installer drops the binary at ~/.local/bin/claude.
Without this PATH entry, freshly-installed Claude Code is invisible to
new shells until the user adds it manually. Other ~/.local/bin scripts
in this dotfiles repo (tmux-ip, tmux-window-icon, twitterbot, etc.)
benefit from the same.
2026-05-06 02:24:33 -07:00
dissimulo 700da3aa0b Make tmux/tmux.conf a relative symlink to ../.tmux.conf
YADR's Rakefile maps tmux/tmux.conf -> $HOME/.tmux.conf, but the
canonical, customized tmux config has lived at the repo root since
3d2508a (when the relationship was inverted). Re-running rake install
on its own (without the bash installer's subsequent personal-deploy
overlay) was therefore replacing the deployed real .tmux.conf with a
symlink to the older 3987-byte tmux/tmux.conf, dropping the IP/host
status-right and the bumped history limit.

Pointing tmux/tmux.conf at ../.tmux.conf via a relative symlink fixes
this on any machine, regardless of where ~/.yadr lives or which user
owns it: rake install's symlink chain now resolves to the customized
config no matter the install order.
2026-05-06 02:24:32 -07:00
dissimulo fb80b6dfb2 gitconfig: use absolute include path for .gitconfig.user
The previous `[include] path = .gitconfig.user` was resolved relative to
the config file being read, which — because `~/.gitconfig` is a symlink
to `~/.yadr/git/gitconfig` — meant git looked for the user-identity
override at `~/.yadr/git/.gitconfig.user` instead of the conventional
`~/.gitconfig.user`. Switch to an absolute path so the include picks up
the homedir file regardless of symlink layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 07:41:12 -07:00
dissimulo 1d7df94a1d install.sh: merge PERSONAL_DIRS contents instead of wholesale replace
The previous deploy_one() did `mv $HOME/<dir> $BACKUP_DIR/<dir>` then
`cp -a $YADR_DIR/<dir> $HOME/<dir>` for every entry in PERSONAL_DIRS.
For dirs the repo only partially populates (notably .local — repo only
tracks .local/bin/), this swept away unrelated user data: the most
recent re-bootstrap moved ~/.local/share/fonts/ (Intel One Mono, Open
Gorton, Roboto Mono, GALLAUDET, code128) into the timestamped backup,
making them appear missing.

Rework deploy logic:
- deploy_file: copies one file/symlink, backing up only the conflicting
  destination (if any). Idempotent via paths_equivalent() so re-runs
  with no changes produce no output and no spurious backups.
- deploy_dir: walks the repo's tree for that dir and deploys each leaf
  via deploy_file. Files in $HOME the repo doesn't know about are left
  untouched. Subdirs are mkdir'd as needed.

Also: track the personal fonts at .local/share/fonts/ so they redeploy
on every install, and run fc-cache -f at the end so apps see them
without a logout/login.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 07:28:40 -07:00
12 changed files with 330 additions and 32 deletions
+33
View File
@@ -0,0 +1,33 @@
# Never track Claude Code per-machine state, secrets, or chat data.
#
# settings.json IS tracked (portable user prefs + permissions allowlist).
# Everything else under ~/.claude/ stays per-host: credentials, session
# logs, project memories, file-edit history, telemetry, caches.
# Auth — must NEVER be tracked
.credentials.json
# Per-machine settings overrides (by Claude Code convention)
settings.local.json
# Chat and session data
history.jsonl
sessions/
projects/
file-history/
plans/
# Caches and ephemeral state
cache/
downloads/
paste-cache/
shell-snapshots/
session-env/
backups/
telemetry/
mcp-needs-auth-cache.json
# Plugin marketplace state — known_marketplaces.json IS portable, but the
# resolved-plugin caches and the local blocklist are per-machine.
plugins/blocklist.json
plugins/marketplaces/
+58
View File
@@ -0,0 +1,58 @@
{
"permissions": {
"allow": [
"Bash(tmux source-file:*)",
"Bash(git:*)",
"Bash(curl:*)",
"Bash(sudo:*)",
"Bash(find:*)",
"Bash(ls:*)",
"Bash(cat:*)",
"Bash(systemctl:*)",
"Bash(sysctl:*)",
"Bash(crontab:*)",
"Bash(dig:*)",
"Bash(ulimit:*)",
"Bash(python3:*)",
"Bash(iptables:*)",
"Bash(ip6tables:*)",
"Bash(ufw status:*)",
"Bash(firewall-cmd:*)",
"Bash(apt list:*)",
"Bash(apt-get install:*)",
"Bash(apt-get upgrade:*)",
"Bash(dpkg:*)",
"Bash(fail2ban-client status:*)",
"Bash(fail2ban-client set:*)",
"Bash(aa-status)",
"Bash(getenforce)",
"Bash(mount)",
"Bash(netstat -tuln)",
"Bash(netstat -tlnp)",
"Bash(openssl x509:*)",
"Bash(openssl rand:*)",
"Bash(grep -v \"^$\")",
"Bash(du -sh /var/log/*)",
"Bash(lsmod)",
"Bash(xargs ls:*)",
"Bash(last:*)",
"Bash(nginx:*)",
"Bash(redis-cli:*)",
"Bash(rkhunter:*)",
"Bash(aideinit)",
"Bash(npm --version)",
"Bash(ruby --version)",
"Bash(getent passwd:*)",
"Bash(sqlite3:*)",
"Read(//home/**)",
"Read(//opt/**)",
"Read(//etc/nginx/sites-enabled/**)",
"Read(//etc/nginx/sites-available/**)"
],
"defaultMode": "auto"
},
"theme": "dark-daltonized",
"verbose": true,
"tui": "fullscreen",
"skipAutoPermissionPrompt": true
}
+56 -20
View File
@@ -1,33 +1,69 @@
#!/bin/bash #!/bin/bash
# #
# Print the "best" IP for the tmux status bar. # Print the "best" IP for the tmux status bar.
# Preference: DO reserved/floating IP > public egress (ipify) > first local IP. #
# Shows a directly-held public/WAN IP when the machine has one on an interface,
# otherwise its LAN/private IP. No external "what's my IP" lookup -- a NAT'd box
# shows its LAN IP, never the gateway's egress. Works the same everywhere: a box
# with a public IP on a NIC (incl. a cloud droplet's eth0) shows that WAN IP; a
# NAT'd box shows its LAN IP. The VPN overlay is added separately by tmux-net via
# tmux-vpn-ip and is untouched here.
# #
set -u set -u
META="http://169.254.169.254/metadata/v1" # This machine's own non-loopback IPv4 addresses, one per line. VPN tunnels are
CURL="curl -sf --connect-timeout 1 --max-time 2" # excluded (tmux-net surfaces the VPN address separately as the ⇡ segment).
list_ipv4() {
is_digitalocean() { if command -v ip >/dev/null 2>&1; then
[ -r /sys/class/dmi/id/sys_vendor ] \ ip -4 -o addr show scope global 2>/dev/null \
&& grep -qi digitalocean /sys/class/dmi/id/sys_vendor | awk '$2 !~ /^(tun|wg|ppp|tap)/ {print $4}' | cut -d/ -f1
elif hostname -I >/dev/null 2>&1; then
hostname -I 2>/dev/null | tr ' ' '\n'
else
ifconfig 2>/dev/null | awk '/inet /{print $2}'
fi | grep -E '^([0-9]{1,3}\.){3}[0-9]{1,3}$' | grep -v '^127\.'
} }
do_anchor_ip() { # RFC1918 / link-local / CGNAT -- not a directly-routable WAN address.
local kind active ip is_private_ipv4() {
for kind in reserved_ip floating_ip; do case "$1" in
active=$($CURL "$META/$kind/ipv4/active" 2>/dev/null) || continue 10.*|192.168.*|169.254.*) return 0 ;;
[ "$active" = "true" ] || continue 172.1[6-9].*|172.2[0-9].*|172.3[01].*) return 0 ;;
ip=$($CURL "$META/$kind/ipv4/ip_address" 2>/dev/null) || continue 100.6[4-9].*|100.[7-9][0-9].*|100.1[01][0-9].*|100.12[0-7].*) return 0 ;;
[ -n "$ip" ] && { printf '%s\n' "$ip"; return 0; } *) return 1 ;;
done esac
}
# First directly-held public/WAN IP, if the machine has one on an interface.
public_ip() {
local ip
while IFS= read -r ip; do
[ -n "$ip" ] || continue
is_private_ipv4 "$ip" || { printf '%s\n' "$ip"; return 0; }
done <<EOF
$(list_ipv4)
EOF
return 1 return 1
} }
if is_digitalocean && do_anchor_ip; then # Fallback: the machine's primary interface IP (covers macOS and odd setups).
exit 0 print_local_ip() {
fi local iface ip
if command -v ipconfig >/dev/null 2>&1; then
for iface in en0 en1 en2; do
ip=$(ipconfig getifaddr "$iface" 2>/dev/null) || true
[ -n "${ip:-}" ] && { printf '%s\n' "$ip"; return 0; }
done
fi
if hostname -I >/dev/null 2>&1; then
hostname -I | awk '{print $1}'
return 0
fi
ifconfig 2>/dev/null | awk '/inet /{ if ($2 != "127.0.0.1") { print $2; exit } }'
}
curl -s --connect-timeout 3 https://api.ipify.org 2>/dev/null \ # A directly-held public/WAN IP if the box has one, else the LAN IP.
|| hostname -I | awk '{print $1}' ip=$(public_ip || true)
[ -z "${ip:-}" ] && ip=$(print_local_ip)
printf '%s\n' "${ip:-}"
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
#
# Emit the tmux status-bar network segment.
# No VPN: "⌂ <local_ip>"
# VPN up: "⌂ <local_ip> / ⇡ <vpn_ip>"
# Offline: "✕" (no local IP and no VPN tunnel)
#
set -u
local_ip=$("$HOME/.local/bin/tmux-ip" 2>/dev/null || true)
vpn_ip=$("$HOME/.local/bin/tmux-vpn-ip" 2>/dev/null || true)
if [ -z "${local_ip:-}" ] && [ -z "${vpn_ip:-}" ]; then
printf '\xe2\x9c\x95 \n' # ✕ no active connection (trailing space for padding)
elif [ -n "${vpn_ip:-}" ]; then
printf '\xe2\x8c\x82 %s / \xe2\x87\xa1 %s\n' "${local_ip:-}" "$vpn_ip"
else
printf '\xe2\x8c\x82 %s\n' "${local_ip:-}"
fi
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
#
# Print the IPv4 of the first active VPN tunnel interface, if any.
# Empty output when no VPN is up.
#
# macOS: utun* Linux: tun*, wg*, ppp*
set -u
case "$(uname -s)" in
Darwin)
ifconfig 2>/dev/null | awk '
/^utun[0-9]+:/ { iface=$1; sub(":", "", iface); next }
/^[a-z]+[0-9]*:/ { iface="" }
iface != "" && $1 == "inet" { print $2; exit }
'
;;
Linux)
if command -v ip >/dev/null 2>&1; then
ip -4 -o addr show 2>/dev/null \
| awk '$2 ~ /^(tun|wg|ppp)[0-9]+/ { sub("/.*","",$4); print $4; exit }'
fi
;;
esac
+17 -4
View File
@@ -2,7 +2,20 @@
set -g bell-action any set -g bell-action any
# Default termtype. If the rcfile sets $TERM, that overrides this value. # Default termtype. If the rcfile sets $TERM, that overrides this value.
set -g default-terminal screen-256color set -g default-terminal "tmux-256color"
# Truecolor + clipboard passthrough for outer terminals that advertise RGB
# (covers xterm-*, alacritty, kitty, wezterm, iTerm, ghostty, modern Apple Terminal).
set -ga terminal-features ",xterm-256color:RGB"
set -ga terminal-features ",alacritty:RGB"
set -ga terminal-features ",kitty:RGB"
set -ga terminal-features ",wezterm:RGB"
set -ga terminal-features ",ghostty:RGB"
set -ga terminal-features ",screen-256color:RGB"
# TUI apps (Claude Code, nvim, etc.) want focus events so they can redraw
# / refresh state when the pane regains focus.
set -g focus-events on
# Keep your finger on ctrl, or don't # Keep your finger on ctrl, or don't
bind-key ^D detach-client bind-key ^D detach-client
@@ -66,9 +79,9 @@ set -g pane-border-style fg=colour245
set -g pane-active-border-style fg=colour39 set -g pane-active-border-style fg=colour39
set -g message-style fg=colour16,bg=colour221,bold set -g message-style fg=colour16,bg=colour221,bold
set -g status-left '#[fg=colour235,bg=colour252,bold] ❐ #S #[fg=colour252,bg=colour238,nobold]#[fg=colour245,bg=colour238,bold] #(whoami) ' set -g status-left '#[fg=colour235,bg=colour252,bold] ❐ #S #[fg=colour252,bg=colour238,nobold]#[fg=colour245,bg=colour238,bold] #(whoami) '
set -g status-right '#[bold][#[nobold,fg=colour229]#H#[fg=default] / #[fg=colour229]#(~/.local/bin/tmux-ip)#[fg=default,bold]]#[nobold,fg=colour255] %H:%M %d-%b-%Y ' set -g status-right '#[bold][#[nobold,fg=colour229]#h#[fg=default] / #[fg=colour229]#(~/.local/bin/tmux-net)#[fg=default,bold]]#[nobold,fg=colour255] %-I:%M%P %d-%b-%Y '
set -g window-status-format '#[fg=colour235,bg=colour252,nobold] #(~/.local/bin/tmux-window-icon #{window_index}) #(pwd="#{pane_current_path}"; echo ${pwd####*/}) #W ' set -g window-status-format '#[fg=colour235,bg=colour252,nobold] #{?#{==:#{window_index},1},❶,#{?#{==:#{window_index},2},❷,#{?#{==:#{window_index},3},❸,#{?#{==:#{window_index},4},❹,#{?#{==:#{window_index},5},❺,#{?#{==:#{window_index},6},❻,#{?#{==:#{window_index},7},❼,#{?#{==:#{window_index},8},❽,#{?#{==:#{window_index},9},❾,#{?#{==:#{window_index},10},❿,#{window_index}}}}}}}}}}} #{b:pane_current_path} #W '
set -g window-status-current-format '#[fg=colour234,bg=colour39,bold] [#[fg=colour232,bold]#{?window_zoomed_flag,#[fg=colour228],} #(~/.local/bin/tmux-window-icon #{window_index}) #(pwd="#{pane_current_path}"; echo ${pwd####*/}) #W #[fg=colour234,bold]] ' set -g window-status-current-format '#[fg=colour234,bg=colour39,bold] [#[fg=colour232,bold]#{?window_zoomed_flag,#[fg=colour228],} #{?#{==:#{window_index},1},❶,#{?#{==:#{window_index},2},❷,#{?#{==:#{window_index},3},❸,#{?#{==:#{window_index},4},❹,#{?#{==:#{window_index},5},❺,#{?#{==:#{window_index},6},❻,#{?#{==:#{window_index},7},❼,#{?#{==:#{window_index},8},❽,#{?#{==:#{window_index},9},❾,#{?#{==:#{window_index},10},❿,#{window_index}}}}}}}}}}} #{b:pane_current_path} #W #[fg=colour234,bold]] '
set-option -g status-interval 60 set-option -g status-interval 60
# Patch for OS X pbpaste and pbcopy under tmux. # Patch for OS X pbpaste and pbcopy under tmux.
+40
View File
@@ -102,6 +102,46 @@ On top of stock YADR:
- Misc: `.rainbow_config.json` (rainbowstream), `.nanorc`, `.selected_editor`, - Misc: `.rainbow_config.json` (rainbowstream), `.nanorc`, `.selected_editor`,
`.mplayer/config`, `.jigdo-lite` `.mplayer/config`, `.jigdo-lite`
## Rainbow output (lolcat)
`zsh/lolcat.zsh` wires [lolcat](https://github.com/busyloop/lolcat) (Debian's
`/usr/games/lolcat`, busyloop's Ruby build — 24-bit truecolor) into a few shell
helpers. lolcat auto-detects a tty — it colorizes straight to the terminal but
passes text through plain when piped onward, so use `-f`/`--force` to colorize
mid-pipeline.
### Opt-in, per command
Prefix any command to rainbow its output:
```sh
lol fastfetch
lol git log --oneline
lol ls -C # -C keeps columns: a piped ls otherwise goes single-column
lolf git diff | less -R # force color so it survives down a pipeline
```
### Shortcuts
```sh
rcat file.txt # rainbow cat
rls -la # rainbow ls, columns preserved
some-cmd | rless # rainbow + pager (less -R)
```
### Session toggle
Rainbow *all* shell stdout until you turn it off:
```sh
rainbow_on # everything is rainbow now
...
rainbow_off # back to normal
```
Novelty only: it garbles full-screen/interactive programs (vim, less, htop,
fzf, ssh) and the prompt, and buffers streaming output. Doesn't touch stderr.
## Upstream ## Upstream
Base is [skwp/dotfiles][yadr] (YADR — Yet Another Dotfiles Repo). All credit Base is [skwp/dotfiles][yadr] (YADR — Yet Another Dotfiles Repo). All credit
+9 -2
View File
@@ -210,7 +210,7 @@ def install_term_theme
message = "Which theme would you like to apply to your iTerm2 profile?" message = "Which theme would you like to apply to your iTerm2 profile?"
color_scheme = ask message, iTerm_available_themes color_scheme = ask message, iTerm_available_themes
return if color_scheme == 'None' return if color_scheme.nil? || color_scheme == 'None'
color_scheme_file = File.join('iTerm2', "#{color_scheme}.itermcolors") color_scheme_file = File.join('iTerm2', "#{color_scheme}.itermcolors")
@@ -220,6 +220,8 @@ def install_term_theme
profiles << 'All' profiles << 'All'
selected = ask message, profiles selected = ask message, profiles
return if selected.nil?
if selected == 'All' if selected == 'All'
(profiles.size-1).times { |idx| apply_theme_to_iterm_profile_idx idx, color_scheme_file } (profiles.size-1).times { |idx| apply_theme_to_iterm_profile_idx idx, color_scheme_file }
else else
@@ -244,7 +246,12 @@ def ask(message, values)
puts message puts message
while true while true
values.each_with_index { |val, idx| puts " #{idx+1}. #{val}" } values.each_with_index { |val, idx| puts " #{idx+1}. #{val}" }
selection = STDIN.gets.chomp input = STDIN.gets
if input.nil?
puts "(no input available — skipping prompt)"
return nil
end
selection = input.chomp
if (Float(selection)==nil rescue true) || selection.to_i < 0 || selection.to_i > values.size+1 if (Float(selection)==nil rescue true) || selection.to_i < 0 || selection.to_i > values.size+1
puts "ERROR: Invalid selection.\n\n" puts "ERROR: Invalid selection.\n\n"
else else
+3
View File
@@ -1,5 +1,8 @@
# set your user tokens as environment variables, such as ~/.secrets # set your user tokens as environment variables, such as ~/.secrets
# See the README for examples. # See the README for examples.
[user]
name = dissimulo
email = connect+gitea@dustin-williams.com
[color] [color]
ui = true ui = true
[color "branch"] [color "branch"]
+24 -6
View File
@@ -36,7 +36,7 @@ PERSONAL_FILES=(
# untouched. This deliberately avoids wholesale-replacing $HOME/.local etc., # untouched. This deliberately avoids wholesale-replacing $HOME/.local etc.,
# which would sweep away unrelated user data (fonts, app state, ...). # which would sweep away unrelated user data (fonts, app state, ...).
PERSONAL_DIRS=( PERSONAL_DIRS=(
.fonts .irssi .nano .themes .local .mplayer .fonts .irssi .nano .themes .local .mplayer .claude
) )
have() { command -v "$1" >/dev/null 2>&1; } have() { command -v "$1" >/dev/null 2>&1; }
@@ -162,11 +162,29 @@ log "Deploying personal dotfiles"
for f in "${PERSONAL_FILES[@]}"; do deploy_file "$f"; done for f in "${PERSONAL_FILES[@]}"; do deploy_file "$f"; done
for d in "${PERSONAL_DIRS[@]}"; do deploy_dir "$d"; done for d in "${PERSONAL_DIRS[@]}"; do deploy_dir "$d"; done
# .local/bin/claude is a relative symlink to ../share/claude/versions/... # .local/bin/claude is a relative symlink to ../share/claude/versions/<version>.
# If that target isn't present on this machine, remove the dangling link so # The version baked into the repo snapshot is whatever was current when this
# Claude Code's own installer (next step) can manage it. # was last committed; on a fresh host that exact version probably isn't
if [ -L "$HOME/.local/bin/claude" ] && [ ! -e "$HOME/.local/bin/claude" ]; then # installed. Resolve as follows:
rm "$HOME/.local/bin/claude" # 1. If the deployed symlink already resolves, leave it alone.
# 2. Else, if any other Claude version is present under
# ~/.local/share/claude/versions/, repoint the symlink to the highest
# one (semver sort) so users get the latest installed binary.
# 3. Else, drop the dangling link and let Claude Code's own installer
# (next step) recreate it.
claude_link="$HOME/.local/bin/claude"
claude_versions_dir="$HOME/.local/share/claude/versions"
if [ -L "$claude_link" ] && [ ! -e "$claude_link" ]; then
latest_claude=""
if [ -d "$claude_versions_dir" ]; then
latest_claude="$(ls -1 "$claude_versions_dir" 2>/dev/null | sort -V | tail -1)"
fi
if [ -n "$latest_claude" ] && [ -e "$claude_versions_dir/$latest_claude" ]; then
ln -sfn "../share/claude/versions/$latest_claude" "$claude_link"
info "Repointed ~/.local/bin/claude -> $latest_claude (latest installed)"
else
rm "$claude_link"
fi
fi fi
# 4. Install Claude Code (Anthropic's CLI). Skip if already installed or # 4. Install Claude Code (Anthropic's CLI). Skip if already installed or
+13
View File
@@ -0,0 +1,13 @@
# Eagerly define `diff` as a real function instead of relying on prezto's
# autoload stub. The autoload stub emits
# "(eval):1: diff: function definition file not found"
# in non-interactive eval contexts where $fpath doesn't yet include the
# prezto utility module's functions directory. Defining a real function
# here bypasses the autoload path entirely.
function diff {
if (( $+commands[colordiff] )); then
command diff --unified "$@" | colordiff --difftype diffu
else
command diff --unified "$@"
fi
}
+33
View File
@@ -0,0 +1,33 @@
# zsh/lolcat.zsh (drunkendotfiles) — auto-sourced via ~/.zshrc: for f in ~/.yadr/zsh/*.zsh
# Rainbow-output helpers built on lolcat = Debian's busyloop Ruby build at
# /usr/games/lolcat (upstream github.com/busyloop/lolcat; 24-bit truecolor).
# It auto-detects a tty, so use -f/--force-color to colorize mid-pipeline.
# This lolcat is truecolor and auto-detects a tty: it colorizes when writing
# straight to the terminal, but passes text through UNcolored when piped onward,
# so use -f/--force to colorize in the middle of a pipeline.
# Debian ships lolcat in /usr/games; make sure it's reachable in any shell.
[[ ":$PATH:" == *":/usr/games:"* ]] || export PATH="$PATH:/usr/games"
# --- opt-in: prefix ANY command to rainbow its output on the terminal --------
# lol ls -C lol fastfetch lol git log --oneline
# (The wrapped command sees a pipe, not a tty, so some tools drop their own
# colors/columns -- e.g. use `lol ls -C` to keep ls in columns.)
lol() { "$@" | lolcat; }
# Same, but force color so it survives further down a pipeline:
# lolf git diff | less -R
lolf() { "$@" | lolcat -f; }
# --- handy rainbow shortcuts for plain-text output ---------------------------
rcat() { lolcat "$@"; } # rcat file.txt (or: some-cmd | rcat)
rls() { ls -C "$@" | lolcat; } # rainbow ls, columns preserved
rless() { lolcat -f | less -R; } # pipe into me: some-cmd | rless
# --- whole-session "rainbow everything" toggle (NOVELTY) ---------------------
# Pipes the shell's stdout through lolcat until turned off. It WILL garble
# full-screen/interactive programs (vim, less, htop, fzf, ssh) and your prompt,
# and buffers streaming output. Use it for a burst of plain command output,
# then rainbow_off. Does not affect stderr.
rainbow_on() { [[ -n $RAINBOW_PIPE ]] && return; exec 3>&1; exec > >(lolcat -f); export RAINBOW_PIPE=1; }
rainbow_off() { [[ -z $RAINBOW_PIPE ]] && return; exec 1>&3 3>&-; unset RAINBOW_PIPE; }