Files
dotfiles/zsh/lib/interactive.zsh
T

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