Closed eko234 closed 2 years ago
Hi, @eko234! Sorry for taking so long to reply. It took me a time to elaborate on your question.
First of all: happy new year!
Regarding your question, the kak
module is minimalist by design: it's conceived to replicate Kakoune's command API and nothing else. That way, if you know how to call commands, you know kak
module's API. It's the same idea behind Kakoune scripting itself. That means that the functions provided by the kak
module return nothing, since Kakoune commands are statements, not expressions.
The only additional thing functions in the kak
module do is automatically converting their arguments from Lua's primitive types (like numbers and booleans) to Kakoune's equivalents.
That said, I must say that, in my experience writing scripts using luar, I've found the mechanisms provided by the kak
module flexible enough. Let me present you some tricks I've been using.
Since the kak
module gives you access to all Kakoune commands, you can, in particular, call define-command
. That alone gives you extreme flexibility to generate code based, for instance, on external data, if you need to do so.
define-command register-my-plugin-commands %{
lua %{
if os.getenv("TERM") == "xterm-kitty" then
kak.define_command("show-context", [[
kitty-terminal-tab ...
]])
else
kak.define_command("show-context", [[
new ...
]])
end
}
}
Personally, I tend to not use the kind of trick shown above, because usually there are better alternatives. One of them is factoring out your code into different commands and calling them as needed:
define-command -hidden show-context-on-new-tab %{
kitty-terminal-tab ...
}
define-command -hidden show-context-on-new-window %{
new ...
}
define-command show-context %{
lua %{
if os.getenv("TERM") == "xterm-kitty" then
kak.show_context_on_new_tab()
else
kak.show_context_on_new_window()
end
}
}
The true power comes when you realise lua
is just a regular Kakoune command, and you can mix and match lua code and Kakoune code. That leads to a better code organisation.
As I said, luar automatically converts Lua primitive types to Kakoune's types, making it possible to pass numbers, strings and booleans as arguments to Kakoune commands. But you can't pass higher order types, like tables and functions. So, there aren't such things as higher order functions in the kak
module.
On the other hand, Kakoune does have what we could call higher order commands: commands that receive a string as argument and interpret it as a code block, in a way as ergonomic as a Ruby or SmallTalk code block. All of that is possible because Kakoune offers us the excelent evaluate-commands
command. And you can take advantage of it to implement many interesting patterns.
Take for instance the peneira
command I've written for the plugin of the same name: it accepts three arguments, the second of which is supposed to be a shell command it executes to give back a list of candidates; and the third one is a kakscript block it executes when the user selects one of those candidates. Inside that kakscript block, the expansion %arg{1}
refers to the selected candidate. As you can see, it's a command that receives as argument a code block.
As a last suggestion, I'd recomend you to take a look at the peneira
plugin's code. It's a good use case for luar, since there I use many interesting tricks. Here I list some of them:
I use a lua
block to parse flags for a wrapping command just to call another wrapped hidden command with the arguments in the right order.
I needed to do some black magic string manipulation to generate kakscript code dinamically in order to make shell expansions to work in the second argument of the peneira
command.
I defined a separe lua module I then require
inside the kakscript code, thus avoiding having a single big and messy lua
block and, additionally, allowing me to reuse the same code in different places.
I mix and match Lua code and Kakscript code with no fear whenever I see a need for it.
All in all, I don't feel myself limited by the simplicity of the kak
module's API, quite on the contrary: since it fits so well inside Kakoune's scripting model, it feels almost like native code, not as a poor man's FFI.
I hope it can help. If you need extra clarifications, please ask.
Happy new year for your too and thanks for your very complete answer!
We are currently mixing languages here, but that's OK hahaha!
I just want to point out that, if performance is a concern, my advice is to simply try to make a prototype using idiomatic Kakoune and Lua codes with luar
and, only if you experience performance issues, resort to do everything in Lua using some dark magic.
In my experience writing peneira
(the most performance-sensitive project I wrote using luar
), I didn't experience performance problems. The lua
interpreter is not only very fast to execute code (possibly it's the fastest interpreter I know), but it also has very fast startup times. So, even if I have to call luar
multiple times (and, by that, spawn a new lua interpreter each time), that wasn't responsible for any slow down in my program.
Hi, I'm trying out luar, and I wanted to know if the methods provided by the kak module actually return values or if they might take higher order functions...
I'm particularly interested in using stuff like on-key and being able to stay in a lua block to define some commands, I'd guess it doesn't, but also wanted to know your perspective on the subject.