Compare commits
18
Commits
925c71cbaa
..
main
No files matched your search
@@ -0,0 +1,7 @@
|
|||||||
|
## Overrides only; all defaults: `atuin default-config`
|
||||||
|
|
||||||
|
## brew/pacman handle updates; no version check against api.atuin.sh
|
||||||
|
update_check = false
|
||||||
|
|
||||||
|
## Enter puts the command on the prompt for editing (like fzf) instead of running it
|
||||||
|
enter_accept = false
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Loaded via RIPGREP_CONFIG_PATH (zsh/.zshrc). Hidden dirs (.venv, .claude,
|
||||||
|
# .codex) are skipped by default. -uu doesn't undo the globs: use --no-config.
|
||||||
|
--smart-case
|
||||||
|
--glob=!*venv/
|
||||||
|
--glob=!node_modules/
|
||||||
|
--glob=!__pycache__/
|
||||||
@@ -21,9 +21,9 @@ Practical rule: **edit the `.example` source, not the generated symlink target.*
|
|||||||
|
|
||||||
## Component architecture
|
## Component architecture
|
||||||
|
|
||||||
- **zsh** (`zsh/.zshrc`): Powerlevel10k instant prompt + [antidote](https://github.com/mattmc3/antidote) plugin manager (plugin list in `zsh/.zsh_plugins.txt`). `.zshrc` sources optional layered configs if present: `.powerline_config`, `.user_config`, `.virtual_env_config.zsh`, `.mac_config.zsh`, `.local_config`. `update_dotfiles()` auto-`git pull`s this repo in the background on every shell start. Machine-local overrides belong in `.local_config` (not committed).
|
- **zsh** (`zsh/.zshrc`): Powerlevel10k instant prompt + [antidote](https://github.com/mattmc3/antidote) plugin manager (plugin list in `zsh/.zsh_plugins.txt`). `.zshrc` sources optional layered configs if present: `.powerline_config`, `.user_config`, `.virtual_env_config.zsh`, `.mac_config.zsh`, `.local_config`. `update_dotfiles()` auto-`git pull`s this repo in the background on every shell start. Machine-local overrides belong in `.local_config` (not committed). [atuin](https://github.com/atuinsh/atuin) records history with cwd/exit code and owns Ctrl-R (over fzf); its config is `.config/atuin/config.toml` via `ATUIN_CONFIG_DIR`, data stays in `~/.atuin`.
|
||||||
- **nvim** (`nvim/init.vim`): [vim-plug](https://github.com/junegunn/vim-plug), auto-bootstrapped on first launch (`:PlugInstall`). Python provider points at the `~/python-envs/neovim` virtualenv on Apple Silicon. `colors/` holds a large bundled colorscheme collection.
|
- **nvim** (`nvim/init.vim`): [vim-plug](https://github.com/junegunn/vim-plug), auto-bootstrapped on first launch (`:PlugInstall`). Python provider points at the `~/python-envs/neovim` virtualenv on Apple Silicon. `colors/` holds a large bundled colorscheme collection.
|
||||||
- **tmux** (`tmux/.tmux.conf`): TPM-style `plugins/`. `tmux/tmux_attach.sh` is an attach helper.
|
- **tmux** (`tmux/.tmux.conf`): TPM-style `plugins/`. `tmux/tmux_attach.sh` is an attach helper. On macOS, `.mac_config` binds `prefix+P` to `tmux/op_password_paste.zsh` (pastes a 1Password password into the pane, e.g. remote sudo; needs the `op` CLI with app integration).
|
||||||
- **alacritty** (`.config/alacritty/`): active theme selected via the `import = [...]` line in `alacritty.toml`.
|
- **alacritty** (`.config/alacritty/`): active theme selected via the `import = [...]` line in `alacritty.toml`.
|
||||||
- **gitconfig** (`gitconfig/gitconfig`): identity/behavior split by remote host using `includeIf "hasconfig:remote.*.url:..."` — `github`, `fhms` (fh-muenster), `murgi`, and `sit` (Fraunhofer) each load their own `*.gitconfig`. Change per-context email/signing in the matching include file, not the base config.
|
- **gitconfig** (`gitconfig/gitconfig`): identity/behavior split by remote host using `includeIf "hasconfig:remote.*.url:..."` — `github`, `fhms` (fh-muenster), `murgi`, and `sit` (Fraunhofer) each load their own `*.gitconfig`. Change per-context email/signing in the matching include file, not the base config.
|
||||||
|
|
||||||
@@ -33,5 +33,5 @@ Practical rule: **edit the `.example` source, not the generated symlink target.*
|
|||||||
|
|
||||||
## Maintenance
|
## Maintenance
|
||||||
|
|
||||||
- `./update_mac.sh` — macOS update runner. Default (no args) runs `--brew-update --cleanup --diagnostics --update-others`; other flags: `--system-update`, `--permission-fix` (strips Caskroom/App quarantine xattrs). Run `./update_mac.sh --help` for the list. `--update-others` also updates Alacritty from its verified upstream release, then runs `claude --update` and `Codex --update`.
|
- `./update_mac.sh` — macOS update runner. Default (no args) runs `--brew-update --cleanup --diagnostics --update-others`; other flags: `--system-update`, `--permission-fix` (strips Caskroom/App quarantine xattrs). Run `./update_mac.sh --help` for the list. `--update-others` also updates Alacritty from its verified upstream release and antidote plugins (not updated at shell start), tmux plugins (TPM) and nvim plugins (vim-plug, headless), cleaning plugins no longer in the config, then runs `claude --update` (+ marketplaces and user-scope plugins), `codex update` (+ Git plugin marketplaces), and `pi update` (incl. extensions) when installed, plus `skills update --global` (brew `skills`) for skills in `~/.agents/skills`. MCP servers need nothing: they're remote or launched via `npx …@latest`.
|
||||||
- `brew_autoupdate` — runs scheduled brew and Alacritty auto-updates.
|
- `brew_autoupdate` — runs scheduled brew and Alacritty auto-updates.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# hunk headers show the enclosing heading/section
|
||||||
|
*.md diff=markdown
|
||||||
|
gitconfig diff=ini
|
||||||
|
*.gitconfig diff=ini
|
||||||
|
*.ini diff=ini
|
||||||
|
*.toml diff=ini
|
||||||
@@ -26,6 +26,8 @@ email = github@murgi.de
|
|||||||
path = ~/dotfiles/gitconfig/sit.gitconfig
|
path = ~/dotfiles/gitconfig/sit.gitconfig
|
||||||
[core]
|
[core]
|
||||||
excludesfile = ~/dotfiles/.gitignore_global
|
excludesfile = ~/dotfiles/.gitignore_global
|
||||||
|
attributesfile = ~/dotfiles/gitconfig/attributes
|
||||||
|
pager = delta
|
||||||
[submodule]
|
[submodule]
|
||||||
recurse = true
|
recurse = true
|
||||||
[filter "lfs"]
|
[filter "lfs"]
|
||||||
@@ -37,3 +39,24 @@ email = github@murgi.de
|
|||||||
autoStash = true
|
autoStash = true
|
||||||
[pull]
|
[pull]
|
||||||
rebase = true
|
rebase = true
|
||||||
|
[interactive]
|
||||||
|
diffFilter = delta --color-only
|
||||||
|
[diff]
|
||||||
|
colorMoved = default
|
||||||
|
[delta]
|
||||||
|
navigate = true
|
||||||
|
; plain look: +/- markers, line backgrounds (auto light/dark), no syntax colors
|
||||||
|
keep-plus-minus-markers = true
|
||||||
|
syntax-theme = none
|
||||||
|
file-style = bold
|
||||||
|
file-decoration-style = none
|
||||||
|
hunk-header-style = file syntax
|
||||||
|
hunk-header-decoration-style = none
|
||||||
|
tabs = 4
|
||||||
|
line-numbers = true
|
||||||
|
line-numbers-left-format =
|
||||||
|
line-numbers-right-format = "{np:>4} "
|
||||||
|
[diff "ini"]
|
||||||
|
xfuncname = "^\\[.*\\]"
|
||||||
|
[alias]
|
||||||
|
wsdiff = -c pager.diff='less -R' -c color.diff.old='red reverse' -c color.diff.new='green reverse' diff --word-diff=color --word-diff-regex='[^[:space:]]+|[[:space:]]+'
|
||||||
@@ -118,6 +118,10 @@ call plug#end()
|
|||||||
" Check for plugin updates after the editor is responsive.
|
" Check for plugin updates after the editor is responsive.
|
||||||
lua << EOF
|
lua << EOF
|
||||||
local function check_plugin_updates()
|
local function check_plugin_updates()
|
||||||
|
if vim.system == nil then
|
||||||
|
return -- needs nvim >= 0.10
|
||||||
|
end
|
||||||
|
|
||||||
local plugins = {}
|
local plugins = {}
|
||||||
for name, plugin in pairs(vim.g.plugs or {}) do
|
for name, plugin in pairs(vim.g.plugs or {}) do
|
||||||
if vim.fn.isdirectory(plugin.dir) == 1 then
|
if vim.fn.isdirectory(plugin.dir) == 1 then
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ set -e
|
|||||||
|
|
||||||
sudo pacman --needed -Sy archlinux-keyring --noconfirm
|
sudo pacman --needed -Sy archlinux-keyring --noconfirm
|
||||||
sudo pacman --needed -Syu --noconfirm
|
sudo pacman --needed -Syu --noconfirm
|
||||||
sudo pacman --needed -Sy base-devel gnome neovim zsh tmux openssh alacritty powerline-fonts otf-firamono-nerd prettier python-pip python-pynvim --noconfirm
|
sudo pacman --needed -Sy base-devel gnome neovim zsh tmux openssh alacritty powerline-fonts otf-firamono-nerd prettier python-pip python-pynvim atuin ripgrep --noconfirm
|
||||||
|
|
||||||
./clone_and_link.sh
|
./clone_and_link.sh
|
||||||
./copy_fonts_arch.sh
|
./copy_fonts_arch.sh
|
||||||
|
|||||||
+2
-2
@@ -6,8 +6,8 @@
|
|||||||
# Distributed under terms of the MIT license.
|
# Distributed under terms of the MIT license.
|
||||||
#
|
#
|
||||||
|
|
||||||
brew install neovim tmux coreutils cmake golang jq npm prettier virtualenvwrapper
|
brew install neovim tmux coreutils cmake golang jq npm prettier virtualenvwrapper fzf atuin git-delta ripgrep skills
|
||||||
brew install --cask font-fira-mono-nerd-font
|
brew install --cask font-fira-mono-nerd-font 1password-cli
|
||||||
./install_alacritty_mac.sh
|
./install_alacritty_mac.sh
|
||||||
BREW_PREFIX="$(brew --prefix)"
|
BREW_PREFIX="$(brew --prefix)"
|
||||||
source "$BREW_PREFIX/bin/virtualenvwrapper.sh"
|
source "$BREW_PREFIX/bin/virtualenvwrapper.sh"
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
set-option -g default-shell /bin/zsh
|
set-option -g default-shell /bin/zsh
|
||||||
|
|
||||||
|
# prefix+P: paste a password from 1Password into the pane (e.g. remote sudo)
|
||||||
|
# (via run-shell: display-popup does not expand formats in its command)
|
||||||
|
bind P run-shell -b "tmux display-popup -c '#{client_name}' -E -w 80% -h 50% -T ' 1Password ' '$HOME/.tmux/op_password_paste.zsh #{pane_id} #{client_name}'"
|
||||||
#bind -Tcopy-mode-vi y send -X copy-pipe "pbcopy" \; display-message "copied to system clipboard"
|
#bind -Tcopy-mode-vi y send -X copy-pipe "pbcopy" \; display-message "copied to system clipboard"
|
||||||
#bind C-p run "tmux set-buffer \"$pbpaste\"; tmux paste-buffer"
|
#bind C-p run "tmux set-buffer \"$pbpaste\"; tmux paste-buffer"
|
||||||
#bind C-y run "tmux save-buffer - | pbcopy"
|
#bind C-y run "tmux save-buffer - | pbcopy"
|
||||||
@@ -43,6 +43,16 @@ bind - run-shell 'v="#{@venv}"; d="#{pane_current_path}"; if [ -n "$v" ]; then t
|
|||||||
# its global env carries one), regardless of what the source pane had.
|
# its global env carries one), regardless of what the source pane had.
|
||||||
bind c new-window -e VIRTUAL_ENV=
|
bind c new-window -e VIRTUAL_ENV=
|
||||||
|
|
||||||
|
# ssh panes: the shell sets #{@ssh_host} to the alias (see
|
||||||
|
# zsh/lib/interactive.zsh). Label them with the remote's title if it is a bare
|
||||||
|
# user@host (as our server zsh pins it), else with the alias; in the window
|
||||||
|
# name and, only in windows with an ssh pane, in the pane border.
|
||||||
|
set -g @ssh_label '#{?#{m/r:^[^@: ]+@[^@: ]+$,#{pane_title}},#{pane_title},#{@ssh_host}}'
|
||||||
|
set -g automatic-rename-format '#{?#{@ssh_host},#{=40:#{E:@ssh_label}},#{?pane_in_mode,[tmux],#{pane_current_command}}#{?pane_dead,[dead],}}'
|
||||||
|
set -g pane-border-format '#{?#{@ssh_host},#[bold] #{=60:#{E:@ssh_label}} #[default],}'
|
||||||
|
set-hook -g window-layout-changed \
|
||||||
|
'if -F "#{P:#{@ssh_host}}" "set -w pane-border-status top" "set -wu pane-border-status"'
|
||||||
|
|
||||||
# Switch windows
|
# Switch windows
|
||||||
bind-key -n M-Left select-window -t -1
|
bind-key -n M-Left select-window -t -1
|
||||||
bind-key -n M-Right select-window -t +1
|
bind-key -n M-Right select-window -t +1
|
||||||
|
|||||||
Executable
+92
@@ -0,0 +1,92 @@
|
|||||||
|
#!/bin/zsh
|
||||||
|
# Paste a password from 1Password into a tmux pane, e.g. at a remote sudo
|
||||||
|
# prompt. Run in a popup (see .mac_config):
|
||||||
|
# op_password_paste.zsh <pane_id> [client_name]
|
||||||
|
emulate -L zsh
|
||||||
|
setopt extended_glob pipe_fail no_unset
|
||||||
|
|
||||||
|
pane=${1:?usage: op_password_paste.zsh <pane_id> [client_name]}
|
||||||
|
client=${2:-}
|
||||||
|
# -l: messages may contain item titles, which must not be expanded as formats
|
||||||
|
die() {
|
||||||
|
print -ru2 -- "1Password: $*"
|
||||||
|
tmux display-message -l ${client:+-c} $client "1Password: $*"
|
||||||
|
# keep the popup (and op's error output) visible until a key is pressed
|
||||||
|
[[ -t 0 ]] && read -sk1 "?Press any key to close."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
(( $+commands[op] )) || die "op CLI missing (brew install --cask 1password-cli)"
|
||||||
|
|
||||||
|
# Guard: a paste outside a password prompt echoes the secret (and may run it).
|
||||||
|
# The cursor line must end in a prompt like "[sudo] password for x:".
|
||||||
|
cursor_line() {
|
||||||
|
local pos=$(tmux display-message -p -t $pane '#{cursor_x},#{cursor_y}')
|
||||||
|
print -r -- "$pos $(tmux capture-pane -p -t $pane -S ${pos#*,} -E ${pos#*,})"
|
||||||
|
}
|
||||||
|
prompt=$(cursor_line)
|
||||||
|
if [[ ${prompt#* } != *(#i)(password|passphrase|passwort|kennwort)*:[[:space:]]# ]]; then
|
||||||
|
print -r -- "No password prompt at the cursor:"
|
||||||
|
print -r -- " ${${prompt#* }:-<empty line>}"
|
||||||
|
read -q "?Paste anyway? [y/N] " || exit 0
|
||||||
|
print
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Destination of an ssh running in the pane, used as the initial fzf query.
|
||||||
|
ssh_host() {
|
||||||
|
local -a words=(${(z)1})
|
||||||
|
local w i
|
||||||
|
[[ ${words[1]:t} == ssh ]] || return 1
|
||||||
|
for (( i = 2; i <= $#words; i++ )); do
|
||||||
|
w=${words[i]}
|
||||||
|
if [[ $w == -- ]]; then
|
||||||
|
w=${words[i+1]:-}
|
||||||
|
break
|
||||||
|
elif [[ $w == -?* ]]; then
|
||||||
|
# option letters taking an argument; the last letter may take the next word
|
||||||
|
[[ $w == -[^BbcDEeFIiJLlmOoPpQRSWw]#[BbcDEeFIiJLlmOoPpQRSWw] ]] && (( i++ ))
|
||||||
|
else
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
w=${${${w#ssh://}#*@}%%/*}
|
||||||
|
w=${w%:[0-9]##}
|
||||||
|
[[ -n $w ]] && print -r -- $w
|
||||||
|
}
|
||||||
|
|
||||||
|
host=
|
||||||
|
tty=$(tmux display-message -p -t $pane '#{pane_tty}')
|
||||||
|
for args in ${(f)"$(ps -o args= -t ${tty#/dev/} 2>/dev/null)"}; do
|
||||||
|
host=$(ssh_host $args) && break
|
||||||
|
done
|
||||||
|
|
||||||
|
# All signed-in accounts; the desktop app integration asks for Touch ID.
|
||||||
|
accounts=(${(f)"$(op account list --format json | jq -r '.[].account_uuid')"}) ||
|
||||||
|
die "op account list failed"
|
||||||
|
(( $#accounts )) || die "no 1Password account (enable CLI integration in the app)"
|
||||||
|
rows=$(for acc in $accounts; do
|
||||||
|
op item list --account $acc --categories Login,Password,Server --format json |
|
||||||
|
jq -r --arg acc $acc '.[] | [$acc, .vault.id, .id, .title,
|
||||||
|
(.additional_information // ""), .vault.name,
|
||||||
|
([.urls[]?.href] | join(" "))] | @tsv' || exit 1
|
||||||
|
done) || die "op item list failed for an account"
|
||||||
|
[[ -n $rows ]] || die "no Login/Password/Server items found"
|
||||||
|
|
||||||
|
# The prefill comes from the local ssh; after another hop it names the wrong host.
|
||||||
|
choice=$(print -r -- $rows | fzf --delimiter='\t' --with-nth=4.. --reverse \
|
||||||
|
--query=$host --prompt='password> ' \
|
||||||
|
--header="paste into $pane${host:+ (local ssh: $host)}") || exit 0
|
||||||
|
fields=("${(@ps:\t:)choice}")
|
||||||
|
|
||||||
|
pw=$(op read --account $fields[1] "op://$fields[2]/$fields[3]/password") ||
|
||||||
|
die "no 'password' field in ${fields[4]}"
|
||||||
|
|
||||||
|
# Named buffer, deleted by paste-buffer -d; no clipboard (no load-buffer -w).
|
||||||
|
buf=op-password-$$
|
||||||
|
trap 'tmux delete-buffer -b $buf 2>/dev/null' EXIT
|
||||||
|
print -rn -- $pw | tmux load-buffer -b $buf -
|
||||||
|
pw=
|
||||||
|
# Picking and Touch ID take a while: refuse if the prompt moved meanwhile
|
||||||
|
# (sudo timeout, dropped connection).
|
||||||
|
[[ "$(cursor_line)" == "$prompt" ]] || die "pane changed since the check, not pasted"
|
||||||
|
tmux paste-buffer -d -b $buf -t $pane
|
||||||
+39
-3
@@ -63,17 +63,31 @@ function update_others {
|
|||||||
echo "Update other stuff"
|
echo "Update other stuff"
|
||||||
echo "----------"
|
echo "----------"
|
||||||
|
|
||||||
echo "-- ALACRITTY"
|
|
||||||
"$SCRIPT_DIR/install_alacritty_mac.sh" || echo "Alacritty update failed." >&2
|
|
||||||
|
|
||||||
if [ -x "$(command -v claude)" ]; then
|
if [ -x "$(command -v claude)" ]; then
|
||||||
echo "-- CLAUDE"
|
echo "-- CLAUDE"
|
||||||
claude --update
|
claude --update
|
||||||
|
echo "-- CLAUDE PLUGINS"
|
||||||
|
claude plugin marketplace update
|
||||||
|
# No pipe into the loop: update must keep the terminal as stdin for its
|
||||||
|
# confirm prompt (bun's kqueue rejects a `< /dev/tty` redirect)
|
||||||
|
plugins=$(claude plugin list --json \
|
||||||
|
| python3 -c 'import json, sys; print(*(p["id"] for p in json.load(sys.stdin) if p["scope"] == "user"))')
|
||||||
|
for plugin in $plugins; do
|
||||||
|
claude plugin update --scope user "$plugin"
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -x "$(command -v codex)" ]; then
|
if [ -x "$(command -v codex)" ]; then
|
||||||
echo "-- CODEX"
|
echo "-- CODEX"
|
||||||
codex update
|
codex update
|
||||||
|
echo "-- CODEX PLUGINS"
|
||||||
|
codex plugin marketplace upgrade
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Skills installed via the skills CLI (shared by Claude, Codex, ...)
|
||||||
|
if [ -f "$HOME/.agents/.skill-lock.json" ] && [ -x "$(command -v skills)" ]; then
|
||||||
|
echo "-- SKILLS"
|
||||||
|
skills update --global --yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -x "$(command -v pi)" ]; then
|
if [ -x "$(command -v pi)" ]; then
|
||||||
@@ -81,6 +95,28 @@ function update_others {
|
|||||||
pi update
|
pi update
|
||||||
pi update --extensions
|
pi update --extensions
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "-- ALACRITTY"
|
||||||
|
"$SCRIPT_DIR/install_alacritty_mac.sh" || echo "Alacritty update failed." >&2
|
||||||
|
|
||||||
|
if [ -f "$HOME/.antidote/antidote.zsh" ]; then
|
||||||
|
echo "-- ANTIDOTE"
|
||||||
|
zsh "$HOME/.antidote/antidote.zsh" update
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -x "$HOME/.tmux/plugins/tpm/bin/update_plugins" ]; then
|
||||||
|
echo "-- TMUX PLUGINS"
|
||||||
|
"$HOME/.tmux/plugins/tpm/bin/clean_plugins"
|
||||||
|
"$HOME/.tmux/plugins/tpm/bin/update_plugins" all
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -x "$(command -v nvim)" ]; then
|
||||||
|
echo "-- NVIM PLUGINS"
|
||||||
|
# Headless vim-plug only logs to its buffer; print it
|
||||||
|
nvim --headless -c 'PlugClean!' -c 'PlugUpgrade' -c 'PlugUpdate --sync' \
|
||||||
|
-c 'lua io.write("\n", table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), "\n"), "\n")' \
|
||||||
|
-c 'qa'
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ $* == *--help* ]]; then
|
if [[ $* == *--help* ]]; then
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
export LC_ALL=en_US.UTF-8
|
export LC_ALL=en_US.UTF-8
|
||||||
export LANG=en_US.UTF-8
|
export LANG=en_US.UTF-8
|
||||||
export JAVA_HOME=`/usr/libexec/java_home`
|
# deps: system/user JDK dirs, which change when a JDK is added or removed
|
||||||
defaults write .GlobalPreferences AppleLocale en_DE
|
_zsh_cached java_home /Library/Java/JavaVirtualMachines ~/Library/Java/JavaVirtualMachines \
|
||||||
|
-- /usr/libexec/java_home && read -r JAVA_HOME < $REPLY && export JAVA_HOME
|
||||||
|
# macOS resets this on updates (and at random); background it, it's slow
|
||||||
|
defaults write .GlobalPreferences AppleLocale en_DE &!
|
||||||
|
|
||||||
# Set path to work with pycharm ...
|
# Set path to work with pycharm ...
|
||||||
# [[ "$PATH" =~ /usr/local/bin ]] || export PATH=$PATH:/usr/local/bin
|
# [[ "$PATH" =~ /usr/local/bin ]] || export PATH=$PATH:/usr/local/bin
|
||||||
@@ -27,7 +30,7 @@ alias tailscale=/Applications/Tailscale.app/Contents/MacOS/Tailscale
|
|||||||
#alias virt-manager="LD_PRELOAD=/opt/homebrew/Cellar/glib/2.86.0/lib virt-manager"
|
#alias virt-manager="LD_PRELOAD=/opt/homebrew/Cellar/glib/2.86.0/lib virt-manager"
|
||||||
#alias virt-manager="LD_PRELOAD=/opt/homebrew/Cellar/glib/2.86.0/lib $HOME/python-envs/virt-manager/bin/python3 $HOME/stuff/virt-manager/virt-manager"
|
#alias virt-manager="LD_PRELOAD=/opt/homebrew/Cellar/glib/2.86.0/lib $HOME/python-envs/virt-manager/bin/python3 $HOME/stuff/virt-manager/virt-manager"
|
||||||
|
|
||||||
HOMEBREW_COMMAND_NOT_FOUND_HANDLER="$(brew --repository)/Library/Homebrew/command-not-found/handler.sh"
|
HOMEBREW_COMMAND_NOT_FOUND_HANDLER="${HOMEBREW_REPOSITORY:-$(brew --repository)}/Library/Homebrew/command-not-found/handler.sh"
|
||||||
if [ -f "$HOMEBREW_COMMAND_NOT_FOUND_HANDLER" ]; then
|
if [ -f "$HOMEBREW_COMMAND_NOT_FOUND_HANDLER" ]; then
|
||||||
source "$HOMEBREW_COMMAND_NOT_FOUND_HANDLER";
|
source "$HOMEBREW_COMMAND_NOT_FOUND_HANDLER";
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
phpenv # php version from phpenv (https://github.com/phpenv/phpenv)
|
phpenv # php version from phpenv (https://github.com/phpenv/phpenv)
|
||||||
scalaenv # scala version from scalaenv (https://github.com/scalaenv/scalaenv)
|
scalaenv # scala version from scalaenv (https://github.com/scalaenv/scalaenv)
|
||||||
haskell_stack # haskell version from stack (https://haskellstack.org/)
|
haskell_stack # haskell version from stack (https://haskellstack.org/)
|
||||||
kubecontext # current kubernetes context (https://kubernetes.io/)
|
# kubecontext # off: runs kubectl on each shell's first prompt, even when hidden
|
||||||
terraform # terraform workspace (https://www.terraform.io)
|
terraform # terraform workspace (https://www.terraform.io)
|
||||||
# terraform_version # terraform version (https://www.terraform.io)
|
# terraform_version # terraform version (https://www.terraform.io)
|
||||||
aws # aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html)
|
aws # aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html)
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ fi
|
|||||||
export WORKON_HOME=~/python-envs
|
export WORKON_HOME=~/python-envs
|
||||||
export VIRTUALENVWRAPPER_VIRTUALENV=$PREFIX/bin/virtualenv
|
export VIRTUALENVWRAPPER_VIRTUALENV=$PREFIX/bin/virtualenv
|
||||||
mkdir -p $WORKON_HOME
|
mkdir -p $WORKON_HOME
|
||||||
source $PREFIX/bin/virtualenvwrapper.sh
|
source $PREFIX/bin/virtualenvwrapper_lazy.sh
|
||||||
|
|
||||||
# NOTE: an inherited VIRTUAL_ENV is *not* re-activated here — that happens at the
|
# NOTE: an inherited VIRTUAL_ENV is *not* re-activated here — that happens at the
|
||||||
# very end of .zshrc so activate captures the fully-built PATH (see the comment
|
# very end of .zshrc so activate captures the fully-built PATH (see the comment
|
||||||
# there). Sourcing virtualenvwrapper.sh above only defines workon/deactivate/etc.
|
# there). virtualenvwrapper initializes when a command such as workon is used.
|
||||||
|
|
||||||
# Mirror the current venv into a per-pane tmux option so that splitting a pane
|
# Mirror the current venv into a per-pane tmux option so that splitting a pane
|
||||||
# can carry it into the new pane (.tmux.conf reads #{@venv} with `-e`). Per-pane
|
# can carry it into the new pane (.tmux.conf reads #{@venv} with `-e`). Per-pane
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
# Load OMZ plugins
|
# Load OMZ lib and plugins; not oh-my-zsh.sh itself (own compinit, theme, update check)
|
||||||
ohmyzsh/ohmyzsh
|
|
||||||
ohmyzsh/ohmyzsh path:lib
|
ohmyzsh/ohmyzsh path:lib
|
||||||
ohmyzsh/ohmyzsh path:plugins/git
|
ohmyzsh/ohmyzsh path:plugins/git
|
||||||
ohmyzsh/ohmyzsh path:plugins/golang
|
ohmyzsh/ohmyzsh path:plugins/golang
|
||||||
|
|||||||
+75
-24
@@ -1,12 +1,48 @@
|
|||||||
# Powerlevel10k instant prompt and machine-local layers must remain first.
|
# First, so an interrupted startup (Ctrl-C) doesn't keep /etc/zshrc's
|
||||||
|
# SAVEHIST=1000 and truncate the history file on exit
|
||||||
|
HISTSIZE=100000
|
||||||
|
SAVEHIST=100000
|
||||||
|
setopt EXTENDED_HISTORY
|
||||||
|
|
||||||
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/startup.zsh"
|
||||||
|
[[ -d ${ZDOTDIR:-$HOME}/.cache/zsh ]] || mkdir -p ${ZDOTDIR:-$HOME}/.cache/zsh
|
||||||
|
|
||||||
|
# May ask for the key passphrase (once per boot), so it precedes instant prompt.
|
||||||
|
_in_coding_agent="$CLAUDECODE$CODEX_SESSION_ID$PI_CODING_AGENT"
|
||||||
|
if [[ -f ~/.ssh/sudo_key && -z $_in_coding_agent ]] &&
|
||||||
|
_zsh_cached sudo_key.fp ~/.ssh/sudo_key -- ssh-keygen -lf ~/.ssh/sudo_key; then
|
||||||
|
read -r _ _sudo_fp _ < $REPLY
|
||||||
|
[[ -e /tmp/sudo-agent.sock ]] || ssh-agent -a /tmp/sudo-agent.sock &>/dev/null
|
||||||
|
SSH_AUTH_SOCK=/tmp/sudo-agent.sock ssh-add -l | grep -q "$_sudo_fp" ||
|
||||||
|
SSH_AUTH_SOCK=/tmp/sudo-agent.sock ssh-add ~/.ssh/sudo_key
|
||||||
|
# agent forwarded by coding agents (see ~/.ssh/config): every signature,
|
||||||
|
# i.e. every remote sudo, needs confirmation via askpass
|
||||||
|
[[ -e /tmp/sudo-agent-confirm.sock ]] ||
|
||||||
|
SSH_ASKPASS=~/.ssh/askpass-agent-confirm.sh SSH_ASKPASS_REQUIRE=force \
|
||||||
|
ssh-agent -a /tmp/sudo-agent-confirm.sock &>/dev/null
|
||||||
|
SSH_AUTH_SOCK=/tmp/sudo-agent-confirm.sock ssh-add -l | grep -q "$_sudo_fp" ||
|
||||||
|
SSH_AUTH_SOCK=/tmp/sudo-agent-confirm.sock ssh-add -c ~/.ssh/sudo_key
|
||||||
|
unset _sudo_fp
|
||||||
|
fi
|
||||||
|
_zst_mark sudo-agent
|
||||||
|
|
||||||
|
# Powerlevel10k instant prompt; nothing below may need console input.
|
||||||
|
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
|
||||||
|
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
|
||||||
|
fi
|
||||||
|
_zst_mark instant-prompt
|
||||||
|
|
||||||
|
# Machine-local layers.
|
||||||
[[ -f ~/.zsh/.powerline_config ]] && source ~/.zsh/.powerline_config
|
[[ -f ~/.zsh/.powerline_config ]] && source ~/.zsh/.powerline_config
|
||||||
[[ -f ~/.zsh/.user_config ]] && source ~/.zsh/.user_config
|
[[ -f ~/.zsh/.user_config ]] && source ~/.zsh/.user_config
|
||||||
[[ -f ~/.zsh/.virtual_env_config.zsh ]] && source ~/.zsh/.virtual_env_config.zsh
|
[[ -f ~/.zsh/.virtual_env_config.zsh ]] && source ~/.zsh/.virtual_env_config.zsh
|
||||||
[[ -f ~/.zsh/.local_config ]] && source ~/.zsh/.local_config
|
[[ -f ~/.zsh/.local_config ]] && source ~/.zsh/.local_config
|
||||||
[[ -f ~/.zsh/.env.local ]] && source ~/.zsh/.env.local
|
[[ -f ~/.zsh/.env.local ]] && source ~/.zsh/.env.local
|
||||||
|
_zst_mark layers
|
||||||
|
|
||||||
source "${ZDOTDIR:-$HOME}/.zsh/lib/updates.zsh"
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/updates.zsh"
|
||||||
export LC_OSC52=1
|
export LC_OSC52=1
|
||||||
|
_zst_mark updates
|
||||||
|
|
||||||
# Completions for tools installed under ~/.local (e.g. tools-repo's safe*
|
# Completions for tools installed under ~/.local (e.g. tools-repo's safe*
|
||||||
# wrappers). Must precede antidote, whose completion plugin runs compinit.
|
# wrappers). Must precede antidote, whose completion plugin runs compinit.
|
||||||
@@ -15,17 +51,41 @@ fpath=("$HOME/.local/share/zsh/site-functions" $fpath)
|
|||||||
plugins_txt=${ZDOTDIR:-$HOME}/.zsh/.zsh_plugins.txt
|
plugins_txt=${ZDOTDIR:-$HOME}/.zsh/.zsh_plugins.txt
|
||||||
static_file=${ZDOTDIR:-$HOME}/.cache/zsh/.zsh_plugins.zsh
|
static_file=${ZDOTDIR:-$HOME}/.cache/zsh/.zsh_plugins.zsh
|
||||||
source "${ZDOTDIR:-$HOME}/.zsh/lib/antidote.zsh"
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/antidote.zsh"
|
||||||
|
_zst_mark antidote
|
||||||
source "${ZDOTDIR:-$HOME}/.zsh/lib/interactive.zsh"
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/interactive.zsh"
|
||||||
|
|
||||||
bindkey '^w' kill-region
|
bindkey '^w' kill-region
|
||||||
bindkey -v
|
bindkey -v
|
||||||
VI_MODE_SET_CURSOR=true
|
VI_MODE_SET_CURSOR=true
|
||||||
|
# fzf keys (Ctrl-R/Ctrl-T/Alt-C, **<Tab>); after bindkey -v so vi keymaps get them
|
||||||
|
(( $+commands[fzf] )) && _zsh_cached fzf.zsh ${commands[fzf]:A} -- fzf --zsh &&
|
||||||
|
source $REPLY
|
||||||
|
_zst_mark fzf
|
||||||
|
|
||||||
|
# atuin: history with cwd/exit code; after fzf so its Ctrl-R wins. Keeps up-arrow
|
||||||
|
# and ? (no Atuin AI).
|
||||||
|
if (( $+commands[atuin] )); then
|
||||||
|
export ATUIN_CONFIG_DIR=~/dotfiles/.config/atuin
|
||||||
|
_zsh_cached atuin.zsh ${commands[atuin]:A} $ATUIN_CONFIG_DIR/config.toml \
|
||||||
|
-- atuin init zsh --disable-up-arrow --disable-ai && source $REPLY
|
||||||
|
# no `atuin search` spawn per keystroke (autosuggest runs synchronously)
|
||||||
|
ZSH_AUTOSUGGEST_STRATEGY=(${ZSH_AUTOSUGGEST_STRATEGY:#atuin})
|
||||||
|
fi
|
||||||
|
_zst_mark atuin
|
||||||
|
|
||||||
|
export RIPGREP_CONFIG_PATH=~/dotfiles/.config/ripgrep/config
|
||||||
|
|
||||||
[[ -f ~/.zsh/.mac_config.zsh ]] && source ~/.zsh/.mac_config.zsh
|
[[ -f ~/.zsh/.mac_config.zsh ]] && source ~/.zsh/.mac_config.zsh
|
||||||
if (( $+commands[go] )); then
|
_zst_mark mac-config
|
||||||
export GOPATH="$(go env GOPATH 2>/dev/null)"
|
# deps: go binary and `go env -w` files (macOS, Linux)
|
||||||
[[ -n "$GOPATH" ]] && path+=("$GOPATH/bin")
|
if (( $+commands[go] )) && _zsh_cached gopath ${commands[go]:A} \
|
||||||
|
"$HOME/Library/Application Support/go/env" "${XDG_CONFIG_HOME:-$HOME/.config}/go/env" \
|
||||||
|
-- env -u GOPATH go env GOPATH; then
|
||||||
|
[[ -n $GOPATH ]] || read -r GOPATH < $REPLY
|
||||||
|
export GOPATH
|
||||||
|
path+=("$GOPATH/bin")
|
||||||
fi
|
fi
|
||||||
|
_zst_mark go
|
||||||
|
|
||||||
# Use safe wrappers after ~/.local/bin has been added to PATH.
|
# Use safe wrappers after ~/.local/bin has been added to PATH.
|
||||||
# Agent shells: </dev/null makes the prompt decline (exit 1) instead of blocking.
|
# Agent shells: </dev/null makes the prompt decline (exit 1) instead of blocking.
|
||||||
@@ -34,16 +94,13 @@ if [[ -n ${CLAUDECODE:-} || -n ${CODEX_SHELL:-} ]]; then
|
|||||||
fi
|
fi
|
||||||
(( $+commands[safecp] )) && alias cp="safecp${_safe_redir:-}"
|
(( $+commands[safecp] )) && alias cp="safecp${_safe_redir:-}"
|
||||||
(( $+commands[safemv] )) && alias mv="safemv${_safe_redir:-}"
|
(( $+commands[safemv] )) && alias mv="safemv${_safe_redir:-}"
|
||||||
|
(( $+commands[safeln] )) && alias ln="safeln${_safe_redir:-}"
|
||||||
(( $+commands[safescp] )) && alias scp="safescp${_safe_redir:-}"
|
(( $+commands[safescp] )) && alias scp="safescp${_safe_redir:-}"
|
||||||
unset _safe_redir
|
unset _safe_redir
|
||||||
|
|
||||||
if [[ -f ~/.ssh/sudo_key ]]; then
|
# no GUI password dialog for sudo from agent shells; a non-interactive sudo just fails
|
||||||
[[ -e /tmp/sudo-agent.sock ]] || ssh-agent -a /tmp/sudo-agent.sock &>/dev/null
|
[[ -z $_in_coding_agent ]] && export SUDO_ASKPASS=${commands[ssh-askpass]}
|
||||||
SSH_AUTH_SOCK=/tmp/sudo-agent.sock ssh-add -l |
|
unset _in_coding_agent
|
||||||
grep -q "$(ssh-keygen -lf ~/.ssh/sudo_key | awk '{print $2}')" ||
|
|
||||||
SSH_AUTH_SOCK=/tmp/sudo-agent.sock ssh-add ~/.ssh/sudo_key
|
|
||||||
fi
|
|
||||||
export SUDO_ASKPASS=$(command -v ssh-askpass)
|
|
||||||
|
|
||||||
if [[ -f ~/dotfiles/zsh/.p10k.mac.zsh ]]; then
|
if [[ -f ~/dotfiles/zsh/.p10k.mac.zsh ]]; then
|
||||||
p10k_config=~/dotfiles/zsh/.p10k.mac.zsh
|
p10k_config=~/dotfiles/zsh/.p10k.mac.zsh
|
||||||
@@ -51,26 +108,17 @@ else
|
|||||||
p10k_config=~/dotfiles/zsh/.p10k.zsh
|
p10k_config=~/dotfiles/zsh/.p10k.zsh
|
||||||
fi
|
fi
|
||||||
source "${ZDOTDIR:-$HOME}/.zsh/lib/prompt.zsh"
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/prompt.zsh"
|
||||||
|
_zst_mark prompt
|
||||||
|
|
||||||
alias screenshot_mode='powerlevel10k_plugin_unload; export PS1="$ "; python3 ~/.config/alacritty/screenshot_mode.py on'
|
alias screenshot_mode='powerlevel10k_plugin_unload; export PS1="$ "; python3 ~/.config/alacritty/screenshot_mode.py on'
|
||||||
alias screenshot_mode_off='prompt_powerlevel9k_setup; python3 ~/.config/alacritty/screenshot_mode.py off'
|
alias screenshot_mode_off='prompt_powerlevel9k_setup; python3 ~/.config/alacritty/screenshot_mode.py off'
|
||||||
antidote update &>/dev/null &|
|
|
||||||
|
|
||||||
[[ -d "$HOME/.lmstudio/bin" ]] && path+=("$HOME/.lmstudio/bin")
|
[[ -d "$HOME/.lmstudio/bin" ]] && path+=("$HOME/.lmstudio/bin")
|
||||||
[[ -d "$HOME/.runai/bin" ]] && path+=("$HOME/.runai/bin")
|
[[ -d "$HOME/.runai/bin" ]] && path+=("$HOME/.runai/bin")
|
||||||
runai_bin="$HOME/.runai/bin/runai"
|
runai_bin="$HOME/.runai/bin/runai"
|
||||||
runai_completion=${ZDOTDIR:-$HOME}/.cache/zsh/runai-completion.zsh
|
[[ -x "$runai_bin" ]] &&
|
||||||
if [[ -x "$runai_bin" ]]; then
|
_zsh_cached runai-completion.zsh "$runai_bin" -- "$runai_bin" --quiet completion zsh &&
|
||||||
if [[ ! -s "$runai_completion" || "$runai_bin" -nt "$runai_completion" ]]; then
|
source $REPLY
|
||||||
runai_completion_tmp="$runai_completion.$$.tmp"
|
|
||||||
if "$runai_bin" --quiet completion zsh >| "$runai_completion_tmp"; then
|
|
||||||
command mv -f "$runai_completion_tmp" "$runai_completion"
|
|
||||||
else
|
|
||||||
command rm -f "$runai_completion_tmp"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
[[ -s "$runai_completion" ]] && source "$runai_completion"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Keep this last: activate must snapshot the fully built PATH for deactivate.
|
# Keep this last: activate must snapshot the fully built PATH for deactivate.
|
||||||
typeset -U path PATH
|
typeset -U path PATH
|
||||||
@@ -80,3 +128,6 @@ if [[ -n "$VIRTUAL_ENV" && -f "$VIRTUAL_ENV/bin/activate" ]]; then
|
|||||||
source "$VIRTUAL_ENV/bin/activate"
|
source "$VIRTUAL_ENV/bin/activate"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
_zst_mark rest
|
||||||
|
autoload -Uz add-zsh-hook
|
||||||
|
add-zsh-hook precmd _zst_report
|
||||||
@@ -4,9 +4,27 @@ if [[ ! -e ${ZDOTDIR:-$HOME}/.antidote ]]; then
|
|||||||
git clone https://github.com/mattmc3/antidote.git "${ZDOTDIR:-$HOME}/.antidote"
|
git clone https://github.com/mattmc3/antidote.git "${ZDOTDIR:-$HOME}/.antidote"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# OMZ lib/plugins without oh-my-zsh.sh, which would set these up
|
||||||
|
ZSH_CACHE_DIR=${ZDOTDIR:-$HOME}/.cache/zsh/omz
|
||||||
|
[[ -d $ZSH_CACHE_DIR/completions ]] || mkdir -p "$ZSH_CACHE_DIR/completions"
|
||||||
|
fpath=("$ZSH_CACHE_DIR/completions" $fpath)
|
||||||
|
# ssh-agent plugin keys its env file on this; HOST changes with VPN rDNS
|
||||||
|
SHORT_HOST=${HOST/.*/}
|
||||||
|
if [[ $OSTYPE == darwin* ]] && _zsh_cached short_host \
|
||||||
|
/Library/Preferences/SystemConfiguration/preferences.plist -- scutil --get LocalHostName; then
|
||||||
|
read -r SHORT_HOST < $REPLY
|
||||||
|
fi
|
||||||
|
# OMZ calls compdef before compinit (last plugin) has run: queue, replay below
|
||||||
|
typeset -ga _compdef_queue
|
||||||
|
compdef() { _compdef_queue+=("${(j: :)${(@q)@}}") }
|
||||||
|
|
||||||
zstyle ':completion:*:ssh:*' hosts off
|
zstyle ':completion:*:ssh:*' hosts off
|
||||||
zstyle ':completion:*:scp:*' hosts off
|
zstyle ':completion:*:scp:*' hosts off
|
||||||
zstyle ':completion:*:commands' rehash 1
|
zstyle ':completion:*:commands' rehash 1
|
||||||
|
|
||||||
source "${ZDOTDIR:-$HOME}/.antidote/antidote.zsh"
|
source "${ZDOTDIR:-$HOME}/.antidote/antidote.zsh"
|
||||||
antidote load "$plugins_txt" "$static_file"
|
antidote load "$plugins_txt" "$static_file"
|
||||||
|
if (( ${+_comps} )); then
|
||||||
|
for _c in $_compdef_queue; do eval "compdef $_c"; done
|
||||||
|
unset _c _compdef_queue
|
||||||
|
fi
|
||||||
@@ -108,3 +108,53 @@ pastefinish() {
|
|||||||
zstyle :bracketed-paste-magic paste-init pasteinit
|
zstyle :bracketed-paste-magic paste-init pasteinit
|
||||||
zstyle :bracketed-paste-magic paste-finish pastefinish
|
zstyle :bracketed-paste-magic paste-finish pastefinish
|
||||||
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste)
|
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste)
|
||||||
|
|
||||||
|
# Mirror the ssh destination into a per-pane tmux option; .tmux.conf labels ssh
|
||||||
|
# panes with it or the remote's user@host title.
|
||||||
|
_ssh_host_tmux() {
|
||||||
|
local -a set=(set -p -t $TMUX_PANE @ssh_host "$1")
|
||||||
|
[[ -n $1 ]] || set=(set -pu -t $TMUX_PANE @ssh_host)
|
||||||
|
tmux $set \; if -F -t $TMUX_PANE '#{P:#{@ssh_host}}' \
|
||||||
|
"set -w -t $TMUX_PANE pane-border-status top" \
|
||||||
|
"set -wu -t $TMUX_PANE pane-border-status" 2>/dev/null
|
||||||
|
}
|
||||||
|
_ssh_host_preexec() {
|
||||||
|
[[ -n $TMUX ]] || return
|
||||||
|
local -a w=(${(z)3}) # $2 is size-limited
|
||||||
|
while [[ $w[1] == *=* || $w[1] == (command|exec|noglob|nocorrect) ]]; do shift w; done
|
||||||
|
[[ ${w[1]:t} == ssh ]] || return
|
||||||
|
shift w
|
||||||
|
local host opt
|
||||||
|
while (( $#w )); do
|
||||||
|
case ${(Q)w[1]} in
|
||||||
|
--) host=${(Q)w[2]}; break ;;
|
||||||
|
-?*)
|
||||||
|
# option cluster; stop at the first flag that takes an argument
|
||||||
|
opt=${(Q)w[1]#-}; shift w
|
||||||
|
while [[ -n $opt ]]; do
|
||||||
|
if [[ $opt[1] == [BbcDEeFIiJLlmOoPpRSWw] ]]; then
|
||||||
|
[[ -n ${opt:1} ]] || shift w
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
opt=${opt:1}
|
||||||
|
done ;;
|
||||||
|
*) host=${(Q)w[1]}; break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[[ $host == ssh://* ]] && host=${${host#ssh://}%:<->}
|
||||||
|
host=${host##*@}
|
||||||
|
[[ -n $host ]] || return
|
||||||
|
_ssh_host_tmux $host
|
||||||
|
_ssh_host_set=1
|
||||||
|
# title the pane with the alias until the remote sets one; runs after
|
||||||
|
# OMZ's preexec, so this replaces its "ssh ..." title
|
||||||
|
print -rn -- $'\e]2;'"$host"$'\e\\'
|
||||||
|
}
|
||||||
|
_ssh_host_precmd() {
|
||||||
|
(( ${_ssh_host_set:-0} )) || return
|
||||||
|
_ssh_host_tmux ''
|
||||||
|
_ssh_host_set=0
|
||||||
|
}
|
||||||
|
autoload -Uz add-zsh-hook
|
||||||
|
add-zsh-hook preexec _ssh_host_preexec
|
||||||
|
add-zsh-hook precmd _ssh_host_precmd
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# Startup helpers: output caching and slow-start logging.
|
||||||
|
|
||||||
|
zmodload zsh/datetime
|
||||||
|
zmodload -F zsh/stat b:zstat
|
||||||
|
|
||||||
|
# Cache a command's output; regenerate when a dependency's resolved path or
|
||||||
|
# mtime changes (brew upgrades swap Cellar paths but keep old mtimes).
|
||||||
|
# Usage: _zsh_cached <name> [dep...] -- <cmd...>; sets REPLY to the cache file.
|
||||||
|
_zsh_cached() {
|
||||||
|
local file=${ZDOTDIR:-$HOME}/.cache/zsh/$1 stamp old
|
||||||
|
local -a mt
|
||||||
|
shift
|
||||||
|
while [[ $# -gt 0 && $1 != -- ]]; do
|
||||||
|
mt=(); zstat -A mt +mtime -- $1 2>/dev/null
|
||||||
|
stamp+="${1:A}@${mt[1]:-none};"
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
shift
|
||||||
|
[[ -r $file.stamp ]] && read -r old < $file.stamp
|
||||||
|
if [[ ! -s $file || $old != $stamp ]]; then
|
||||||
|
local tmp=$file.$$.tmp
|
||||||
|
if "$@" >| $tmp 2>/dev/null && [[ -s $tmp ]]; then
|
||||||
|
command mv -f $tmp $file
|
||||||
|
print -r -- $stamp >| $file.stamp
|
||||||
|
else
|
||||||
|
command rm -f $tmp
|
||||||
|
[[ -s $file ]] || return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
REPLY=$file
|
||||||
|
}
|
||||||
|
|
||||||
|
# Slow-start log: per-step ms, written only if startup (until the first prompt)
|
||||||
|
# exceeds ZSH_STARTUP_LOG_MS. Diagnostic for cold starts; remove once resolved.
|
||||||
|
typeset -gF _zst_t0=$EPOCHREALTIME _zst_last=$EPOCHREALTIME
|
||||||
|
typeset -ga _zst_steps
|
||||||
|
_zst_mark() {
|
||||||
|
local ms
|
||||||
|
printf -v ms '%s=%.0f' $1 $(( (EPOCHREALTIME - _zst_last) * 1000 ))
|
||||||
|
_zst_steps+=($ms)
|
||||||
|
_zst_last=$EPOCHREALTIME
|
||||||
|
}
|
||||||
|
_zst_report() {
|
||||||
|
add-zsh-hook -d precmd _zst_report
|
||||||
|
_zst_mark precmd
|
||||||
|
local total=$(( (EPOCHREALTIME - _zst_t0) * 1000 ))
|
||||||
|
(( total >= ${ZSH_STARTUP_LOG_MS:-1000} )) || return 0
|
||||||
|
local ts login=0
|
||||||
|
strftime -s ts '%Y-%m-%dT%H:%M:%S' $EPOCHSECONDS
|
||||||
|
[[ -o login ]] && login=1
|
||||||
|
printf '%s total=%.0f tmux=%d login=%d | %s\n' $ts $total ${+TMUX} $login "$_zst_steps" \
|
||||||
|
>> ${ZDOTDIR:-$HOME}/.cache/zsh/startup-slow.log
|
||||||
|
}
|
||||||
Reference in new issue
Block a user