Compare commits
17
Commits
5b3b61e0e0
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
874a823d1e | ||
|
|
cc90b515c6 | ||
|
|
13ffdfdb04 | ||
|
|
67885075d3 | ||
|
|
9ffe78362e | ||
|
|
f5389de7b8 | ||
|
|
9e059859c6 | ||
|
|
6f9e4910bb | ||
|
|
104b8e2d8d | ||
|
|
5cca1956fc | ||
|
|
4c5f988d92 | ||
|
|
7afa58f3ec | ||
|
|
7d97559b20 | ||
|
|
3e7a8d4f10 | ||
|
|
cb5c767ca2 | ||
|
|
81deaa75a4 | ||
|
|
7ccb268cfb |
@@ -61,3 +61,8 @@ y = 0
|
|||||||
key = "Return"
|
key = "Return"
|
||||||
mods = "Shift"
|
mods = "Shift"
|
||||||
chars = "\u001B\r"
|
chars = "\u001B\r"
|
||||||
|
|
||||||
|
[[keyboard.bindings]]
|
||||||
|
key = "Slash"
|
||||||
|
mods = "Control"
|
||||||
|
chars = "\u001F"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ This is a personal dotfiles repository targeting macOS (Apple Silicon + Intel) a
|
|||||||
|
|
||||||
Setup is platform-specific and runs from the repo root:
|
Setup is platform-specific and runs from the repo root:
|
||||||
|
|
||||||
- **macOS:** `./setup_mac.sh` — brews dependencies, creates a `neovim` virtualenv, then calls `./clone_and_link_mac.sh`. Uses GNU coreutils' `gln` (not `ln`), so coreutils must be installed first.
|
- **macOS:** `./setup_mac.sh` — brews dependencies, installs the latest verified upstream Alacritty release, creates a `neovim` virtualenv, then calls `./clone_and_link_mac.sh`. Uses GNU coreutils' `gln` (not `ln`), so coreutils must be installed first.
|
||||||
- **Arch:** `./setup_arch.sh` — pacman deps, then `./clone_and_link.sh` + `./copy_fonts_arch.sh`.
|
- **Arch:** `./setup_arch.sh` — pacman deps, then `./clone_and_link.sh` + `./copy_fonts_arch.sh`.
|
||||||
- `clone_and_link*.sh` create the symlinks (`~/.zsh`, `~/.zshrc`, `~/.tmux`, `~/.tmux.conf`, `~/.config/nvim`, `~/.config/alacritty`, virtualenvwrapper hooks). `link_config.sh` is a simpler standalone variant.
|
- `clone_and_link*.sh` create the symlinks (`~/.zsh`, `~/.zshrc`, `~/.tmux`, `~/.tmux.conf`, `~/.config/nvim`, `~/.config/alacritty`, virtualenvwrapper hooks). `link_config.sh` is a simpler standalone variant.
|
||||||
- `general_setup.sh` switches the login shell to zsh and triggers plugin installs.
|
- `general_setup.sh` switches the login shell to zsh and triggers plugin installs.
|
||||||
@@ -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 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, then runs `claude --update` and `Codex --update`.
|
||||||
- `brew_autoupdate` — sets up scheduled brew auto-updates.
|
- `brew_autoupdate` — runs scheduled brew and Alacritty auto-updates.
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ export HOMEBREW_LOGS='/Users/ising/Library/Logs/Homebrew'
|
|||||||
export SUDO_ASKPASS='/Users/ising/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate_sudo_gui'
|
export SUDO_ASKPASS='/Users/ising/Library/Application Support/com.github.domt4.homebrew-autoupdate/brew_autoupdate_sudo_gui'
|
||||||
defaults export com.apple.dock "/tmp/dock-layout.plist"
|
defaults export com.apple.dock "/tmp/dock-layout.plist"
|
||||||
/bin/date && /opt/homebrew/bin/brew update && /opt/homebrew/bin/brew upgrade --formula -v && /opt/homebrew/bin/brew upgrade --cask -v && /opt/homebrew/bin/brew cleanup && /usr/bin/open -g /opt/homebrew/Library/Taps/homebrew/homebrew-autoupdate/notifier/brew-autoupdate.app
|
/bin/date && /opt/homebrew/bin/brew update && /opt/homebrew/bin/brew upgrade --formula -v && /opt/homebrew/bin/brew upgrade --cask -v && /opt/homebrew/bin/brew cleanup && /usr/bin/open -g /opt/homebrew/Library/Taps/homebrew/homebrew-autoupdate/notifier/brew-autoupdate.app
|
||||||
|
/Users/ising/dotfiles/install_alacritty_mac.sh
|
||||||
defaults import com.apple.dock "/tmp/dock-layout.plist"
|
defaults import com.apple.dock "/tmp/dock-layout.plist"
|
||||||
killall dock
|
killall dock
|
||||||
|
|||||||
Executable
+265
@@ -0,0 +1,265 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
readonly RELEASE_API="https://api.github.com/repos/alacritty/alacritty/releases/latest"
|
||||||
|
readonly APPLICATIONS_DIR="/Applications"
|
||||||
|
readonly APP_NAME="Alacritty.app"
|
||||||
|
|
||||||
|
temp_dir=""
|
||||||
|
mount_point=""
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n "$mount_point" && -d "$mount_point" ]]; then
|
||||||
|
hdiutil detach "$mount_point" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
if [[ -n "$temp_dir" && -d "$temp_dir" ]]; then
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
|
die() {
|
||||||
|
echo "Alacritty update failed: $*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
require_command() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || die "required command not found: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
app_version() {
|
||||||
|
/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" \
|
||||||
|
"$1/Contents/Info.plist" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
version_is_newer() {
|
||||||
|
local left="${1%%-*}"
|
||||||
|
local right="${2%%-*}"
|
||||||
|
local left_major left_minor left_patch
|
||||||
|
local right_major right_minor right_patch
|
||||||
|
|
||||||
|
IFS=. read -r left_major left_minor left_patch <<< "$left"
|
||||||
|
IFS=. read -r right_major right_minor right_patch <<< "$right"
|
||||||
|
|
||||||
|
[[ "$left_major" =~ ^[0-9]+$ && "$left_minor" =~ ^[0-9]+$ && "$left_patch" =~ ^[0-9]+$ ]] || return 1
|
||||||
|
[[ "$right_major" =~ ^[0-9]+$ && "$right_minor" =~ ^[0-9]+$ && "$right_patch" =~ ^[0-9]+$ ]] || return 1
|
||||||
|
|
||||||
|
(( 10#$left_major > 10#$right_major )) && return 0
|
||||||
|
(( 10#$left_major < 10#$right_major )) && return 1
|
||||||
|
(( 10#$left_minor > 10#$right_minor )) && return 0
|
||||||
|
(( 10#$left_minor < 10#$right_minor )) && return 1
|
||||||
|
(( 10#$left_patch > 10#$right_patch ))
|
||||||
|
}
|
||||||
|
|
||||||
|
run_for_applications() {
|
||||||
|
if [[ -w "$APPLICATIONS_DIR" ]]; then
|
||||||
|
"$@"
|
||||||
|
else
|
||||||
|
sudo "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_link() {
|
||||||
|
local source="$1"
|
||||||
|
local destination="$2"
|
||||||
|
|
||||||
|
if [[ -e "$destination" && ! -L "$destination" ]]; then
|
||||||
|
die "will not replace non-symlink: $destination"
|
||||||
|
fi
|
||||||
|
ln -sfn "$source" "$destination"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_linkable() {
|
||||||
|
local destination="$1"
|
||||||
|
|
||||||
|
if [[ -e "$destination" && ! -L "$destination" ]]; then
|
||||||
|
die "will not replace non-symlink: $destination"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_shell_artifacts() {
|
||||||
|
local app="$1"
|
||||||
|
local brew_prefix="$2"
|
||||||
|
local resources="$app/Contents/Resources"
|
||||||
|
local source manpage section
|
||||||
|
|
||||||
|
for source in \
|
||||||
|
"$app/Contents/MacOS/alacritty" \
|
||||||
|
"$resources/completions/alacritty.bash" \
|
||||||
|
"$resources/completions/alacritty.fish" \
|
||||||
|
"$resources/completions/_alacritty" \
|
||||||
|
"$resources/61/alacritty" \
|
||||||
|
"$resources/61/alacritty-direct"; do
|
||||||
|
[[ -f "$source" ]] || die "required artifact is missing: ${source#"$app/"}"
|
||||||
|
done
|
||||||
|
|
||||||
|
assert_linkable "$brew_prefix/bin/alacritty"
|
||||||
|
assert_linkable "$brew_prefix/etc/bash_completion.d/alacritty"
|
||||||
|
assert_linkable "$brew_prefix/share/fish/vendor_completions.d/alacritty.fish"
|
||||||
|
assert_linkable "$brew_prefix/share/zsh/site-functions/_alacritty"
|
||||||
|
assert_linkable "$HOME/.terminfo/61/alacritty"
|
||||||
|
assert_linkable "$HOME/.terminfo/61/alacritty-direct"
|
||||||
|
|
||||||
|
for section in 1 5 7; do
|
||||||
|
for manpage in "$resources"/*."$section".gz; do
|
||||||
|
[[ -e "$manpage" ]] || continue
|
||||||
|
assert_linkable "$brew_prefix/share/man/man$section/${manpage##*/}"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
install_shell_artifacts() {
|
||||||
|
local app="$APPLICATIONS_DIR/$APP_NAME"
|
||||||
|
local resources="$app/Contents/Resources"
|
||||||
|
local brew_prefix="$1"
|
||||||
|
local manpage section
|
||||||
|
|
||||||
|
mkdir -p \
|
||||||
|
"$brew_prefix/bin" \
|
||||||
|
"$brew_prefix/etc/bash_completion.d" \
|
||||||
|
"$brew_prefix/share/fish/vendor_completions.d" \
|
||||||
|
"$brew_prefix/share/zsh/site-functions" \
|
||||||
|
"$brew_prefix/share/man/man1" \
|
||||||
|
"$brew_prefix/share/man/man5" \
|
||||||
|
"$brew_prefix/share/man/man7" \
|
||||||
|
"$HOME/.terminfo/61"
|
||||||
|
|
||||||
|
safe_link "$app/Contents/MacOS/alacritty" "$brew_prefix/bin/alacritty"
|
||||||
|
safe_link "$resources/completions/alacritty.bash" "$brew_prefix/etc/bash_completion.d/alacritty"
|
||||||
|
safe_link "$resources/completions/alacritty.fish" "$brew_prefix/share/fish/vendor_completions.d/alacritty.fish"
|
||||||
|
safe_link "$resources/completions/_alacritty" "$brew_prefix/share/zsh/site-functions/_alacritty"
|
||||||
|
safe_link "$resources/61/alacritty" "$HOME/.terminfo/61/alacritty"
|
||||||
|
safe_link "$resources/61/alacritty-direct" "$HOME/.terminfo/61/alacritty-direct"
|
||||||
|
|
||||||
|
for section in 1 5 7; do
|
||||||
|
for manpage in "$resources"/*."$section".gz; do
|
||||||
|
[[ -e "$manpage" ]] || continue
|
||||||
|
safe_link "$manpage" "$brew_prefix/share/man/man$section/${manpage##*/}"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_previous_app() {
|
||||||
|
local destination="$1"
|
||||||
|
local backup="$2"
|
||||||
|
|
||||||
|
run_for_applications rm -rf "$destination"
|
||||||
|
if [[ -d "$backup" ]]; then
|
||||||
|
run_for_applications /usr/bin/ditto "$backup" "$destination"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local destination="$APPLICATIONS_DIR/$APP_NAME"
|
||||||
|
local release_json latest_tag latest_version asset_name asset_url asset_digest
|
||||||
|
local expected_sha actual_sha dmg staged_app staged_version installed_version
|
||||||
|
local previous_app brew_prefix brew_managed=false
|
||||||
|
|
||||||
|
[[ "$(uname -s)" == "Darwin" ]] || die "this installer only supports macOS"
|
||||||
|
|
||||||
|
require_command brew
|
||||||
|
require_command curl
|
||||||
|
require_command jq
|
||||||
|
require_command hdiutil
|
||||||
|
require_command codesign
|
||||||
|
|
||||||
|
brew_prefix="$(brew --prefix)"
|
||||||
|
if brew list --cask alacritty >/dev/null 2>&1; then
|
||||||
|
brew_managed=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
temp_dir="$(mktemp -d "${TMPDIR:-/tmp}/alacritty-update.XXXXXX")"
|
||||||
|
release_json="$temp_dir/release.json"
|
||||||
|
|
||||||
|
curl --fail --location --silent --show-error --retry 3 \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||||
|
"$RELEASE_API" -o "$release_json"
|
||||||
|
|
||||||
|
latest_tag="$(jq -er '.tag_name' "$release_json")"
|
||||||
|
latest_version="${latest_tag#v}"
|
||||||
|
asset_name="Alacritty-${latest_tag}.dmg"
|
||||||
|
asset_url="$(jq -er --arg asset "$asset_name" \
|
||||||
|
'.assets[] | select(.name == $asset) | .browser_download_url' "$release_json")"
|
||||||
|
asset_digest="$(jq -er --arg asset "$asset_name" \
|
||||||
|
'.assets[] | select(.name == $asset) | .digest' "$release_json")"
|
||||||
|
|
||||||
|
[[ "$asset_digest" == sha256:* ]] || die "GitHub did not provide a SHA-256 digest for $asset_name"
|
||||||
|
expected_sha="$(printf '%s' "${asset_digest#sha256:}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
[[ "$expected_sha" =~ ^[[:xdigit:]]{64}$ ]] || die "invalid SHA-256 digest for $asset_name"
|
||||||
|
|
||||||
|
installed_version=""
|
||||||
|
if [[ -d "$destination" ]]; then
|
||||||
|
installed_version="$(app_version "$destination")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$installed_version" == "$latest_version" && "$brew_managed" == false ]]; then
|
||||||
|
validate_shell_artifacts "$destination" "$brew_prefix"
|
||||||
|
install_shell_artifacts "$brew_prefix"
|
||||||
|
echo "Alacritty $installed_version is already up to date."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ -n "$installed_version" ]] && version_is_newer "$installed_version" "$latest_version"; then
|
||||||
|
echo "Installed Alacritty $installed_version is newer than stable $latest_version; leaving it unchanged."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing Alacritty $latest_version from the upstream release."
|
||||||
|
dmg="$temp_dir/$asset_name"
|
||||||
|
curl --fail --location --silent --show-error --retry 3 "$asset_url" -o "$dmg"
|
||||||
|
|
||||||
|
actual_sha="$(shasum -a 256 "$dmg" | awk '{print $1}')"
|
||||||
|
[[ "$actual_sha" == "$expected_sha" ]] || die "SHA-256 mismatch for $asset_name"
|
||||||
|
|
||||||
|
mount_point="$temp_dir/mount"
|
||||||
|
mkdir -p "$mount_point"
|
||||||
|
hdiutil attach "$dmg" -nobrowse -readonly -mountpoint "$mount_point" >/dev/null
|
||||||
|
[[ -d "$mount_point/$APP_NAME" ]] || die "$APP_NAME is missing from $asset_name"
|
||||||
|
|
||||||
|
staged_app="$temp_dir/$APP_NAME"
|
||||||
|
/usr/bin/ditto "$mount_point/$APP_NAME" "$staged_app"
|
||||||
|
hdiutil detach "$mount_point" >/dev/null
|
||||||
|
mount_point=""
|
||||||
|
|
||||||
|
staged_version="$(app_version "$staged_app")"
|
||||||
|
[[ "$staged_version" == "$latest_version" ]] || die "release metadata says $latest_version, app says $staged_version"
|
||||||
|
codesign --verify --deep --strict "$staged_app" || die "the staged app has an invalid ad-hoc signature"
|
||||||
|
xattr -dr com.apple.quarantine "$staged_app" 2>/dev/null || true
|
||||||
|
validate_shell_artifacts "$staged_app" "$brew_prefix"
|
||||||
|
|
||||||
|
previous_app="$temp_dir/previous/$APP_NAME"
|
||||||
|
if [[ -d "$destination" ]]; then
|
||||||
|
mkdir -p "${previous_app%/*}"
|
||||||
|
/usr/bin/ditto "$destination" "$previous_app"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$brew_managed" == true ]]; then
|
||||||
|
echo "Migrating Alacritty away from the disabled Homebrew cask."
|
||||||
|
if ! brew uninstall --cask alacritty; then
|
||||||
|
restore_previous_app "$destination" "$previous_app"
|
||||||
|
install_shell_artifacts "$brew_prefix" || true
|
||||||
|
die "Homebrew could not uninstall its Alacritty cask"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! run_for_applications rm -rf "$destination" || \
|
||||||
|
! run_for_applications /usr/bin/ditto "$staged_app" "$destination"; then
|
||||||
|
restore_previous_app "$destination" "$previous_app"
|
||||||
|
die "could not install $destination"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! codesign --verify --deep --strict "$destination" || \
|
||||||
|
[[ "$(app_version "$destination")" != "$latest_version" ]]; then
|
||||||
|
restore_previous_app "$destination" "$previous_app"
|
||||||
|
die "installed app validation failed; restored the previous app"
|
||||||
|
fi
|
||||||
|
|
||||||
|
install_shell_artifacts "$brew_prefix"
|
||||||
|
echo "Alacritty $latest_version installed successfully."
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
||||||
|
main "$@"
|
||||||
|
fi
|
||||||
+130
-3
@@ -32,9 +32,6 @@ let g:loaded_perl_provider = 0
|
|||||||
call plug#begin()
|
call plug#begin()
|
||||||
|
|
||||||
if !exists('g:vscode')
|
if !exists('g:vscode')
|
||||||
" Warn about plugin updates
|
|
||||||
Plug 'semanser/vim-outdated-plugins'
|
|
||||||
|
|
||||||
" Powerline replacement
|
" Powerline replacement
|
||||||
Plug 'vim-airline/vim-airline'
|
Plug 'vim-airline/vim-airline'
|
||||||
Plug 'vim-airline/vim-airline-themes'
|
Plug 'vim-airline/vim-airline-themes'
|
||||||
@@ -112,6 +109,136 @@ endif
|
|||||||
|
|
||||||
call plug#end()
|
call plug#end()
|
||||||
|
|
||||||
|
" Check for plugin updates after the editor is responsive.
|
||||||
|
lua << EOF
|
||||||
|
local function check_plugin_updates()
|
||||||
|
local plugins = {}
|
||||||
|
for name, plugin in pairs(vim.g.plugs or {}) do
|
||||||
|
if vim.fn.isdirectory(plugin.dir) == 1 then
|
||||||
|
table.insert(plugins, { name = name, dir = plugin.dir })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort(plugins, function(a, b) return a.name < b.name end)
|
||||||
|
|
||||||
|
local next_plugin = 1
|
||||||
|
local active = 0
|
||||||
|
local finished = 0
|
||||||
|
local failures = 0
|
||||||
|
local updates = {}
|
||||||
|
local concurrency = 2
|
||||||
|
|
||||||
|
local function git_command(args)
|
||||||
|
local command = {}
|
||||||
|
if vim.fn.executable('ionice') == 1 then
|
||||||
|
vim.list_extend(command, { 'ionice', '-c', '3' })
|
||||||
|
end
|
||||||
|
if vim.fn.executable('nice') == 1 then
|
||||||
|
vim.list_extend(command, { 'nice', '-n', '10' })
|
||||||
|
end
|
||||||
|
table.insert(command, 'git')
|
||||||
|
vim.list_extend(command, args)
|
||||||
|
return command
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_airline_status(message)
|
||||||
|
vim.g.plugin_update_status = message
|
||||||
|
local marker = '%{get(g:,"plugin_update_status","")}'
|
||||||
|
local warning = vim.g.airline_section_warning or ''
|
||||||
|
if not string.find(warning, 'plugin_update_status', 1, true) then
|
||||||
|
vim.g.airline_section_warning = warning .. ' ' .. marker
|
||||||
|
end
|
||||||
|
if vim.fn.exists(':AirlineRefresh') == 2 then
|
||||||
|
vim.cmd('AirlineRefresh')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function report()
|
||||||
|
if #updates > 0 then
|
||||||
|
set_airline_status(string.format('[updates: %d]', #updates))
|
||||||
|
local message = string.format(
|
||||||
|
'%d plugin update%s available: %s',
|
||||||
|
#updates,
|
||||||
|
#updates == 1 and '' or 's',
|
||||||
|
table.concat(updates, ', ')
|
||||||
|
)
|
||||||
|
if failures > 0 then
|
||||||
|
message = message .. string.format(' (%d check%s failed)', failures, failures == 1 and '' or 's')
|
||||||
|
end
|
||||||
|
vim.notify(message, failures > 0 and vim.log.levels.WARN or vim.log.levels.INFO)
|
||||||
|
elseif failures > 0 then
|
||||||
|
set_airline_status('[update check failed]')
|
||||||
|
vim.notify(
|
||||||
|
string.format('Plugin update check incomplete: %d check%s failed', failures, failures == 1 and '' or 's'),
|
||||||
|
vim.log.levels.WARN
|
||||||
|
)
|
||||||
|
else
|
||||||
|
set_airline_status('')
|
||||||
|
vim.notify('All plugins up-to-date', vim.log.levels.INFO)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local pump
|
||||||
|
local function complete_one()
|
||||||
|
active = active - 1
|
||||||
|
finished = finished + 1
|
||||||
|
if finished == #plugins then
|
||||||
|
report()
|
||||||
|
else
|
||||||
|
pump()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function check_one(plugin)
|
||||||
|
active = active + 1
|
||||||
|
vim.system(
|
||||||
|
git_command({ '-C', plugin.dir, 'fetch', '--quiet', '--no-tags', 'origin' }),
|
||||||
|
{ text = true, timeout = 20000 },
|
||||||
|
vim.schedule_wrap(function(fetch_result)
|
||||||
|
if fetch_result.code ~= 0 then
|
||||||
|
failures = failures + 1
|
||||||
|
complete_one()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.system(
|
||||||
|
git_command({ '-C', plugin.dir, 'rev-list', '--count', 'HEAD..@{upstream}' }),
|
||||||
|
{ text = true, timeout = 5000 },
|
||||||
|
vim.schedule_wrap(function(count_result)
|
||||||
|
local count = tonumber(vim.trim(count_result.stdout or ''))
|
||||||
|
if count_result.code ~= 0 or count == nil then
|
||||||
|
failures = failures + 1
|
||||||
|
elseif count > 0 then
|
||||||
|
table.insert(updates, plugin.name)
|
||||||
|
end
|
||||||
|
complete_one()
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
pump = function()
|
||||||
|
while active < concurrency and next_plugin <= #plugins do
|
||||||
|
local plugin = plugins[next_plugin]
|
||||||
|
next_plugin = next_plugin + 1
|
||||||
|
check_one(plugin)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #plugins > 0 then
|
||||||
|
pump()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.api.nvim_create_autocmd('VimEnter', {
|
||||||
|
group = vim.api.nvim_create_augroup('plugin_update_check', { clear = true }),
|
||||||
|
once = true,
|
||||||
|
callback = function()
|
||||||
|
vim.defer_fn(check_plugin_updates, 1500)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
EOF
|
||||||
|
|
||||||
" Run PlugInstall if there are missing plugins
|
" Run PlugInstall if there are missing plugins
|
||||||
autocmd VimEnter * if len(filter(values(g:plugs), '!isdirectory(v:val.dir)'))
|
autocmd VimEnter * if len(filter(values(g:plugs), '!isdirectory(v:val.dir)'))
|
||||||
\| PlugInstall --sync | source $MYVIMRC
|
\| PlugInstall --sync | source $MYVIMRC
|
||||||
|
|||||||
+6
-4
@@ -6,14 +6,16 @@
|
|||||||
# Distributed under terms of the MIT license.
|
# Distributed under terms of the MIT license.
|
||||||
#
|
#
|
||||||
|
|
||||||
brew install neovim tmux alacritty coreutils cmake golang npm virtualenvwrapper
|
brew install neovim tmux coreutils cmake golang jq npm virtualenvwrapper
|
||||||
source /opt/homebrew/bin/virtualenvwrapper.sh
|
./install_alacritty_mac.sh
|
||||||
|
BREW_PREFIX="$(brew --prefix)"
|
||||||
|
source "$BREW_PREFIX/bin/virtualenvwrapper.sh"
|
||||||
mkvirtualenv neovim
|
mkvirtualenv neovim
|
||||||
pip3 install pynvim
|
pip3 install pynvim
|
||||||
npm install -g neovim
|
npm install -g neovim
|
||||||
echo For alacritty to work seemlessly with tmux, we will have to add '/usr/local/bin'\
|
echo For alacritty to work seamlessly with tmux, we will add the Homebrew bin directory\
|
||||||
to the path. This will require your root password.
|
to the path. This will require your root password.
|
||||||
sudo launchctl config user path /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
|
sudo launchctl config user path /usr/bin:/bin:/usr/sbin:/sbin:"$BREW_PREFIX/bin":/usr/local/bin
|
||||||
cp $PWD/nvim/scheme.vim.template $PWD/nvim/scheme.vim
|
cp $PWD/nvim/scheme.vim.template $PWD/nvim/scheme.vim
|
||||||
cp $PWD/.config/alacritty/schemes.yml.template $PWD/.config/alacritty/schemes.yml
|
cp $PWD/.config/alacritty/schemes.yml.template $PWD/.config/alacritty/schemes.yml
|
||||||
./clone_and_link_mac.sh
|
./clone_and_link_mac.sh
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# This file echoes a bunch of 24-bit color codes
|
|
||||||
# to the terminal to demonstrate its functionality.
|
|
||||||
# The foreground escape sequence is ^[38;2;<r>;<g>;<b>m
|
|
||||||
# The background escape sequence is ^[48;2;<r>;<g>;<b>m
|
|
||||||
# <r> <g> <b> range from 0 to 255 inclusive.
|
|
||||||
# The escape sequence ^[0m returns output to default
|
|
||||||
|
|
||||||
setBackgroundColor()
|
|
||||||
{
|
|
||||||
echo -en "\x1b[48;2;$1;$2;$3""m"
|
|
||||||
}
|
|
||||||
|
|
||||||
resetOutput()
|
|
||||||
{
|
|
||||||
echo -en "\x1b[0m\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Gives a color $1/255 % along HSV
|
|
||||||
# Who knows what happens when $1 is outside 0-255
|
|
||||||
# Echoes "$red $green $blue" where
|
|
||||||
# $red $green and $blue are integers
|
|
||||||
# ranging between 0 and 255 inclusive
|
|
||||||
rainbowColor()
|
|
||||||
{
|
|
||||||
let h=$1/43
|
|
||||||
let f=$1-43*$h
|
|
||||||
let t=$f*255/43
|
|
||||||
let q=255-t
|
|
||||||
|
|
||||||
if [ $h -eq 0 ]
|
|
||||||
then
|
|
||||||
echo "255 $t 0"
|
|
||||||
elif [ $h -eq 1 ]
|
|
||||||
then
|
|
||||||
echo "$q 255 0"
|
|
||||||
elif [ $h -eq 2 ]
|
|
||||||
then
|
|
||||||
echo "0 255 $t"
|
|
||||||
elif [ $h -eq 3 ]
|
|
||||||
then
|
|
||||||
echo "0 $q 255"
|
|
||||||
elif [ $h -eq 4 ]
|
|
||||||
then
|
|
||||||
echo "$t 0 255"
|
|
||||||
elif [ $h -eq 5 ]
|
|
||||||
then
|
|
||||||
echo "255 0 $q"
|
|
||||||
else
|
|
||||||
# execution should never reach here
|
|
||||||
echo "0 0 0"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in `seq 0 127`; do
|
|
||||||
setBackgroundColor $i 0 0
|
|
||||||
echo -en " "
|
|
||||||
done
|
|
||||||
resetOutput
|
|
||||||
for i in `seq 255 128`; do
|
|
||||||
setBackgroundColor $i 0 0
|
|
||||||
echo -en " "
|
|
||||||
done
|
|
||||||
resetOutput
|
|
||||||
|
|
||||||
for i in `seq 0 127`; do
|
|
||||||
setBackgroundColor 0 $i 0
|
|
||||||
echo -n " "
|
|
||||||
done
|
|
||||||
resetOutput
|
|
||||||
for i in `seq 255 128`; do
|
|
||||||
setBackgroundColor 0 $i 0
|
|
||||||
echo -n " "
|
|
||||||
done
|
|
||||||
resetOutput
|
|
||||||
|
|
||||||
for i in `seq 0 127`; do
|
|
||||||
setBackgroundColor 0 0 $i
|
|
||||||
echo -n " "
|
|
||||||
done
|
|
||||||
resetOutput
|
|
||||||
for i in `seq 255 128`; do
|
|
||||||
setBackgroundColor 0 0 $i
|
|
||||||
echo -n " "
|
|
||||||
done
|
|
||||||
resetOutput
|
|
||||||
|
|
||||||
for i in `seq 0 127`; do
|
|
||||||
setBackgroundColor `rainbowColor $i`
|
|
||||||
echo -n " "
|
|
||||||
done
|
|
||||||
resetOutput
|
|
||||||
for i in `seq 255 128`; do
|
|
||||||
setBackgroundColor `rainbowColor $i`
|
|
||||||
echo -n " "
|
|
||||||
done
|
|
||||||
resetOutput
|
|
||||||
|
|
||||||
@@ -1,5 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
SCRIPT_SOURCE="${BASH_SOURCE[0]}"
|
||||||
|
while [[ -L "$SCRIPT_SOURCE" ]]; do
|
||||||
|
SCRIPT_DIR="$(cd -P "$(dirname "$SCRIPT_SOURCE")" >/dev/null 2>&1 && pwd)"
|
||||||
|
SCRIPT_SOURCE="$(readlink "$SCRIPT_SOURCE")"
|
||||||
|
[[ "$SCRIPT_SOURCE" != /* ]] && SCRIPT_SOURCE="$SCRIPT_DIR/$SCRIPT_SOURCE"
|
||||||
|
done
|
||||||
|
SCRIPT_DIR="$(cd -P "$(dirname "$SCRIPT_SOURCE")" >/dev/null 2>&1 && pwd)"
|
||||||
|
|
||||||
ARCH=`uname -m`
|
ARCH=`uname -m`
|
||||||
if [[ $ARCH == "arm64" ]]; then
|
if [[ $ARCH == "arm64" ]]; then
|
||||||
PREFIX="/opt/homebrew/"
|
PREFIX="/opt/homebrew/"
|
||||||
@@ -55,6 +63,9 @@ 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
|
||||||
|
|||||||
@@ -3,3 +3,4 @@
|
|||||||
.p10k.zsh
|
.p10k.zsh
|
||||||
.p10k.mac.zsh
|
.p10k.mac.zsh
|
||||||
antigen/
|
antigen/
|
||||||
|
.env.local
|
||||||
|
|||||||
@@ -8,11 +8,16 @@ defaults write .GlobalPreferences AppleLocale en_DE
|
|||||||
|
|
||||||
ARCH=`uname -m`
|
ARCH=`uname -m`
|
||||||
if [[ $ARCH == "arm64" ]]; then
|
if [[ $ARCH == "arm64" ]]; then
|
||||||
HOMEBREWPREFIX="/opt/homebrew"
|
export HOMEBREW_PREFIX="/opt/homebrew"
|
||||||
else
|
else
|
||||||
HOMEBREWPREFIX="/usr/local"
|
export HOMEBREW_PREFIX="/usr/local"
|
||||||
fi
|
fi
|
||||||
export PATH="$HOMEBREWPREFIX/opt/coreutils/libexec/gnubin:$HOME/.local/bin:$HOMEBREWPREFIX/bin:$PATH:$HOMEBREWPREFIX/sbin"
|
export PATH="$HOMEBREW_PREFIX/opt/coreutils/libexec/gnubin:$HOME/.local/bin:$HOMEBREW_PREFIX/bin:$PATH:$HOMEBREW_PREFIX/sbin"
|
||||||
|
|
||||||
|
# macOS-specific completion functions.
|
||||||
|
fpath=("${ZDOTDIR:-$HOME}/.zsh/completions_mac" $fpath)
|
||||||
|
autoload -Uz _launchctl
|
||||||
|
compdef _launchctl launchctl
|
||||||
|
|
||||||
# test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh"
|
# test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh"
|
||||||
|
|
||||||
@@ -27,12 +32,13 @@ if [ -f "$HOMEBREW_COMMAND_NOT_FOUND_HANDLER" ]; then
|
|||||||
source "$HOMEBREW_COMMAND_NOT_FOUND_HANDLER";
|
source "$HOMEBREW_COMMAND_NOT_FOUND_HANDLER";
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export DYLD_FALLBACK_LIBRARY_PATH="$HOMEBREW_PREFIX/lib:${DYLD_FALLBACK_LIBRARY_PATH}"
|
export DYLD_FALLBACK_LIBRARY_PATH="$HOMEBREW_PREFIX/lib${DYLD_FALLBACK_LIBRARY_PATH:+:$DYLD_FALLBACK_LIBRARY_PATH}"
|
||||||
export GI_TYPELIB_PATH="$HOMEBREW_PREFIX/lib/girepository-1.0:${GI_TYPELIB_PATH}"
|
export GI_TYPELIB_PATH="$HOMEBREW_PREFIX/lib/girepository-1.0${GI_TYPELIB_PATH:+:$GI_TYPELIB_PATH}"
|
||||||
export PKG_CONFIG_PATH="$HOMEBREW_PREFIX/lib/pkgconfig:$HOMEBREW_PREFIX/share/pkgconfig:${PKG_CONFIG_PATH}"
|
export PKG_CONFIG_PATH="$HOMEBREW_PREFIX/lib/pkgconfig:$HOMEBREW_PREFIX/share/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
|
||||||
alias claude="workon claude; claude; deactivate"
|
|
||||||
alias python="python3"
|
alias python="python3"
|
||||||
|
|
||||||
# Tahoe 26 WindowServer bug: windows stay interactive but can't be moved by
|
# Tahoe 26 WindowServer bug: windows stay interactive but can't be moved by
|
||||||
# mouse or API until the window-management daemon is restarted (no logout).
|
# mouse or API until the window-management daemon is restarted (no logout).
|
||||||
alias unstick-windows="killall WindowManager"
|
alias unstick-windows="killall WindowManager"
|
||||||
|
|
||||||
|
alias resetdns="sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder"
|
||||||
|
|||||||
@@ -27,3 +27,49 @@ _venv_track_precmd() {
|
|||||||
}
|
}
|
||||||
autoload -Uz add-zsh-hook
|
autoload -Uz add-zsh-hook
|
||||||
add-zsh-hook precmd _venv_track_precmd
|
add-zsh-hook precmd _venv_track_precmd
|
||||||
|
|
||||||
|
# Which venv an agent shell should use: nearest .venv/venv walking up from $1
|
||||||
|
# (default $PWD, stopping above $HOME), else the shared fallback env.
|
||||||
|
_agent_venv_path() {
|
||||||
|
local d=${1:-$PWD} c
|
||||||
|
while [[ $d == */* && $d != $HOME ]]; do
|
||||||
|
for c in "$d/.venv" "$d/venv"; do
|
||||||
|
[[ -f $c/bin/activate ]] && { print -r -- "$c"; return 0 }
|
||||||
|
done
|
||||||
|
d=${d%/*}
|
||||||
|
done
|
||||||
|
[[ -f $HOME/python-envs/claude/bin/activate ]] && print -r -- "$HOME/python-envs/claude"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Agent shells source this file once per session, rooted at the project dir, and
|
||||||
|
# snapshot the result: CLAUDECODE marks Claude Code, CODEX_SHELL the ChatGPT/Codex
|
||||||
|
# desktop app. Only VIRTUAL_ENV is set here; the block at the end of .zshrc turns it
|
||||||
|
# into an activation once PATH is fully built. Terminal launches use the wrappers below.
|
||||||
|
if [[ -n ${CLAUDECODE:-} || -n ${CODEX_SHELL:-} ]] && [[ -z ${VIRTUAL_ENV:-} ]]; then
|
||||||
|
_venv=$(_agent_venv_path)
|
||||||
|
[[ -n $_venv ]] && export VIRTUAL_ENV=$_venv
|
||||||
|
unset _venv
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Claude Code takes PATH from its own process env: its shell snapshot writes
|
||||||
|
# `export PATH=` last, discarding whatever .zshrc built. So the venv has to be
|
||||||
|
# active *before* launch. The subshell keeps this shell's PATH untouched.
|
||||||
|
claude() {
|
||||||
|
if [[ -n ${VIRTUAL_ENV:-} ]]; then
|
||||||
|
command claude "$@"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
local v=$(_agent_venv_path)
|
||||||
|
( [[ -n $v ]] && source "$v/bin/activate"; exec command claude "$@" )
|
||||||
|
}
|
||||||
|
|
||||||
|
# Codex captures the profile's own PATH, so hand it VIRTUAL_ENV only and let the
|
||||||
|
# activation block at the end of .zshrc order PATH correctly. Pre-activating here
|
||||||
|
# would leave venv/bin behind gnubin and homebrew, same as tmux-inherited venvs.
|
||||||
|
codex() {
|
||||||
|
if [[ -n ${VIRTUAL_ENV:-} ]]; then
|
||||||
|
command codex "$@"
|
||||||
|
else
|
||||||
|
VIRTUAL_ENV=$(_agent_venv_path) command codex "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|||||||
+30
-197
@@ -1,212 +1,59 @@
|
|||||||
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
|
# Powerlevel10k instant prompt and machine-local layers must remain first.
|
||||||
# Initialization code that may require console input (password prompts, [y/n]
|
|
||||||
# confirmations, etc.) must go above this block; everything else may go below.
|
|
||||||
[[ -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
|
||||||
|
|
||||||
# On shell start, bring ~/dotfiles up to date by fast-forwarding the CURRENT
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/updates.zsh"
|
||||||
# branch to its upstream only. Never rebase or stash in the background: if the
|
|
||||||
# branch diverged or local edits block it, warn and leave it for a manual pull.
|
|
||||||
# Per-branch, so `server` on each device fast-forwards to origin/server.
|
|
||||||
update_dotfiles() {
|
|
||||||
local repo="$HOME/dotfiles"
|
|
||||||
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
|
||||||
local notice_file="$cache_dir/dotfiles-update-notice"
|
|
||||||
local notice_tmp="$notice_file.$$.tmp"
|
|
||||||
# Bound the network call so a stalled fetch can't wedge this backgrounded
|
|
||||||
# (&!) job into a days-long orphan holding unreaped children. `timeout` is
|
|
||||||
# absent on macOS, so only use it when present. Disable ssh multiplexing so
|
|
||||||
# no daemonized mux master can inherit and keep our fds open past git's exit.
|
|
||||||
local -a TO; (( $+commands[timeout] )) && TO=(timeout -k 5 15)
|
|
||||||
GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o ControlMaster=no -o ControlPath=none' \
|
|
||||||
$TO git -C "$repo" fetch --quiet </dev/null 2>/dev/null || return
|
|
||||||
git -C "$repo" rev-parse --abbrev-ref '@{u}' >/dev/null 2>&1 || return # no upstream
|
|
||||||
git -C "$repo" merge-base --is-ancestor '@{u}' HEAD 2>/dev/null && return # already current
|
|
||||||
git -C "$repo" merge --ff-only --quiet '@{u}' 2>/dev/null && return
|
|
||||||
local notice="⚠ dotfiles: $(git -C "$repo" symbolic-ref --short HEAD) can't fast-forward to @{u} — run: git -C ~/dotfiles pull"
|
|
||||||
mkdir -p "$cache_dir" || return
|
|
||||||
print -r -- "$notice" >| "$notice_tmp" || return
|
|
||||||
mv -f "$notice_tmp" "$notice_file"
|
|
||||||
}
|
|
||||||
|
|
||||||
update_dotfiles &!
|
|
||||||
|
|
||||||
# On shell start, check the security tools repo for upstream updates and queue a
|
|
||||||
# one-line notice if the checkout is behind. A precmd hook prints it between
|
|
||||||
# commands, rather than letting this background job write across other startup
|
|
||||||
# output or a prompt that is already being edited. Notify only (never auto-pull).
|
|
||||||
# The check stays read-only so it works even in root-owned /opt/tools:
|
|
||||||
# - `safe.directory=*` sidesteps git's "dubious ownership" refusal on a repo
|
|
||||||
# owned by root, which would otherwise fail every git command.
|
|
||||||
# - `ls-remote` queries the remote without writing into .git (a normal user
|
|
||||||
# can't write a root-owned .git, so `fetch` would fail there).
|
|
||||||
# Uses the first candidate that is a git checkout; covers global and per-user layouts.
|
|
||||||
check_tools_repo() {
|
|
||||||
local repo branch remote mergeref remote_sha local_sha cmd notice
|
|
||||||
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
|
||||||
local notice_file="$cache_dir/tools-update-notice"
|
|
||||||
local notice_tmp="$notice_file.$$.tmp"
|
|
||||||
# See update_dotfiles: bound the network probe (timeout, absent on macOS) and
|
|
||||||
# disable ssh multiplexing so a stalled ls-remote can't orphan this &! job.
|
|
||||||
local -a TO; (( $+commands[timeout] )) && TO=(timeout -k 5 10)
|
|
||||||
for repo in /opt/tools "$HOME/tools" "$HOME/tools/tools-repo"; do
|
|
||||||
local -a g=(git -c 'safe.directory=*' -C "$repo")
|
|
||||||
$g rev-parse --is-inside-work-tree >/dev/null 2>&1 || continue
|
|
||||||
branch=$($g symbolic-ref --short HEAD 2>/dev/null) || return
|
|
||||||
remote=$($g config "branch.$branch.remote" 2>/dev/null) || return # no upstream
|
|
||||||
mergeref=$($g config "branch.$branch.merge" 2>/dev/null) || return
|
|
||||||
remote_sha=$(GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o ControlMaster=no -o ControlPath=none' \
|
|
||||||
$TO $g ls-remote "$remote" "$mergeref" </dev/null 2>/dev/null | awk '{print $1}')
|
|
||||||
local_sha=$($g rev-parse HEAD 2>/dev/null)
|
|
||||||
[[ -n "$remote_sha" && -n "$local_sha" ]] || return # remote unreachable
|
|
||||||
[[ "$remote_sha" == "$local_sha" ]] && return # already current
|
|
||||||
$g merge-base --is-ancestor "$remote_sha" HEAD 2>/dev/null && return # remote is an ancestor: ahead/equal (also true if we lack the object -> falls through to "behind")
|
|
||||||
[[ -w "$repo/.git" ]] && cmd="git -C $repo pull" || cmd="sudo git -C $repo pull"
|
|
||||||
notice="⬆ tools: updates available in $repo — run: $cmd"
|
|
||||||
mkdir -p "$cache_dir" || return
|
|
||||||
print -r -- "$notice" >| "$notice_tmp" || return
|
|
||||||
mv -f "$notice_tmp" "$notice_file"
|
|
||||||
return
|
|
||||||
done
|
|
||||||
}
|
|
||||||
check_tools_repo &!
|
|
||||||
|
|
||||||
show_update_notices() {
|
|
||||||
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
|
||||||
local notice_file claimed_notice
|
|
||||||
for notice_file in "$cache_dir"/{dotfiles,tools}-update-notice; do
|
|
||||||
[[ -s "$notice_file" ]] || continue
|
|
||||||
claimed_notice="$notice_file.$$.show"
|
|
||||||
mv "$notice_file" "$claimed_notice" 2>/dev/null || continue
|
|
||||||
command cat "$claimed_notice"
|
|
||||||
command rm -f "$claimed_notice"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
autoload -Uz add-zsh-hook
|
|
||||||
add-zsh-hook precmd show_update_notices
|
|
||||||
|
|
||||||
export LC_OSC52=1
|
export LC_OSC52=1
|
||||||
|
|
||||||
# Load Antidote
|
# Completions for tools installed under ~/.local (e.g. tools-repo's safe*
|
||||||
mkdir -p ${ZDOTDIR:-~}/.cache/zsh
|
# wrappers). Must precede antidote, whose completion plugin runs compinit.
|
||||||
static_file=${ZDOTDIR:-~}/.cache/zsh/.zsh_plugins.zsh
|
fpath=("$HOME/.local/share/zsh/site-functions" $fpath)
|
||||||
plugins_txt=${ZDOTDIR:-~}/.zsh/.zsh_plugins.txt
|
|
||||||
# clone antidote if necessary
|
|
||||||
if ! [[ -e ${ZDOTDIR:-~}/.antidote ]]; then
|
|
||||||
git clone https://github.com/mattmc3/antidote.git ${ZDOTDIR:-~}/.antidote
|
|
||||||
fi
|
|
||||||
|
|
||||||
zstyle ':completion:*:ssh:*' hosts off
|
plugins_txt=${ZDOTDIR:-$HOME}/.zsh/.zsh_plugins.txt
|
||||||
zstyle ':completion:*:scp:*' hosts off
|
static_file=${ZDOTDIR:-$HOME}/.cache/zsh/.zsh_plugins.zsh
|
||||||
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/antidote.zsh"
|
||||||
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/interactive.zsh"
|
||||||
|
|
||||||
# Run rehash for external commands
|
bindkey '^w' kill-region
|
||||||
zstyle ":completion:*:commands" rehash 1
|
|
||||||
# source antidote and load plugins from `${ZDOTDIR:-~}/.zsh_plugins.txt`
|
|
||||||
source ${ZDOTDIR:-~}/.antidote/antidote.zsh
|
|
||||||
antidote load ${plugins_txt} ${static_file}
|
|
||||||
|
|
||||||
setopt interactivecomments
|
|
||||||
|
|
||||||
# History options
|
|
||||||
HISTSIZE=100000 # Set the amount of lines you want saved
|
|
||||||
SAVEHIST=100000 # This is required to actually save them, needs to match with HISTSIZE
|
|
||||||
setopt EXTENDED_HISTORY # Write the history file in the ":start:elapsed;command" format.
|
|
||||||
setopt INC_APPEND_HISTORY # Write to the history file immediately, not when the shell exits.
|
|
||||||
setopt SHARE_HISTORY # Share history between all sessions.
|
|
||||||
setopt HIST_EXPIRE_DUPS_FIRST # Expire duplicate entries first when trimming history.
|
|
||||||
setopt HIST_IGNORE_DUPS # Don\'t record an entry that was just recorded again.
|
|
||||||
setopt HIST_IGNORE_ALL_DUPS # Delete old recorded entry if new entry is a duplicate.
|
|
||||||
setopt HIST_FIND_NO_DUPS # Do not display a line previously found.
|
|
||||||
setopt HIST_IGNORE_SPACE # Don\'t record an entry starting with a space.
|
|
||||||
setopt HIST_SAVE_NO_DUPS # Don\'t write duplicate entries in the history file.
|
|
||||||
setopt HIST_REDUCE_BLANKS # Remove superfluous blanks before recording entry.
|
|
||||||
# Clear screen by ctrl+q
|
|
||||||
bindkey '^q' clear-screen
|
|
||||||
|
|
||||||
# Bind Ctrl-W to kill-region
|
|
||||||
bindkey "^w" kill-region
|
|
||||||
bindkey -v
|
bindkey -v
|
||||||
VI_MODE_SET_CURSOR=true
|
VI_MODE_SET_CURSOR=true
|
||||||
|
|
||||||
(( $+commands[nvim] )) && alias vim=nvim
|
|
||||||
alias sudo='sudo '
|
|
||||||
(( $+commands[nvim] )) && export EDITOR='nvim'
|
|
||||||
(( $+commands[nvim] )) && export VISUAL='nvim'
|
|
||||||
|
|
||||||
alias ls="ls --color=always"
|
|
||||||
alias cgrep="grep --color=always"
|
|
||||||
alias cdiff="git diff --color-words --no-index"
|
|
||||||
|
|
||||||
delzip() {
|
|
||||||
unzip -Z -1 "$@" | xargs -I{} rm -rf {}
|
|
||||||
}
|
|
||||||
# mitmproxy
|
|
||||||
export MITMPROXY_SSLKEYLOGFILE="~/.mitmproxy/sslkeylogfile.txt"
|
|
||||||
|
|
||||||
[[ -f ~/.zsh/.mac_config.zsh ]] && source ~/.zsh/.mac_config.zsh
|
[[ -f ~/.zsh/.mac_config.zsh ]] && source ~/.zsh/.mac_config.zsh
|
||||||
if `which go &>/dev/null`; then
|
if (( $+commands[go] )); then
|
||||||
export PATH="$PATH:$(go env GOPATH)/bin"
|
export GOPATH="$(go env GOPATH 2>/dev/null)"
|
||||||
export GOPATH=$(go env GOPATH)
|
[[ -n "$GOPATH" ]] && path+=("$GOPATH/bin")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use safecp/safemv from the tools-repo when available (after ~/.local/bin is on PATH)
|
# Use safe wrappers after ~/.local/bin has been added to PATH.
|
||||||
(( $+commands[safecp] )) && alias cp=safecp
|
(( $+commands[safecp] )) && alias cp=safecp
|
||||||
(( $+commands[safemv] )) && alias mv=safemv
|
(( $+commands[safemv] )) && alias mv=safemv
|
||||||
(( $+commands[safescp] )) && alias scp=safescp
|
(( $+commands[safescp] )) && alias scp=safescp
|
||||||
|
|
||||||
if [[ -f ~/.ssh/sudo_key ]]; then
|
if [[ -f ~/.ssh/sudo_key ]]; then
|
||||||
[[ -e /tmp/sudo-agent.sock ]] || ssh-agent -a /tmp/sudo-agent.sock &>/dev/null
|
[[ -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 `ssh-keygen -lf ~/.ssh/sudo_key | awk '{print $2}'` || SSH_AUTH_SOCK=/tmp/sudo-agent.sock ssh-add ~/.ssh/sudo_key
|
SSH_AUTH_SOCK=/tmp/sudo-agent.sock ssh-add -l |
|
||||||
|
grep -q "$(ssh-keygen -lf ~/.ssh/sudo_key | awk '{print $2}')" ||
|
||||||
|
SSH_AUTH_SOCK=/tmp/sudo-agent.sock ssh-add ~/.ssh/sudo_key
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Sudo workaround for neovim
|
|
||||||
export SUDO_ASKPASS=$(command -v ssh-askpass)
|
export SUDO_ASKPASS=$(command -v ssh-askpass)
|
||||||
|
|
||||||
# Workaround for async issues https://github.com/romkatv/powerlevel10k/issues/1554
|
if [[ -f ~/dotfiles/zsh/.p10k.mac.zsh ]]; then
|
||||||
unset ZSH_AUTOSUGGEST_USE_ASYNC
|
p10k_config=~/dotfiles/zsh/.p10k.mac.zsh
|
||||||
|
|
||||||
# Fixate language
|
|
||||||
export LANG="en_US.UTF-8"
|
|
||||||
export LC_CTYPE="en_US.UTF-8"
|
|
||||||
export TIME_STYLE="long-iso"
|
|
||||||
|
|
||||||
# Powerlevel 10k
|
|
||||||
# Remove padding on right side
|
|
||||||
ZLE_RPROMPT_INDENT=0
|
|
||||||
|
|
||||||
# To customize prompt, run `p10k configure` or edit ~/dotfiles/zsh/.p10k.zsh.
|
|
||||||
function load_p10k() {
|
|
||||||
if test -f ~/dotfiles/zsh/.p10k.mac.zsh; then
|
|
||||||
source ~/dotfiles/zsh/.p10k.mac.zsh
|
|
||||||
else
|
else
|
||||||
[[ ! -f ~/dotfiles/zsh/.p10k.zsh ]] || source ~/dotfiles/zsh/.p10k.zsh
|
p10k_config=~/dotfiles/zsh/.p10k.zsh
|
||||||
fi
|
fi
|
||||||
}
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/prompt.zsh"
|
||||||
load_p10k
|
|
||||||
|
|
||||||
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 &|
|
antidote update &>/dev/null &|
|
||||||
|
|
||||||
# This speeds up pasting w/ autosuggest
|
[[ -d "$HOME/.lmstudio/bin" ]] && path+=("$HOME/.lmstudio/bin")
|
||||||
# https://github.com/zsh-users/zsh-autosuggestions/issues/238
|
[[ -d "$HOME/.runai/bin" ]] && path+=("$HOME/.runai/bin")
|
||||||
pasteinit() {
|
runai_bin="$HOME/.runai/bin/runai"
|
||||||
OLD_SELF_INSERT=${${(s.:.)widgets[self-insert]}[2,3]}
|
|
||||||
zle -N self-insert url-quote-magic # I wonder if you'd need `.url-quote-magic`?
|
|
||||||
}
|
|
||||||
|
|
||||||
pastefinish() {
|
|
||||||
zle -N self-insert $OLD_SELF_INSERT
|
|
||||||
}
|
|
||||||
zstyle :bracketed-paste-magic paste-init pasteinit
|
|
||||||
zstyle :bracketed-paste-magic paste-finish pastefinish
|
|
||||||
|
|
||||||
# https://github.com/zsh-users/zsh-autosuggestions/issues/351
|
|
||||||
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste)
|
|
||||||
export PATH=$PATH:/Users/ising/.runai/bin
|
|
||||||
runai_bin=/Users/ising/.runai/bin/runai
|
|
||||||
runai_completion=${ZDOTDIR:-$HOME}/.cache/zsh/runai-completion.zsh
|
runai_completion=${ZDOTDIR:-$HOME}/.cache/zsh/runai-completion.zsh
|
||||||
if [[ -x "$runai_bin" ]]; then
|
if [[ -x "$runai_bin" ]]; then
|
||||||
if [[ ! -s "$runai_completion" || "$runai_bin" -nt "$runai_completion" ]]; then
|
if [[ ! -s "$runai_completion" || "$runai_bin" -nt "$runai_completion" ]]; then
|
||||||
@@ -220,25 +67,11 @@ if [[ -x "$runai_bin" ]]; then
|
|||||||
[[ -s "$runai_completion" ]] && source "$runai_completion"
|
[[ -s "$runai_completion" ]] && source "$runai_completion"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Re-activate an inherited virtualenv — MUST be the last PATH-affecting line.
|
# Keep this last: activate must snapshot the fully built PATH for deactivate.
|
||||||
#
|
typeset -U path PATH
|
||||||
# When VIRTUAL_ENV is present in the environment (a tmux pane split carries it
|
[[ -z "${VIRTUAL_ENV:-}" ]] && unset VIRTUAL_ENV
|
||||||
# in via `-e VIRTUAL_ENV=...`, see .tmux.conf) we source the venv's activate
|
if [[ -n "$VIRTUAL_ENV" && -f "$VIRTUAL_ENV/bin/activate" ]]; then
|
||||||
# script here rather than in .virtual_env_config.zsh. activate snapshots the
|
if [[ ${PATH%%:*} != "$VIRTUAL_ENV/bin" ]]; then
|
||||||
# current PATH into _OLD_VIRTUAL_PATH and restores it on `deactivate`; if we
|
|
||||||
# activated earlier (before .mac_config.zsh, go, runai below all prepend to
|
|
||||||
# PATH) that snapshot would be incomplete and `deactivate` would strip
|
|
||||||
# ~/.local/bin & friends — dropping claude and co. off PATH. Keeping this last
|
|
||||||
# guarantees the snapshot is the fully-built PATH.
|
|
||||||
#
|
|
||||||
# ANY new PATH mutation must go ABOVE this block.
|
|
||||||
#
|
|
||||||
# A new tmux window clears the var to empty (`bind c ... -e VIRTUAL_ENV=`) to
|
|
||||||
# force the base environment; drop that empty value so nothing sees a bogus venv.
|
|
||||||
[ -z "${VIRTUAL_ENV:-}" ] && unset VIRTUAL_ENV
|
|
||||||
if [ -n "$VIRTUAL_ENV" ] && [ -f "$VIRTUAL_ENV/bin/activate" ]; then
|
|
||||||
# Guard against double-activation on a manual `source ~/.zshrc`.
|
|
||||||
if [[ ":$PATH:" != *":$VIRTUAL_ENV/bin:"* ]]; then
|
|
||||||
source "$VIRTUAL_ENV/bin/activate"
|
source "$VIRTUAL_ENV/bin/activate"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
#compdef launchctl
|
||||||
|
# macOS launchd completion.
|
||||||
|
|
||||||
|
_launchctl_domains() {
|
||||||
|
local uid=$EUID
|
||||||
|
local -a domains=(
|
||||||
|
'system:system services'
|
||||||
|
"user/${uid}:services for the current user"
|
||||||
|
"gui/${uid}:services in the current graphical session"
|
||||||
|
)
|
||||||
|
_describe -t domains 'launchd domain' domains
|
||||||
|
}
|
||||||
|
|
||||||
|
_launchctl_service_targets() {
|
||||||
|
local uid=$EUID label
|
||||||
|
local -a targets=()
|
||||||
|
|
||||||
|
while IFS=$'\t' read -r _ _ label; do
|
||||||
|
[[ -n $label ]] && targets+=("gui/${uid}/${label}")
|
||||||
|
done < <(launchctl list 2>/dev/null | tail -n +2)
|
||||||
|
|
||||||
|
if (( ${#targets} )); then
|
||||||
|
_describe -t services 'launchd service target' targets
|
||||||
|
else
|
||||||
|
_message 'launchd service target'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_launchctl() {
|
||||||
|
local context state state_descr line
|
||||||
|
typeset -A opt_args
|
||||||
|
|
||||||
|
local -a commands=(
|
||||||
|
'bootstrap:register services or directories in a domain'
|
||||||
|
'bootout:unregister services or directories from a domain'
|
||||||
|
'enable:enable a service'
|
||||||
|
'disable:disable a service'
|
||||||
|
'kickstart:run or restart a service'
|
||||||
|
'kill:send a signal to a service'
|
||||||
|
'print:show a domain or service'
|
||||||
|
'print-disabled:show persistent enable and disable overrides'
|
||||||
|
'list:list loaded services'
|
||||||
|
'start:start a legacy service by label'
|
||||||
|
'stop:stop a legacy service by label'
|
||||||
|
'remove:remove a legacy service by label'
|
||||||
|
'load:load legacy plist files'
|
||||||
|
'unload:unload legacy plist files'
|
||||||
|
'setenv:set an environment variable'
|
||||||
|
'unsetenv:unset an environment variable'
|
||||||
|
'getenv:get an environment variable'
|
||||||
|
'limit:view or change resource limits'
|
||||||
|
'config:set persistent launchd configuration'
|
||||||
|
'dumpstate:dump launchd state'
|
||||||
|
'reboot:reboot a launchd domain or the system'
|
||||||
|
'version:show launchd version'
|
||||||
|
'help:show launchctl help'
|
||||||
|
)
|
||||||
|
|
||||||
|
_arguments -C \
|
||||||
|
'1:command:->command' \
|
||||||
|
'*::argument:->args'
|
||||||
|
|
||||||
|
case $state in
|
||||||
|
command)
|
||||||
|
_describe -t commands 'launchctl command' commands
|
||||||
|
;;
|
||||||
|
args)
|
||||||
|
case $words[2] in
|
||||||
|
bootstrap)
|
||||||
|
if (( CURRENT == 3 )); then
|
||||||
|
_launchctl_domains
|
||||||
|
else
|
||||||
|
_files -g '*.plist(-.)'
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
bootout)
|
||||||
|
if (( CURRENT == 3 )); then
|
||||||
|
_launchctl_domains
|
||||||
|
_launchctl_service_targets
|
||||||
|
else
|
||||||
|
_files -g '*.plist(-.)'
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
enable|disable|kickstart)
|
||||||
|
_launchctl_service_targets
|
||||||
|
;;
|
||||||
|
print)
|
||||||
|
_launchctl_domains
|
||||||
|
_launchctl_service_targets
|
||||||
|
;;
|
||||||
|
print-disabled)
|
||||||
|
_launchctl_domains
|
||||||
|
;;
|
||||||
|
load|unload)
|
||||||
|
_files -g '*.plist(-.)'
|
||||||
|
;;
|
||||||
|
start|stop|remove)
|
||||||
|
local -a labels
|
||||||
|
labels=(${${(f)"$(launchctl list 2>/dev/null)"}[2,-1]##*$'\t'})
|
||||||
|
_describe -t services 'service label' labels
|
||||||
|
;;
|
||||||
|
kill)
|
||||||
|
if (( CURRENT == 3 )); then
|
||||||
|
_signals
|
||||||
|
else
|
||||||
|
_launchctl_service_targets
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
setenv)
|
||||||
|
if (( CURRENT == 3 )); then
|
||||||
|
_parameters
|
||||||
|
else
|
||||||
|
_message 'value'
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
getenv|unsetenv)
|
||||||
|
_parameters
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_message 'argument'
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_launchctl "$@"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Callers set plugins_txt and static_file before sourcing this module.
|
||||||
|
mkdir -p "${static_file:h}"
|
||||||
|
if [[ ! -e ${ZDOTDIR:-$HOME}/.antidote ]]; then
|
||||||
|
git clone https://github.com/mattmc3/antidote.git "${ZDOTDIR:-$HOME}/.antidote"
|
||||||
|
fi
|
||||||
|
|
||||||
|
zstyle ':completion:*:ssh:*' hosts off
|
||||||
|
zstyle ':completion:*:scp:*' hosts off
|
||||||
|
zstyle ':completion:*:commands' rehash 1
|
||||||
|
|
||||||
|
source "${ZDOTDIR:-$HOME}/.antidote/antidote.zsh"
|
||||||
|
antidote load "$plugins_txt" "$static_file"
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
setopt interactivecomments
|
||||||
|
|
||||||
|
HISTSIZE=100000
|
||||||
|
SAVEHIST=100000
|
||||||
|
setopt EXTENDED_HISTORY
|
||||||
|
setopt INC_APPEND_HISTORY
|
||||||
|
setopt SHARE_HISTORY
|
||||||
|
setopt HIST_EXPIRE_DUPS_FIRST
|
||||||
|
setopt HIST_IGNORE_DUPS
|
||||||
|
setopt HIST_IGNORE_ALL_DUPS
|
||||||
|
setopt HIST_FIND_NO_DUPS
|
||||||
|
setopt HIST_IGNORE_SPACE
|
||||||
|
setopt HIST_SAVE_NO_DUPS
|
||||||
|
setopt HIST_REDUCE_BLANKS
|
||||||
|
|
||||||
|
bindkey '^q' clear-screen
|
||||||
|
(( $+commands[nvim] )) && alias vim=nvim
|
||||||
|
(( $+commands[nvim] )) && export EDITOR=nvim VISUAL=nvim
|
||||||
|
alias sudo='sudo '
|
||||||
|
alias ls='ls --color=always'
|
||||||
|
alias cgrep='grep --color=always'
|
||||||
|
alias cdiff='git diff --color-words --no-index'
|
||||||
|
|
||||||
|
# Remove the files an archive extracted into the current directory.
|
||||||
|
# Lists what it will delete and asks first; -f skips the prompt, -n dry-runs.
|
||||||
|
# Directories are only removed if they end up empty.
|
||||||
|
delzip() {
|
||||||
|
emulate -L zsh
|
||||||
|
setopt local_options
|
||||||
|
|
||||||
|
local dry=0 force=0
|
||||||
|
while [[ $1 == -[nf] ]]; do
|
||||||
|
[[ $1 == -n ]] && dry=1 || force=1
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
(( $# )) || { print -ru2 "usage: delzip [-n|-f] <archive.zip>..."; return 2 }
|
||||||
|
|
||||||
|
local zip entry parent
|
||||||
|
local -a entries files dirs
|
||||||
|
for zip in "$@"; do
|
||||||
|
[[ -f $zip ]] || { print -ru2 "delzip: no such file: $zip"; return 1 }
|
||||||
|
entries=("${(f)$(unzip -Z -1 -- $zip)}") || return 1
|
||||||
|
for entry in $entries; do
|
||||||
|
[[ -n $entry ]] || continue
|
||||||
|
# zip-slip guard: never touch anything outside the cwd
|
||||||
|
if [[ $entry == (/|~)* || $entry == (|*/)..(|/*) ]]; then
|
||||||
|
print -ru2 "delzip: refusing unsafe path: $entry"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
[[ $entry == */ ]] && dirs+=(${entry%/}) || files+=($entry)
|
||||||
|
# many archives omit directory entries, so infer them from the
|
||||||
|
# paths as well; unzip creates those dirs regardless
|
||||||
|
parent=${entry%/}
|
||||||
|
while [[ $parent == */* ]]; do
|
||||||
|
parent=${parent%/*}
|
||||||
|
dirs+=($parent)
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
dirs=(${(u)dirs})
|
||||||
|
|
||||||
|
# only keep what is actually on disk, so the list reflects reality;
|
||||||
|
# -L catches broken symlinks, which -e alone misses
|
||||||
|
local -a present
|
||||||
|
present=(); for entry in $files; do [[ -e $entry || -L $entry ]] && present+=($entry); done
|
||||||
|
files=($present)
|
||||||
|
present=(); for entry in $dirs; do [[ -d $entry ]] && present+=($entry); done
|
||||||
|
dirs=($present)
|
||||||
|
|
||||||
|
(( $#files + $#dirs )) || { print -ru2 "delzip: nothing to remove here (already gone?)"; return 1 }
|
||||||
|
|
||||||
|
if (( dry )); then
|
||||||
|
print -rl -- ${files} ${(O)dirs}
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( ! force )); then
|
||||||
|
[[ -t 0 ]] || { print -ru2 "delzip: not a terminal, use -f to skip the prompt"; return 1 }
|
||||||
|
print -r -- "delzip: remove ${#files} file(s) under ${PWD}:"
|
||||||
|
print -rl -- " "${^files[1,20]}
|
||||||
|
(( $#files > 20 )) && print -r -- " ... and $(( $#files - 20 )) more"
|
||||||
|
(( $#dirs )) && print -r -- "plus ${#dirs} directory/ies, if they end up empty."
|
||||||
|
read -q "?Proceed? [y/N] " || { print -r -- $'\naborted'; return 1 }
|
||||||
|
print
|
||||||
|
fi
|
||||||
|
|
||||||
|
(( $#files )) && rm -f -- $files
|
||||||
|
# deepest first, so parents can empty out; rmdir refuses non-empty dirs
|
||||||
|
for entry in ${(O)dirs}; do
|
||||||
|
[[ -d $entry ]] && rmdir -- $entry 2>/dev/null
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
export MITMPROXY_SSLKEYLOGFILE="$HOME/.mitmproxy/sslkeylogfile.txt"
|
||||||
|
|
||||||
|
unset ZSH_AUTOSUGGEST_USE_ASYNC
|
||||||
|
export LANG='en_US.UTF-8'
|
||||||
|
export LC_CTYPE='en_US.UTF-8'
|
||||||
|
export TIME_STYLE='long-iso'
|
||||||
|
|
||||||
|
pasteinit() {
|
||||||
|
OLD_SELF_INSERT=${${(s.:.)widgets[self-insert]}[2,3]}
|
||||||
|
zle -N self-insert url-quote-magic
|
||||||
|
}
|
||||||
|
pastefinish() {
|
||||||
|
zle -N self-insert "$OLD_SELF_INSERT"
|
||||||
|
}
|
||||||
|
zstyle :bracketed-paste-magic paste-init pasteinit
|
||||||
|
zstyle :bracketed-paste-magic paste-finish pastefinish
|
||||||
|
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Callers select p10k_config before sourcing this module.
|
||||||
|
ZLE_RPROMPT_INDENT=0
|
||||||
|
[[ -z "$p10k_config" || ! -f "$p10k_config" ]] || source "$p10k_config"
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# Background repository maintenance shared by desktop and server shells.
|
||||||
|
|
||||||
|
update_dotfiles() {
|
||||||
|
local repo="$HOME/dotfiles"
|
||||||
|
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
||||||
|
local notice_file="$cache_dir/dotfiles-update-notice"
|
||||||
|
local notice_tmp="$notice_file.$$.tmp"
|
||||||
|
local -a TO; (( $+commands[timeout] )) && TO=(timeout -k 5 15)
|
||||||
|
GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o ControlMaster=no -o ControlPath=none' \
|
||||||
|
$TO git -C "$repo" fetch --quiet </dev/null 2>/dev/null || return
|
||||||
|
git -C "$repo" rev-parse --abbrev-ref '@{u}' >/dev/null 2>&1 || return
|
||||||
|
git -C "$repo" merge-base --is-ancestor '@{u}' HEAD 2>/dev/null && return
|
||||||
|
if git -C "$repo" merge --ff-only --quiet '@{u}' 2>/dev/null; then
|
||||||
|
local notice="⬆ dotfiles updated — run: exec zsh"
|
||||||
|
mkdir -p "$cache_dir" || return
|
||||||
|
print -r -- "$notice" >| "$notice_tmp" || return
|
||||||
|
mv -f "$notice_tmp" "$notice_file"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
local notice="⚠ dotfiles: $(git -C "$repo" symbolic-ref --short HEAD) can't fast-forward to @{u} — run: git -C ~/dotfiles pull"
|
||||||
|
mkdir -p "$cache_dir" || return
|
||||||
|
print -r -- "$notice" >| "$notice_tmp" || return
|
||||||
|
mv -f "$notice_tmp" "$notice_file"
|
||||||
|
}
|
||||||
|
update_dotfiles &!
|
||||||
|
|
||||||
|
check_tools_repo() {
|
||||||
|
local repo branch remote mergeref remote_sha local_sha cmd notice
|
||||||
|
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
||||||
|
local notice_file="$cache_dir/tools-update-notice"
|
||||||
|
local notice_tmp="$notice_file.$$.tmp"
|
||||||
|
local -a TO; (( $+commands[timeout] )) && TO=(timeout -k 5 10)
|
||||||
|
for repo in /opt/tools "$HOME/tools" "$HOME/tools/tools-repo"; do
|
||||||
|
local -a g=(git -c 'safe.directory=*' -C "$repo")
|
||||||
|
$g rev-parse --is-inside-work-tree >/dev/null 2>&1 || continue
|
||||||
|
branch=$($g symbolic-ref --short HEAD 2>/dev/null) || return
|
||||||
|
remote=$($g config "branch.$branch.remote" 2>/dev/null) || return
|
||||||
|
mergeref=$($g config "branch.$branch.merge" 2>/dev/null) || return
|
||||||
|
remote_sha=$(GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o ControlMaster=no -o ControlPath=none' \
|
||||||
|
$TO $g ls-remote "$remote" "$mergeref" </dev/null 2>/dev/null | awk '{print $1}')
|
||||||
|
local_sha=$($g rev-parse HEAD 2>/dev/null)
|
||||||
|
[[ -n "$remote_sha" && -n "$local_sha" ]] || return
|
||||||
|
[[ "$remote_sha" == "$local_sha" ]] && return
|
||||||
|
$g merge-base --is-ancestor "$remote_sha" HEAD 2>/dev/null && return
|
||||||
|
[[ -w "$repo/.git" ]] && cmd="git -C $repo pull" || cmd="sudo git -C $repo pull"
|
||||||
|
notice="⬆ tools: updates available in $repo — run: $cmd"
|
||||||
|
mkdir -p "$cache_dir" || return
|
||||||
|
print -r -- "$notice" >| "$notice_tmp" || return
|
||||||
|
mv -f "$notice_tmp" "$notice_file"
|
||||||
|
return
|
||||||
|
done
|
||||||
|
}
|
||||||
|
check_tools_repo &!
|
||||||
|
|
||||||
|
show_update_notices() {
|
||||||
|
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
||||||
|
local notice_file claimed_notice
|
||||||
|
for notice_file in "$cache_dir"/{dotfiles,tools}-update-notice; do
|
||||||
|
[[ -s "$notice_file" ]] || continue
|
||||||
|
claimed_notice="$notice_file.$$.show"
|
||||||
|
mv "$notice_file" "$claimed_notice" 2>/dev/null || continue
|
||||||
|
command cat "$claimed_notice"
|
||||||
|
command rm -f "$claimed_notice"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
autoload -Uz add-zsh-hook
|
||||||
|
add-zsh-hook precmd show_update_notices
|
||||||
Reference in New Issue
Block a user