I had a very simple plug-in to preview colors in the buffer by coloring the background of #rrggbb text.
declare-option -hidden range-specs palette
define-command -hidden palette-update %{
try %{
evaluate-commands -draft -save-regs '/DV' %{
execute-keys '<space>;gtGb'
set-register / '(?:#|rgb:)([0-9A-Fa-f]{6})'
execute-keys 's<ret>'
set-option window palette %val(timestamp)
evaluate-commands -no-hooks -draft -itersel %{
# Save description
set-register D %val(selection_desc)
# Select value
execute-keys '1s<ret>'
# Save value
set-register V %reg(.)
set-option -add window palette "%reg(D)|default,rgb:%reg(V)"
}
}
} catch %{
unset-option window palette
}
}
define-command palette-enable -docstring 'Enable color preview' %{
add-highlighter window/palette ranges palette
hook -group palette window NormalIdle '' palette-update
}
define-command palette-disable -docstring 'Disable color preview' %{
remove-highlighter window/palette
remove-hooks window palette
}
We select the view-port and iterate each selection matching #rrggbb or rgb:rrggbb to update the Palette option with the selection description and color value. The all with no shell call.
But yesterday @andreyorst asked and showed me a way to tweak the foreground of #rrggbb text so that the text never gets dimmed by the background.
evaluate-commands -no-hooks -draft -itersel %{
set-register B %reg(.)
set-register F %sh(printf '%s' "$kak_main_reg_dot" | tr '0123456789ABCDEFabcdef' 'fedcba9876543210543210')
set-option -add window palette "%reg(D)|rgb:%reg(F),rgb:%reg(B)"
}
It works by inverting the color of the foreground with the background using the tr program. Which works great. But now a shell is paid for each selection.
So I was tempted to use @SolitudeSF鈥檚 approach to pass the whole buffer to an external program:
define-command colorcol-refresh %{
evaluate-commands %sh{
colorcol "$kak_timestamp" "$kak_buffile" "$kak_opt_colorcol_char"
}
}
But by doing that we lose all the niceties that Kakoune provides for selecting and iterating a selection set. It鈥檚 quite a shame somehow, we can鈥檛 efficiently leverage Kakoune鈥檚 language once a shell is involved.
So what if edit and write could read and write to and from the Kakoune internals?
It reminded me the way [fibers] work on [Crystal]. So I was thinking on a similar feature.
Adapted to Kakoune, it could be:
palette-update: write and edit at L18-19palette-enable: evaluate-commands shell blockpalette-disable: nop shell blockdeclare-option -hidden range-specs palette_highlighter
declare-option -hidden str palette_messaging
define-command -hidden palette-update %{
try %{
evaluate-commands -draft -save-regs '/BDF' %{
execute-keys '<space>;gtGb'
set-register / '(?:#|rgb:)([0-9A-Fa-f]{6})'
execute-keys 's<ret>'
set-option window palette_highlighter %val(timestamp)
evaluate-commands -no-hooks -draft -itersel %{
# Save description
set-register D %val(selection_desc)
# Select value
execute-keys '1s<ret>'
# Save value
set-register B %reg(.)
write "%opt(palette_messaging)/invert-message" -from %val(main_reg_dot)
edit "%opt(palette_messaging)/invert-response" -to reg F
set-option -add window palette_highlighter "%reg(D)|rgb:%reg(F),rgb:%reg(B)"
}
}
} catch %{
unset-option window palette_highlighter
}
}
define-command palette-enable -docstring 'Enable color preview' %{
evaluate-commands %sh{
messaging=$(mktemp -d)
mkfifo "$messaging/invert-message" "$messaging/invert-response"
printf 'set-option window palette_messaging %s' "$messaging"
invert_listen() {
while test $? = 0; do
tr '0123456789ABCDEFabcdef' 'fedcba9876543210543210' < "$messaging/invert-message" > "$messaging/invert-response"
done < /dev/null > /dev/null 2>&1 &
}
invert_listen
}
add-highlighter window/palette ranges palette
hook -group palette window NormalIdle '' palette-update
}
define-command palette-disable -docstring 'Disable color preview' %{
nop %sh{
rm "$kak_opt_palette_messaging/invert-message" "$kak_opt_palette_messaging/invert-response"
rmdir "$kak_opt_palette_messaging"
}
remove-highlighter window/palette
remove-hooks window palette
}
Now the shell is invoked once, when enabling the Palette plug-in.
I think this can be an interesting direction to make some common cases easier to write, however I am not really keen on overloading write/edit, I think I would be more comfortable with the following:
echo -to <filename> ... # same as echo but writes to the given filename instead of to the status line
set global my-option %read{filename} # the new `read` expansion expands to the content of given filename
We might need to make %read expand % strings inside its own parameter so that your example works (that would be %read{%opt{palette_messaging}/invert-response}) or require to use evaluate-commands set-register blah "%%read{%opt{palette_messaging}/invert-response}".
The nice thing is that this could solve the problem with too big env vars, we could just echo -to /tmp/kak-history "%val{history}" before entering the shell scope that would read it.
I find the expansion difficult to use with dynamic paths.
Well, we could make %file{...} expand its parameter to alleviate that problem. I think using an expansion makes sense as it means we can use it with existing commands (set-register, set-option, ...) instead of inventing special syntax for that, but making it convenient to use is important as well.
Is it difficult to use in the use case your presented ? Is the evaluate-commands trick not nice enoug ?
I was thinking we would likely fix most of the dynamic paths use by introducing a session tmp directory that could be used, so instead of having to mktmp directories, we could just use $kak_session_tmp_dir/my-well-known-path.
The syntax is cumbersome but it does the trick yep.
Otherwise I like the idea of a session temp directory.
I added a [comment] for @mawww on [Discuss].
Most helpful comment
Well, we could make
%file{...}expand its parameter to alleviate that problem. I think using an expansion makes sense as it means we can use it with existing commands (set-register, set-option, ...) instead of inventing special syntax for that, but making it convenient to use is important as well.Is it difficult to use in the use case your presented ? Is the
evaluate-commandstrick not nice enoug ?I was thinking we would likely fix most of the dynamic paths use by introducing a session tmp directory that could be used, so instead of having to mktmp directories, we could just use
$kak_session_tmp_dir/my-well-known-path.