mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-03 11:37:36 +00:00
165 lines
5.4 KiB
Bash
165 lines
5.4 KiB
Bash
# ~/.config/zsh/keybinds.zsh — zle ports of fish_user_key_bindings.fish.
|
|
# Keys owned by kitty.conf never reach the shell and are NOT bound here:
|
|
# ctrl-h/j/k/l → vim-aware split nav (pass_keys.py).
|
|
|
|
bindkey -e # pin emacs keymap ($EDITOR containing "vi" would pick viins)
|
|
unsetopt flow_control # free ^Q/^S in zle so the ctrl-q exit bind fires
|
|
|
|
# iris (~/.config/iris) learns a command is running from the preexec/precmd
|
|
# hooks, which never fire for programs a widget starts. Without this, iris
|
|
# keeps treating the screen as an idle prompt while tv, yazi or lazygit run:
|
|
# it swallows up/down/tab and can draw its menu over them. Same messages as
|
|
# iris's own hooks; a no-op outside iris. fish: functions/_iris_busy.fish.
|
|
_iris_busy() {
|
|
[[ -n $IRIS_FD ]] || return 0
|
|
case $1 in
|
|
start) print -u $IRIS_FD -N -r -- IRIS_CMD_START 2>/dev/null ;;
|
|
stop) print -u $IRIS_FD -N -r -- IRIS_CMD_STOP:0 2>/dev/null ;;
|
|
esac
|
|
return 0
|
|
}
|
|
|
|
# Generic runner: widget `run-<cmd>` executes <cmd> (function or binary) with
|
|
# the tty as stdin, then repaints — fish's `commandline -f repaint`.
|
|
# cwd changes from gho/yy persist: widgets run in the shell process.
|
|
# gho, pj and `tv git-files` (below) open television cables (~/.config/
|
|
# television/cable) — the same keys do the same in fish and bash.
|
|
_zle-run() {
|
|
local cmd=${WIDGET#run-}
|
|
zle -I
|
|
_iris_busy start
|
|
$cmd </dev/tty
|
|
_iris_busy stop
|
|
zle reset-prompt
|
|
}
|
|
for _cmd in purple clip-last omp-session yy lazygit; do
|
|
zle -N "run-$_cmd" _zle-run
|
|
done
|
|
unset _cmd
|
|
|
|
# tv pickers run --inline below the prompt. zle -I + reset-prompt redraws the
|
|
# prompt where zle last drew it, wiping anything printed below; zle -I alone
|
|
# redraws a fresh prompt under the output. So: a cancelled picker (cursor
|
|
# left on the line below the prompt) steps back up and resets in place, and
|
|
# output that must stay (onefetch after gho's cd, a pj task) gets zle -I only.
|
|
|
|
# ctrl-e: tv git-files (bat preview, enter opens nvim, which restores the
|
|
# cursor to tv's line).
|
|
_zle-tv-git-files() {
|
|
zle -I
|
|
_iris_busy start
|
|
tv git-files --inline </dev/tty
|
|
_iris_busy stop
|
|
printf '\033[A' >/dev/tty
|
|
zle reset-prompt
|
|
}
|
|
zle -N tv-git-files _zle-tv-git-files
|
|
|
|
# ctrl-o: gho (ghq-repos cable); cd + clear + onefetch when something was
|
|
# picked.
|
|
_zle-gho() {
|
|
local before=$PWD
|
|
zle -I
|
|
_iris_busy start
|
|
gho </dev/tty
|
|
_iris_busy stop
|
|
if [[ $PWD == "$before" ]]; then
|
|
printf '\033[A' >/dev/tty
|
|
zle reset-prompt
|
|
fi
|
|
}
|
|
zle -N gho-inline _zle-gho
|
|
|
|
# ctrl-p: pj. pj reports through $PJ_STATE: `open` = cancelled, `ran` = a task
|
|
# printed output, empty = no task sources.
|
|
_zle-pj() {
|
|
local state
|
|
state=$(mktemp) || return
|
|
zle -I
|
|
_iris_busy start
|
|
PJ_STATE=$state pj </dev/tty
|
|
_iris_busy stop
|
|
case $(<$state) in
|
|
open) printf '\033[A' >/dev/tty; zle reset-prompt ;;
|
|
ran) ;;
|
|
*) zle reset-prompt ;;
|
|
esac
|
|
rm -f $state
|
|
}
|
|
zle -N pj-inline _zle-pj
|
|
|
|
# ctrl-z at the prompt (fish's _jobs_bind): fg the only job, or pick one from
|
|
# the `jobs` tv cable, which reads the job table from $TV_JOBS (records:
|
|
# "%<id> <state> <command>", id, process group). While a job holds the
|
|
# terminal ctrl-z is still the tty's suspend, so the key toggles.
|
|
# fg runs as a real command line (push-input keeps typed text for the next
|
|
# prompt); __jobs_bind_fg erases that echoed line and fg's "[1] continued"
|
|
# notice. The leading space keeps it out of history (HIST_IGNORE_SPACE).
|
|
__jobs_bind_fg() {
|
|
printf '\033[A\033[2K\r' >/dev/tty
|
|
fg %$1 2>/dev/null
|
|
}
|
|
_zle-jobs() {
|
|
local -a ids recs
|
|
local id pick file
|
|
ids=(${(On)${(k)jobstates}})
|
|
(( $#ids )) || return 0
|
|
for id in $ids; do
|
|
recs+=("$(printf '%%%s %-9s %s\t%s\t%s' $id ${jobstates[$id]%%:*} \
|
|
"${jobtexts[$id]}" $id ${${jobstates[$id]#*:*:}%%=*})")
|
|
done
|
|
if (( $#ids == 1 )); then
|
|
pick=$ids[1]
|
|
else
|
|
file=$(mktemp) || return
|
|
print -rl -- $recs >$file
|
|
zle -I
|
|
_iris_busy start
|
|
pick=$(TV_JOBS=$file tv jobs --inline </dev/tty)
|
|
_iris_busy stop
|
|
printf '\033[A' >/dev/tty
|
|
rm -f $file
|
|
if [[ -z $pick ]]; then
|
|
zle reset-prompt
|
|
return
|
|
fi
|
|
fi
|
|
zle push-input
|
|
BUFFER=" __jobs_bind_fg $pick"
|
|
zle accept-line
|
|
}
|
|
zle -N jobs-fg _zle-jobs
|
|
|
|
bindkey '^E' tv-git-files
|
|
bindkey '^B' run-purple
|
|
bindkey '^Y' run-clip-last
|
|
bindkey '^O' gho-inline
|
|
bindkey '^P' pj-inline
|
|
# ctrl-a: omp-session resumes or starts omp for the repo; after a cancelled
|
|
# omp-sessions picker it moves the cursor back up itself.
|
|
bindkey '^A' run-omp-session
|
|
# ctrl-f: yazi; yy cd's to yazi's exit dir on quit.
|
|
bindkey '^F' run-yy
|
|
bindkey '^G' run-lazygit
|
|
bindkey '^Z' jobs-fg
|
|
|
|
# ctrl-q mirrors ctrl-d's preset (`exit`) — quit the shell.
|
|
_zle-exit() { exit }
|
|
zle -N _zle-exit
|
|
bindkey '^Q' _zle-exit
|
|
|
|
# ctrl-c at the prompt: wipe any typed text AND clear screen + kitty
|
|
# scrollback (2J/3J drops it, like the fish `clear` wrapper). ^C is the tty
|
|
# INTR char, so this lives in TRAPINT — bindkey '^C' would never fire.
|
|
# Mid-command SIGINT behaves normally (128+SIGINT). BUFFER is read-only in
|
|
# trap context, so builtin widgets are invoked via `zle .name` instead.
|
|
TRAPINT() {
|
|
if zle; then
|
|
zle .kill-buffer
|
|
printf '\033[2J\033[3J\033[1;1H'
|
|
zle .reset-prompt
|
|
return 0
|
|
fi
|
|
return $(( 128 + $1 ))
|
|
}
|