Skip to content

Instantly share code, notes, and snippets.

@adrusi
Last active April 10, 2022 01:56
Show Gist options
  • Save adrusi/5ec619d06ebe55746bb49422071a7206 to your computer and use it in GitHub Desktop.
Save adrusi/5ec619d06ebe55746bb49422071a7206 to your computer and use it in GitHub Desktop.
andreyorst/powerline.kak: resize modeline dynamically base on window size
kakquote() {
out=
for text; do
out=$out"'"
while :; do
case "$text" in
*\'*)
out=$out${text%%\'*}\'\'
text=${text#*\'}
;;
*)
out=$out$text"' "
break
;;
esac
done
done
printf '%s' "$out"
}
kakcork() {
for arg; do
printf '%s ' "$(kakquote "$arg")"
done
}
readonly _nl_="
"
if printf '%q' _ >/dev/null 2>/dev/null; then
cork() {
printf '%q \\\n' "$@"
printf ' '
}
quote() {
printf '%q\n' "$1"
}
else
cork() {
for prelude_arg do
printf '%s' "$prelude_arg" |
tr '\n' '\033' |
sed "s/'/'\\\\''/g;s/"$(printf '\033')"/'\"\$_nl_\"'/g;1s/^/'/;\$s/\$/' \\\\/"
printf '\n'
done
}
quote() {
printf '%s' "$1" |
tr '\n' '\033' |
sed "s/'/'\\\\''/g;s/"$(printf '\033')"/'\"\$_nl_\"'/g;1s/^/'/;\$s/\$/'/"
printf '\n'
}
fi
require-module powerline
declare-option -docstring "a list of powerline modules in descending priority
order. lower-priority modules will be preferentially removed when there isn't
space enough for the whole set." \
str-list powerline_module_priority mode_info bufname position filetype client \
session line_column lsp git codepoint custom-static
declare-option -docstring "interval without any hooks that trigger
powerline-resize firing, in milliseconds." \
int powerline_resize_delay 50
define-command -docstring "install the necessary hooks to trigger
powerline-resize" \
powerline-resize-enable %{
remove-hooks buffer powerline-resize
hook -group powerline-resize buffer WinResize .* schedule-powerline-resize
hook -group powerline-resize buffer WinDisplay .* schedule-powerline-resize
hook -group powerline-resize buffer User PowerlineChange schedule-powerline-resize
}
declare-option -hidden str approximate_modeline ""
declare-option -hidden str powerline_format_orig %opt{powerline_format}
define-command -hidden -params 0..2 resize-powerline %{
# There's no way to know the precise width of the powerline since kakoune
# doesn't provide any way of knowing what {{mode_info}} or {{context_info}}
# expand to. Fortunately we only need an approximation, and we want to err
# towards overestimation.
evaluate-commands %sh{
printf 'set-option buffer approximate_modeline "'
printf %s\\n "$kak_opt_modelinefmt" | sed -E '
s/%(opt|val|sh|arg|reg)\{/%\1{'$(printf '\033')'/g;
s/\{[a-z-]+(,[a-z-]+)?(,[a-z]+)?(\+[rbBdisFfga]+)?(@[a-zA-Z_]+)?\}//g
s/'$(printf '\033')'//g
s/\{\{(mode_info|context_info)\}\}/ /g
s/"/""/g
'
# }}
printf '"\n'
}
evaluate-commands %sh{
. prelude.inc.sh
. kak.inc.sh
width=$(printf '%s' "$kak_opt_approximate_modeline" | wc -m)
normalize() {
printf %s\\n "$*"
}
shrink() {
[ "$kak_window_width" -le "$width" ] || return
once=false
[ "$1" = once ] && once=true
eval set -- $kak_opt_powerline_module_priority
reversed=""
for module; do reversed="$module $reversed"; done
eval set -- $reversed
for module; do
if printf %s\\n "$kak_opt_powerline_format" |
grep $module >/dev/null
then
newfmt="$(printf %s\\n "$kak_opt_powerline_format" |
sed "s/$module//")"
printf 'set-option buffer powerline_format %s\n' \
"$(kakquote "$newfmt")"
printf 'powerline-rebuild-buffer\n'
$once || printf 'resize-powerline shrink\n'
return
fi
done
}
grow() {
[ "$width" -le "$kak_window_width" ] || return
[ "$(normalize $kak_opt_powerline_format)" \
= "$(normalize $kak_opt_powerline_format_orig)" ] \
&& return
eval set -- $kak_quoted_opt_powerline_module_priority
for m1; do
if ! printf %s\\n "$kak_opt_powerline_format" |
grep "$m1" >/dev/null
then
(
oldfmt="$kak_opt_powerline_format"
newfmt=""
eval set -- $kak_opt_powerline_format_orig
for m2; do
if [ "$m1" = "$m2" ]; then
newfmt="$newfmt "$m1" $oldfmt"
printf 'set-option buffer powerline_format %s\n' \
"$(kakquote "$newfmt")"
printf 'powerline-rebuild-buffer\n'
printf 'resize-powerline grow\n'
return
fi
read -r head_old tail_old <<EOF
$oldfmt
EOF
if [ "$head_old" = "$m2" ]; then
newfmt="$newfmt $head_old"
oldfmt="$tail_old"
fi
done
)
return
fi
done
}
if [ "$kak_window_width" -le "$width" ]
then if [ "$1" = grow ]
then shrink once
else shrink
fi
else [ "$1" != shrink ] && grow
fi
}
}
# When resize hooks fire, a lot fire at once, and resizing the powerline is slow.
# Instead of letting a bunch of calls to resize-powerline queue up, we wait for
# hooks to stop firing for powerline_resize_delay ms before doing anything.
declare-option -hidden int-list powerline_resize_jobs
declare-option -hidden int-list powerline_resize_jobs_tmp
define-command -hidden schedule-powerline-resize %{
evaluate-commands %sh{
(
sleep $(printf %s $kak_opt_powerline_resize_delay |
sed -E 's/^([0-9]{1,3})$/0.\1/;s/^([0-9]+)([0-9]{3})$/\1.\2/')
printf 'evaluate-commands -buffer %s "resize-powerline-wrapper %s"\n' \
"$kak_bufname" $$ | kak -p "$kak_session"
) >/dev/null 2>&1 </dev/null &
printf 'set-option -add buffer powerline_resize_jobs %s\n' $!
eval set -- $kak_opt_powerline_resize_jobs
for job; do
kill "$job" >/dev/null 2>&1 </dev/null &
done
printf 'set-option buffer powerline_resize_jobs\n'
}
}
# Window resizing is a property of the window, but unfortunately modelines
# are the property of the buffer. We need to find the narrowest client that's
# open to a window bound to the same buffer as the resized window, and then
# perform the resize computation on THAT window, otherwise if a window is
# resized while a narrower window is displaying the same buffer, the powerline
# will grow too large for the smaller one. Also there's a concurrency mess here.
declare-option -hidden bool powerline_resize_locked false
declare-option -hidden str-to-str-map powerline_resize_client_widths
declare-option -hidden str powerline_resize_narrowest_client
define-command -hidden -params 1 resize-powerline-wrapper %{
set-option buffer powerline_resize_jobs_tmp %opt{powerline_resize_jobs}
set-option buffer powerline_resize_jobs
try %{
evaluate-commands %sh{
invoking_job="$1"
eval set -- $kak_opt_powerline_resize_jobs_tmp
for job; do
case "$job" in
0|"$invoking_job") : ;;
*) kill "$job" >/dev/null 2>&1 </dev/null & ;;
esac
done
if $kak_opt_powerline_resize_locked; then
printf 'fail "powerline-resize locked"\n'
else
printf 'set-option buffer powerline_resize_locked true\n'
fi
}
echo -debug 'init_resize'
set-option buffer powerline_resize_client_widths
evaluate-commands %sh{
. kak.inc.sh
. prelude.inc.sh
eval set -- $kak_quoted_client_list
for client; do
printf 'evaluate-commands -client %s %%{
evaluate-commands %%sh{
if [ "$kak_bufname" = %s ]; then
printf %s "$kak_client" $kak_window_width
fi
}
}\n' "$(kakquote "$client")" "$(quote "$kak_bufname")" \
"'set-option -add buffer powerline_resize_client_widths %%{%s=%s}'"
done
}
evaluate-commands %sh{
eval set -- $kak_quoted_opt_powerline_resize_client_widths
if [ $# = 0 ]; then
printf 'fail "no clients?"\n'
return
fi
min=9999999
min_client=
for entry; do
client="${entry%%=*}"
width="${entry#*=}"
if [ "$width" -lt "$min" ]; then
min="$width"
min_client="$client"
fi
done
printf 'set-option buffer powerline_resize_narrowest_client %s\n' "$min_client"
}
evaluate-commands -client %opt{powerline_resize_narrowest_client} %{
remove-hooks buffer powerline-resize
resize-powerline whatever %arg{@}
powerline-resize-enable
}
set-option buffer powerline_resize_locked false
} catch %{
evaluate-commands %sh{
if [ "$kak_error" != "powerline-resize locked" ]; then
printf 'set-option buffer powerline_resize_locked false\n'
printf 'fail %%val{error}\n'
fi
}
}
}
evaluate-commands %sh{
. kak.inc.sh
eval set -- $kak_quoted_buflist
for buf; do
printf 'evaluate-commands -buffer %s powerline-resize-enable\n' \
"$(kakquote "$buf")"
done
}
hook -group init-powerline-resize global BufCreate .* powerline-resize-enable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment