161 lines
5.5 KiB
Bash
161 lines
5.5 KiB
Bash
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)
|
|
|
|
# Mirror the ssh destination into a per-pane tmux option; .tmux.conf labels ssh
|
|
# panes (window name, pane border only in windows with ssh panes) by 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
|
|
# pane title starts as the alias; a remote that sets its own title wins.
|
|
# 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
|