mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-02 19:32:43 +00:00
feat(config): switch tv pickers to --inline and improve prompt redraw handling
This commit is contained in:
1 parent
19aeed21ac
commit
a5bf3e9194
10 files changed
+173
-57
No files matched your search
@@ -1,8 +1,8 @@
|
|||||||
# Pick a ghq repo / Obsidian vault with tv (ghq-repos cable) + cd.
|
# Pick a ghq repo / Obsidian vault with tv (ghq-repos cable) + cd.
|
||||||
gho() {
|
gho() {
|
||||||
local dir
|
local dir
|
||||||
dir=$(tv ghq-repos) || return
|
dir=$(tv ghq-repos --inline) || return
|
||||||
[ -n "$dir" ] || return
|
[ -n "$dir" ] || return 1
|
||||||
cd "$dir" || return
|
cd "$dir" || return
|
||||||
clear
|
clear
|
||||||
if [ -d .git ]; then
|
if [ -d .git ]; then
|
||||||
|
|||||||
@@ -4,33 +4,67 @@
|
|||||||
# ctrl-p → pj (pj cable) down → pj on an empty prompt
|
# ctrl-p → pj (pj cable) down → pj on an empty prompt
|
||||||
# ctrl-t → tv smart autocomplete (tv init bash ships no ctrl-t)
|
# ctrl-t → tv smart autocomplete (tv init bash ships no ctrl-t)
|
||||||
# Keys owned by kitty.conf never reach the shell: ctrl-h/j/k/l (pass_keys.py).
|
# Keys owned by kitty.conf never reach the shell: ctrl-h/j/k/l (pass_keys.py).
|
||||||
|
#
|
||||||
|
# Every picker runs tv --inline: it opens on the line below the prompt and
|
||||||
|
# leaves the cursor on that line when it exits. When nothing was printed
|
||||||
|
# below, the binding steps back up (_kb_up) so readline redraws the prompt in
|
||||||
|
# place after bind -x; output that must stay (a pj task) is left alone.
|
||||||
|
|
||||||
# bind -x runs in the shell process, so gho's cd persists — but readline keeps
|
_kb_up() { printf '\033[A' >/dev/tty; }
|
||||||
# drawing the prompt it started with. Each key is therefore a macro: \C-xN
|
|
||||||
# stashes the typed line and runs the command, \C-m accepts the now-empty
|
# ctrl-e: enter opens nvim, which restores the cursor to tv's line.
|
||||||
# line (bash prints a fresh prompt for the new cwd; nothing reaches history),
|
_kb_git_files() {
|
||||||
# and \C-x0 restores the stash into the new line.
|
tv git-files --inline </dev/tty
|
||||||
_kb_run() {
|
_kb_up
|
||||||
|
}
|
||||||
|
bind -x '"\C-e": _kb_git_files'
|
||||||
|
|
||||||
|
# ctrl-p, and down on an empty prompt. pj reports through $PJ_STATE: `open`
|
||||||
|
# = cancelled, `ran` = a task printed output, empty = no task sources.
|
||||||
|
_kb_pj() {
|
||||||
|
local state
|
||||||
|
state=$(mktemp) || return
|
||||||
|
PJ_STATE=$state pj "$@" </dev/tty
|
||||||
|
[ "$(<"$state")" = open ] && _kb_up
|
||||||
|
rm -f "$state"
|
||||||
|
}
|
||||||
|
bind -x '"\C-p": _kb_pj'
|
||||||
|
|
||||||
|
# ctrl-o: gho, split so the prompt is right. bind -x runs in the shell
|
||||||
|
# process, so the cd persists — but readline keeps drawing the prompt it
|
||||||
|
# started with. The macro runs \C-x1 (pick with tv, cd), then \C-x2 and \C-x3,
|
||||||
|
# which _kb_gho rebinds: after a cd, \C-x2 accepts the stashed-empty line
|
||||||
|
# (bash prints a fresh prompt for the new cwd; nothing reaches history) and
|
||||||
|
# \C-x3 does gho's clear + onefetch, after which readline redraws that fresh
|
||||||
|
# prompt below the output; when cancelled both just redraw. \C-x0 restores
|
||||||
|
# the typed text.
|
||||||
|
_kb_gho() {
|
||||||
|
local dir
|
||||||
_kb_line=$READLINE_LINE _kb_point=$READLINE_POINT
|
_kb_line=$READLINE_LINE _kb_point=$READLINE_POINT
|
||||||
READLINE_LINE='' READLINE_POINT=0
|
dir=$(tv ghq-repos --inline </dev/tty)
|
||||||
"$@" </dev/tty
|
_kb_up
|
||||||
|
if [ -n "$dir" ] && cd "$dir"; then
|
||||||
|
READLINE_LINE='' READLINE_POINT=0
|
||||||
|
bind '"\C-x2": accept-line'
|
||||||
|
bind -x '"\C-x3": _kb_gho_show'
|
||||||
|
else
|
||||||
|
bind '"\C-x2": redraw-current-line'
|
||||||
|
bind '"\C-x3": redraw-current-line'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
_kb_gho_show() {
|
||||||
|
clear
|
||||||
|
if [ -d .git ]; then
|
||||||
|
onefetch
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
_kb_restore() {
|
_kb_restore() {
|
||||||
READLINE_LINE=${_kb_line-} READLINE_POINT=${_kb_point-0}
|
READLINE_LINE=${_kb_line-} READLINE_POINT=${_kb_point-0}
|
||||||
unset _kb_line _kb_point
|
unset _kb_line _kb_point
|
||||||
}
|
}
|
||||||
|
bind -x '"\C-x1": _kb_gho'
|
||||||
bind -x '"\C-x0": _kb_restore'
|
bind -x '"\C-x0": _kb_restore'
|
||||||
|
bind '"\C-o": "\C-x1\C-x2\C-x3\C-x0"'
|
||||||
# _kb_bind KEY SLOT COMMAND…
|
|
||||||
_kb_bind() {
|
|
||||||
local key=$1 slot=$2
|
|
||||||
shift 2
|
|
||||||
bind -x "\"\\C-x$slot\": _kb_run $*"
|
|
||||||
bind "\"$key\": \"\\C-x$slot\\C-m\\C-x0\""
|
|
||||||
}
|
|
||||||
_kb_bind '\C-o' 1 gho
|
|
||||||
_kb_bind '\C-e' 2 tv git-files
|
|
||||||
_kb_bind '\C-p' 3 pj
|
|
||||||
|
|
||||||
# down: the pj cable on an idle, empty prompt, otherwise history search
|
# down: the pj cable on an idle, empty prompt, otherwise history search
|
||||||
# (fish's _pj_bind_down). bind -x can't call readline functions, so _kb_down
|
# (fish's _pj_bind_down). bind -x can't call readline functions, so _kb_down
|
||||||
@@ -40,7 +74,7 @@ _kb_down() {
|
|||||||
bind '"\C-x5": history-search-forward'
|
bind '"\C-x5": history-search-forward'
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
PJ_QUIET=1 pj </dev/tty
|
PJ_QUIET=1 _kb_pj
|
||||||
bind '"\C-x5": redraw-current-line'
|
bind '"\C-x5": redraw-current-line'
|
||||||
}
|
}
|
||||||
bind -x '"\C-x4": _kb_down'
|
bind -x '"\C-x4": _kb_down'
|
||||||
@@ -51,7 +85,8 @@ bind '"\eOB": "\C-x4\C-x5"'
|
|||||||
# (shell_integration.channel_triggers) and insert the picks there, quoted.
|
# (shell_integration.channel_triggers) and insert the picks there, quoted.
|
||||||
_kb_tv_autocomplete() {
|
_kb_tv_autocomplete() {
|
||||||
local pre=${READLINE_LINE:0:READLINE_POINT} out item ins=''
|
local pre=${READLINE_LINE:0:READLINE_POINT} out item ins=''
|
||||||
out=$(tv --autocomplete-prompt "$pre" </dev/tty) || return
|
out=$(tv --autocomplete-prompt "$pre" --inline </dev/tty)
|
||||||
|
_kb_up
|
||||||
while IFS= read -r item; do
|
while IFS= read -r item; do
|
||||||
[ -n "$item" ] && ins+="$(printf '%q' "$item") "
|
[ -n "$item" ] && ins+="$(printf '%q' "$item") "
|
||||||
done <<<"$out"
|
done <<<"$out"
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
function _gho_bind --description 'ctrl-o: gho (tv --inline), then redraw the prompt in the right place'
|
||||||
|
set -l before $PWD
|
||||||
|
gho
|
||||||
|
if test "$PWD" = "$before"
|
||||||
|
# Cancelled (or the nvim action ran): tv --inline left the cursor on
|
||||||
|
# the line below the prompt; step back so repaint redraws in place.
|
||||||
|
printf '\033[A' >/dev/tty
|
||||||
|
else
|
||||||
|
# cd + clear + onefetch: put the prompt below onefetch's output.
|
||||||
|
printf '\n' >/dev/tty
|
||||||
|
end
|
||||||
|
commandline -f repaint
|
||||||
|
end
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
function _pj_bind --description 'ctrl-p / down: pj (tv --inline), then redraw the prompt in the right place'
|
||||||
|
# pj reports through $PJ_STATE: `open` = the picker was cancelled and
|
||||||
|
# left the cursor on the line below the prompt; empty = no task sources,
|
||||||
|
# nothing drawn — but fish's repaint after an external command still
|
||||||
|
# lands one line low, so both step back up. `ran` = a task printed
|
||||||
|
# output: new line, prompt below it.
|
||||||
|
set -lx PJ_STATE (mktemp)
|
||||||
|
if contains -- --quiet $argv
|
||||||
|
set -lx PJ_QUIET 1
|
||||||
|
end
|
||||||
|
pj
|
||||||
|
set -l state (cat $PJ_STATE)
|
||||||
|
switch "$state"
|
||||||
|
case open ''
|
||||||
|
printf '\033[A' >/dev/tty
|
||||||
|
case ran
|
||||||
|
printf '\n' >/dev/tty
|
||||||
|
end
|
||||||
|
rm -f $PJ_STATE
|
||||||
|
commandline -f repaint
|
||||||
|
end
|
||||||
@@ -13,9 +13,9 @@ function _pj_bind_down --description "down arrow: pj tv cable on an idle empty p
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
# pj is ~/.local/bin/pj (also ctrl-p), which opens the `pj` tv cable.
|
# _pj_bind runs ~/.local/bin/pj (also ctrl-p), which opens the `pj` tv
|
||||||
# PJ_QUIET keeps it silent when the tree has no task source at all, so
|
# cable. --quiet (PJ_QUIET) keeps it silent when the tree has no task
|
||||||
# down is a no-op outside projects instead of printing an error per press.
|
# source at all, so down is a no-op outside projects instead of printing
|
||||||
PJ_QUIET=1 pj
|
# an error per press.
|
||||||
commandline -f repaint
|
_pj_bind --quiet
|
||||||
end
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
function _tv_inline --description 'tv --inline below the prompt, cursor back on the prompt line; stdout is the pick'
|
||||||
|
# tv --inline opens on the line below the prompt and leaves the cursor on
|
||||||
|
# its own first row when it exits; step back up so the following
|
||||||
|
# `commandline -f repaint` redraws the prompt in place instead of one line
|
||||||
|
# lower. /dev/tty keeps the move out of callers that capture stdout (gho).
|
||||||
|
tv $argv --inline
|
||||||
|
set -l st $status
|
||||||
|
printf '\033[A' >/dev/tty
|
||||||
|
return $st
|
||||||
|
end
|
||||||
@@ -11,13 +11,15 @@ function fish_user_key_bindings
|
|||||||
# ctrl-g → lazygit overlay, ctrl-a → omp hsplit, ctrl-y → yazi vsplit,
|
# ctrl-g → lazygit overlay, ctrl-a → omp hsplit, ctrl-y → yazi vsplit,
|
||||||
# ctrl-h/j/k/l → vim-aware split nav (pass_keys.py).
|
# ctrl-h/j/k/l → vim-aware split nav (pass_keys.py).
|
||||||
# ctrl-e: tv git-files (bat preview, enter opens nvim). ctrl-o, ctrl-p
|
# ctrl-e: tv git-files (bat preview, enter opens nvim). ctrl-o, ctrl-p
|
||||||
# and down also open tv cables — same keys in zsh and bash.
|
# and down also open tv cables — same keys in zsh and bash. tv runs
|
||||||
bind -M $mode ctrl-e 'tv git-files; commandline -f repaint'
|
# --inline below the prompt; _tv_inline/_gho_bind/_pj_bind put the
|
||||||
|
# prompt back in place (or below any output) afterwards.
|
||||||
|
bind -M $mode ctrl-e '_tv_inline git-files; commandline -f repaint'
|
||||||
bind -M $mode ctrl-b purple repaint
|
bind -M $mode ctrl-b purple repaint
|
||||||
bind -M $mode ctrl-y clip-last
|
bind -M $mode ctrl-y clip-last
|
||||||
|
|
||||||
bind -M $mode ctrl-o 'gho; commandline -f repaint'
|
bind -M $mode ctrl-o _gho_bind
|
||||||
bind -M $mode ctrl-p 'pj; commandline -f repaint'
|
bind -M $mode ctrl-p _pj_bind
|
||||||
bind -M $mode ctrl-a 'omp; commandline -f repaint'
|
bind -M $mode ctrl-a 'omp; commandline -f repaint'
|
||||||
bind -M $mode ctrl-w 'atuin ai inline; commandline -f repaint'
|
bind -M $mode ctrl-w 'atuin ai inline; commandline -f repaint'
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
function gho --description 'pick a ghq repo / Obsidian vault (tv ghq-repos cable) + cd'
|
function gho --description 'pick a ghq repo / Obsidian vault (tv ghq-repos cable) + cd'
|
||||||
set -l dir (tv ghq-repos); or return
|
set -l dir (tv ghq-repos --inline); or return
|
||||||
test -n "$dir"; or return
|
test -n "$dir"; or return 1
|
||||||
cd $dir; or return
|
cd $dir; or return
|
||||||
clear
|
clear
|
||||||
if test -d .git
|
if test -d .git
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Pick a ghq repo / Obsidian vault with tv (ghq-repos cable) + cd.
|
# Pick a ghq repo / Obsidian vault with tv (ghq-repos cable) + cd.
|
||||||
gho() {
|
gho() {
|
||||||
local dir
|
local dir
|
||||||
dir=$(tv ghq-repos) || return
|
dir=$(tv ghq-repos --inline) || return
|
||||||
[ -n "$dir" ] || return
|
[ -n "$dir" ] || return 1
|
||||||
cd "$dir" || return
|
cd "$dir" || return
|
||||||
clear
|
clear
|
||||||
if [ -d .git ]; then
|
if [ -d .git ]; then
|
||||||
|
|||||||
+56
-21
@@ -8,49 +8,84 @@ unsetopt flow_control # free ^Q/^S in zle so the ctrl-q exit bind fires
|
|||||||
# Generic runner: widget `run-<cmd>` executes <cmd> (function or binary) with
|
# Generic runner: widget `run-<cmd>` executes <cmd> (function or binary) with
|
||||||
# the tty as stdin, then repaints — fish's `commandline -f repaint`.
|
# the tty as stdin, then repaints — fish's `commandline -f repaint`.
|
||||||
# cwd changes from gho/yy persist: widgets run in the shell process.
|
# cwd changes from gho/yy persist: widgets run in the shell process.
|
||||||
# gho, pj and `tv git-files` open television cables (~/.config/television/
|
# gho, pj and `tv git-files` (below) open television cables (~/.config/
|
||||||
# cable) — the same keys do the same in fish and bash.
|
# television/cable) — the same keys do the same in fish and bash.
|
||||||
_zle-run() {
|
_zle-run() {
|
||||||
local cmd=${WIDGET#run-}
|
local cmd=${WIDGET#run-}
|
||||||
zle -I
|
zle -I
|
||||||
$cmd </dev/tty
|
$cmd </dev/tty
|
||||||
zle reset-prompt
|
zle reset-prompt
|
||||||
}
|
}
|
||||||
for _cmd in purple clip-last gho pj omp yy lazygit; do
|
for _cmd in purple clip-last omp yy lazygit; do
|
||||||
zle -N "run-$_cmd" _zle-run
|
zle -N "run-$_cmd" _zle-run
|
||||||
done
|
done
|
||||||
unset _cmd
|
unset _cmd
|
||||||
|
|
||||||
# ctrl-e: tv git-files (bat preview, enter opens nvim).
|
# 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-tv-git-files() {
|
||||||
zle -I
|
zle -I
|
||||||
tv git-files </dev/tty
|
tv git-files --inline </dev/tty
|
||||||
|
printf '\033[A' >/dev/tty
|
||||||
zle reset-prompt
|
zle reset-prompt
|
||||||
}
|
}
|
||||||
zle -N tv-git-files _zle-tv-git-files
|
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
|
||||||
|
gho </dev/tty
|
||||||
|
if [[ $PWD == "$before" ]]; then
|
||||||
|
printf '\033[A' >/dev/tty
|
||||||
|
zle reset-prompt
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
zle -N gho-inline _zle-gho
|
||||||
|
|
||||||
|
# ctrl-p, and down on an idle empty prompt (fish's _pj_bind_down; otherwise
|
||||||
|
# normal history / multiline movement). pj reports through $PJ_STATE: `open`
|
||||||
|
# = cancelled, `ran` = a task printed output, empty = no task sources
|
||||||
|
# (PJ_QUIET keeps down silent outside projects).
|
||||||
|
_zle-pj() {
|
||||||
|
if [[ $WIDGET == pj-down && -n $BUFFER ]]; then
|
||||||
|
zle down-line-or-history
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
local state
|
||||||
|
state=$(mktemp) || return
|
||||||
|
zle -I
|
||||||
|
if [[ $WIDGET == pj-down ]]; then
|
||||||
|
PJ_STATE=$state PJ_QUIET=1 pj </dev/tty
|
||||||
|
else
|
||||||
|
PJ_STATE=$state pj </dev/tty
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
zle -N pj-down _zle-pj
|
||||||
|
|
||||||
bindkey '^E' tv-git-files
|
bindkey '^E' tv-git-files
|
||||||
bindkey '^B' run-purple
|
bindkey '^B' run-purple
|
||||||
bindkey '^Y' run-clip-last
|
bindkey '^Y' run-clip-last
|
||||||
bindkey '^O' run-gho
|
bindkey '^O' gho-inline
|
||||||
bindkey '^P' run-pj
|
bindkey '^P' pj-inline
|
||||||
bindkey '^A' run-omp
|
bindkey '^A' run-omp
|
||||||
# ctrl-f: yazi; yy cd's to yazi's exit dir on quit.
|
# ctrl-f: yazi; yy cd's to yazi's exit dir on quit.
|
||||||
bindkey '^F' run-yy
|
bindkey '^F' run-yy
|
||||||
bindkey '^G' run-lazygit
|
bindkey '^G' run-lazygit
|
||||||
|
|
||||||
# down: the pj cable on an idle, empty prompt; otherwise normal history /
|
|
||||||
# multiline movement (fish's _pj_bind_down). PJ_QUIET makes it a silent no-op
|
|
||||||
# outside projects.
|
|
||||||
_zle-pj-down() {
|
|
||||||
if [[ -n $BUFFER ]]; then
|
|
||||||
zle down-line-or-history
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
zle -I
|
|
||||||
PJ_QUIET=1 pj </dev/tty
|
|
||||||
zle reset-prompt
|
|
||||||
}
|
|
||||||
zle -N pj-down _zle-pj-down
|
|
||||||
bindkey '^[[B' pj-down
|
bindkey '^[[B' pj-down
|
||||||
bindkey '^[OB' pj-down
|
bindkey '^[OB' pj-down
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user