├── LICENSE
├── README.md
├── luar.asciidoc
├── luar.fnl
├── luar.kak
├── luar.lua
└── luarmodule.lua
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Luar
2 |
3 | Luar is a minimalist plugin to script [Kakoune](http://kakoune.org/) using
4 | either [Lua](https://www.lua.org/) or [Fennel](https://fennel-lang.org/). It's
5 | not designed to expose Kakoune's internals like
6 | [Vis](https://github.com/martanne/vis) or [Neovim](https://neovim.io/) do.
7 | Instead, it's conceived with Kakoune's extension model in mind. It does so by
8 | defining a sole `lua` command which can execute whatever string is passed to it
9 | in an external `lua` interpreter, and an equivalent `fennel` command which
10 | executes whatever string is passed to it in an external `fennel` interpreter. By
11 | doing so, it can act as a complement for the `%sh{}` expansion when you need to
12 | run some logic inside Kakoune.
13 |
14 | ## Usage
15 |
16 | First of all, require the provided module:
17 |
18 | ```kak
19 | require-module luar
20 | ```
21 |
22 | The `luar` module exports a `lua` command, which executes the code passed to it in an external `lua` interpreter. The code is interpreted as the body of an anonymous function, and whatever this anonymous function returns replaces the current selections.
23 |
24 | So, the following code:
25 |
26 | ```lua
27 | lua %{
28 | return "Olá!"
29 | }
30 | ```
31 | replaces your selections with `Olá!`.
32 |
33 | The module also exposes a `fennel` command with the same semantics. See section
34 | [Executing fennel code](https://github.com/gustavo-hms/luar#executing-fennel-code) for some examples.
35 |
36 | In the same vein, if you have, say, three selections, the code:
37 |
38 | ```lua
39 | lua %{
40 | return 17, 19, 23
41 | }
42 | ```
43 |
44 | replaces each selection with `17`, `19` and `23` respectivelly. The same can be achieved by returning a single table with three elements:
45 |
46 |
47 | ```lua
48 | lua %{
49 | return {17, 19, 23}
50 | }
51 | ```
52 |
53 | The two forms are equivalent.
54 |
55 | If, on the other hand, you return nothing, the content of the selections won't be modified:
56 |
57 | ```lua
58 | lua %{
59 | if true then
60 | return
61 | end
62 | }
63 | ```
64 |
65 | The anonymous function can take arguments by passing values before the `%{}` block:
66 |
67 | ```lua
68 | lua 17 19 %{
69 | return arg[1] + arg[2]
70 | }
71 | ```
72 |
73 | The above code will replace all the selections with `36`. As you can see, the arguments can be accessed with the `arg` table.
74 |
75 | As a convenience, you can use the provided `args` function to name your arguments:
76 |
77 | ```lua
78 | lua 17 19 %{
79 | local first, second = args()
80 | return second - first
81 | }
82 | ```
83 |
84 | Since Kakoune does not process expansions inside these `lua %{}` blocks, you need to pass expansions as arguments if you need to inspect Kakoune's state:
85 |
86 | ```lua
87 | lua %val{client} %{
88 | local client = args()
89 | kak.echo(string.format("I'm client “%s”", client))
90 | }
91 | ```
92 |
93 | ## Calling commands
94 |
95 | You can run all commands defined in Kakoune (including third party ones) from `lua` code using the provided `kak` module:
96 |
97 | ```kak
98 | define-command custom-echo -params 1.. %{
99 | echo %arg{@}
100 | }
101 |
102 | lua %{
103 | kak.set_register("/", "Search this!")
104 | kak.execute_keys('%scSearch that!')
105 | -- Calling custom commands is also possible.
106 | kak.custom_echo("Text selected!")
107 | }
108 | ```
109 | As you can see, hyphens are replaced by underscores in command names. Luar also takes care of quoting the arguments to avoid unexpected results.
110 |
111 | ## Executing fennel code
112 |
113 | Anything you can do with the `lua` command you can do with the equivalent `fennel` command. So, to replace your selections with the string `"Olá!"`:
114 | ```fennel
115 | fennel %{
116 | "Olá!"
117 | }
118 | ```
119 | Or, to replace three selections with some numbers:
120 | ```fennel
121 | fennel %{
122 | (values 17 19 23)
123 | }
124 | ```
125 |
126 | Expansions work the same way:
127 |
128 | ```fennel
129 | fennel %val{client} %{
130 | (let [client (args)]
131 | (kak.echo (string.format "I'm client “%s”" client)))
132 | }
133 | ```
134 |
135 | The only difference is that you don't need to replace hyphens with underscores in command names:
136 |
137 | ```kak
138 | define-command custom-echo -params 1.. %{
139 | echo %arg{@}
140 | }
141 |
142 | fennel %{
143 | (kak.set-register "/" "Search this!")
144 | (kak.execute-keys "%scSearch that!")
145 | (kak.custom-echo "Text selected!")
146 | }
147 | ```
148 |
149 | ## External modules
150 |
151 | Since Lua modules are just plain tables and `require` is just a simple function, you can import modules everywhere in your program, not just at the beginning of a file. In particular, you can import external modules inside the `:lua` command. For instance, if you need to parse the contents of a file, you can use the elegant [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/) library:
152 |
153 | ```lua
154 | lua %val{buffile} %{
155 | local lpeg = require "lpeg"
156 |
157 | local function parse(file)
158 | -- do the lpeg's magic here
159 | end
160 |
161 | local tree = parse(arg[1])
162 | -- ...
163 | }
164 | ```
165 |
166 | You can also use this functionality to split your plugin into separate modules
167 | and use `:lua` to glue them together. To make that easier, `luar` provides the
168 | `addpackagepath` convenience function. It configures the lua interpreter to
169 | search for lua modules in the provided directory. It's meant to be used like
170 | this:
171 |
172 | ```kak
173 | declare-option -hidden str my_plugin_path %sh{ dirname $kak_source }
174 |
175 | define-command my-command %{
176 | lua %opt{my_plugin_path} %{
177 | addpackagepath(arg[1])
178 | local module = require "my_local_module"
179 | -- ...
180 | }
181 | }
182 | ```
183 |
184 | ## Debugging
185 |
186 | Passing the `-debug` flag, the `luar` command will print in the `*debug*` buffer all Kakoune commands it would otherwise execute. This way, you can see the exact commands your script would execute. For instance, running
187 |
188 | ```kak
189 | lua -debug %val{client} %{
190 | local keys = "%ssomethingcanything"
191 | kak.execute_keys(keys)
192 | kak.echo("Word something replaced by word anything on client " .. arg[1])
193 | kak.write()
194 | }
195 | ```
196 | would print the following text in the debug buffer:
197 | ```
198 | luar: execute-keys %☾%ssomethingcanything☾
199 | luar: echo %☾Word something replaced by word anything on client client0☾
200 | luar: write
201 | ```
202 |
203 | ## Some examples
204 | The following examples are for didactic purposes. There are other ways to achieve the same results.
205 |
206 | Suppose you want to execute `ctags-update-tags` whenever you write to a file, but only if there's already a `tags` file in the current directory. Using `:lua` you can write the following lines to your `kakrc`:
207 |
208 | ```lua
209 | hook global BufWritePost .* %{
210 | lua %{
211 | if io.open("tags") then kak.ctags_update_tags() end
212 | }
213 | }
214 | ```
215 |
216 | Now suppose you want to define a mapping to toggle the highlight of search patterns in the current window when you press `F2`. To achieve that, you can do something like this:
217 |
218 | ```lua
219 | declare-option -hidden bool highlight_search_on false
220 |
221 | define-command highlight-search-toggle %{
222 | lua %opt{highlight_search_on} %{
223 | local is_on = args()
224 |
225 | if is_on then
226 | kak.remove_highlighter("window/highlight-search")
227 | else
228 | kak.add_highlighter("window/highlight-search", "dynregex", "%reg{/}", "0:default,+ub")
229 | end
230 |
231 | kak.set_option("window", "highlight_search_on", not is_on)
232 | }
233 | }
234 |
235 | map global normal ': highlight-search-toggle'
236 | ```
237 |
238 | You can find more examples [searching Github by topic](https://github.com/search?q=topic%3Akakoune+topic%3Aplugin+topic%3Alua).
239 |
240 | ## Installation
241 |
242 | You must have a `lua` interpreter installed on your system. Then you can add the following line to your `kakrc` (supposing you use [plug.kak](https://github.com/robertmeta/plug.kak)):
243 |
244 | ```kak
245 | plug "gustavo-hms/luar" %{
246 | require-module luar
247 | }
248 | ```
249 |
250 | ## Configuration
251 |
252 | You can also change the Lua interpreter used by this plugin by changing the `luar_interpreter` option, e.g.:
253 |
254 | ```kak
255 | # use luajit to run all Lua snippets
256 | set-option global luar_interpreter luajit
257 | ```
258 |
--------------------------------------------------------------------------------
/luar.asciidoc:
--------------------------------------------------------------------------------
1 | == Luar
2 |
3 | Luar is a minimalist plugin to script Kakoune using either Lua or Fennel. It’s
4 | not designed to expose Kakoune’s internals like Vis or Neovim do. Instead, it’s
5 | conceived with Kakoune’s extension model in mind. It does so by defining a sole
6 | `lua` command which can execute whatever string is passed to it in an external
7 | `lua` interpreter, and an equivalent `fennel` command which executes whatever
8 | string is passed to it in an external `fennel` interpreter. By doing so, it can
9 | act as a complement for the `%sh{}` expansion when you need to run some logic
10 | inside Kakoune.
11 |
12 | === Usage
13 |
14 | First of all, require the provided module:
15 |
16 | ----
17 | require-module luar
18 | ----
19 |
20 | The `luar` module exports a `lua` command, which executes the code
21 | passed to it in an external `lua` interpreter. The code is interpreted
22 | as the body of an anonymous function, and whatever this anonymous
23 | function returns replaces the current selections.
24 |
25 | So, the following code:
26 |
27 | ----
28 | lua %{
29 | return "Olá!"
30 | }
31 | ----
32 |
33 | replaces your selections with `Olá!`.
34 |
35 | The module also exposes a `fennel` command with the same semantics. See section
36 | _Executing fennel code_ for some examples.
37 |
38 | In the same vein, if you have, say, three selections, the code:
39 |
40 | ----
41 | lua %{
42 | return 17, 19, 23
43 | }
44 | ----
45 |
46 | replaces each selection with `17`, `19` and `23` respectivelly.
47 | The same can be achieved by returning a single table with three
48 | elements:
49 |
50 | ----
51 | lua %{
52 | return {17, 19, 23}
53 | }
54 | ----
55 |
56 | The two forms are equivalent.
57 |
58 | If, on the other hand, you return nothing, the content of the selections
59 | won’t be modified:
60 |
61 | ----
62 | lua %{
63 | if true then
64 | return
65 | end
66 | }
67 | ----
68 |
69 | The anonymous function can take arguments by passing values before the
70 | `%{}` block:
71 |
72 | ----
73 | lua 17 19 %{
74 | return arg[1] + arg[2]
75 | }
76 | ----
77 |
78 | The above code will replace all the selections with `36`. As you can
79 | see, the arguments can be accessed with the `arg` table.
80 |
81 | As a convenience, you can use the provided `args` function to name
82 | your arguments:
83 |
84 | ----
85 | lua 17 19 %{
86 | local first, second = args()
87 | return second - first
88 | }
89 | ----
90 |
91 | Since Kakoune does not process expansions inside these `lua %{}`
92 | blocks, you need to pass expansions as arguments if you need to inspect
93 | Kakoune’s state:
94 |
95 | ----
96 | lua %val{client} %{
97 | local client = args()
98 | kak.echo(string.format("I'm client “%s”", client))
99 | }
100 | ----
101 |
102 | === Calling custom commands
103 |
104 | You can run all commands defined in Kakoune (including third
105 | party ones) from `lua` code using the provided `kak` module:
106 |
107 | ----
108 | define-command custom-echo -params 1.. %{
109 | echo %arg{@}
110 | }
111 |
112 | lua %{
113 | kak.set_register("/", "Search this!")
114 | kak.execute_keys('%scSearch that!')
115 | -- Calling custom commands is also possible.
116 | kak.custom_echo("Text selected!")
117 | }
118 | ----
119 |
120 | As you can see, hyphens are replaced by underscores in command names.
121 | Luar also takes care of quoting the arguments to avoid unexpected
122 | results.
123 |
124 | === Executing fennel code
125 |
126 | Anything you can do with the `lua` command you can do with the
127 | equivalent `fennel` command. So, to replace your selections with the
128 | string `"Olá!"`:
129 |
130 | ----
131 | fennel %{
132 | "Olá!"
133 | }
134 | ----
135 |
136 | Or, to replace three selections with some numbers:
137 |
138 | ----
139 | fennel %{
140 | (values 17 19 23)
141 | }
142 | ----
143 |
144 | Expansions work the same way:
145 |
146 | ----
147 | fennel %val{client} %{
148 | (let [client (args)]
149 | (kak.echo (string.format "I'm client “%s”" client)))
150 | }
151 | ----
152 |
153 | The only difference is that you don’t need to replace hyphens with
154 | underscores in command names:
155 |
156 | ----
157 | define-command custom-echo -params 1.. %{
158 | echo %arg{@}
159 | }
160 |
161 | fennel %{
162 | (kak.set-register "/" "Search this!")
163 | (kak.execute-keys "%scSearch that!")
164 | (kak.custom-echo "Text selected!")
165 | }
166 | ----
167 |
168 | === External modules
169 |
170 | Since Lua modules are just plain tables and `require` is just a simple
171 | function, you can import modules everywhere in your program, not just at
172 | the beginning of a file. In particular, you can import external modules
173 | inside the `:lua` command. For instance, if you need to parse the
174 | contents of a file, you can use the elegant [LPeg] library:
175 |
176 | ----
177 | lua %val{buffile} %{
178 | local lpeg = require "lpeg"
179 |
180 | local function parse(file)
181 | -- do the lpeg's magic here
182 | end
183 |
184 | local tree = parse(arg[1])
185 | -- ...
186 | }
187 | ----
188 |
189 | You can also use this functionality to split your plugin into separate
190 | modules and use `:lua` to glue them together. To make that easier,
191 | `luar` provides the `addpackagepath` convenience function. It
192 | configures the lua interpreter to search for lua modules in the provided
193 | directory. It’s meant to be used like this:
194 |
195 | ----
196 | declare-option -hidden str my_plugin_path %sh{ dirname $kak_source }
197 |
198 | define-command my-command %{
199 | lua %opt{my_plugin_path} %{
200 | addpackagepath(arg[1])
201 | local module = require "my_local_module"
202 | -- ...
203 | }
204 | }
205 | ----
206 |
207 | === Debugging
208 |
209 | Passing the `-debug` flag, the `luar` command will print in the
210 | `*debug*` buffer all Kakoune commands it would otherwise execute. This
211 | way, you can see the exact commands your script would execute. For
212 | instance, running
213 |
214 | ----
215 | lua -debug %val{client} %{
216 | local keys = "%ssomethingcanything"
217 | kak.execute_keys(keys)
218 | kak.echo("Word something replaced by word anything on client " .. arg[1])
219 | kak.write()
220 | }
221 | ----
222 |
223 | would print the following text in the debug buffer:
224 |
225 | ----
226 | luar: execute-keys %☾%ssomethingcanything☾
227 | luar: echo %☾Word something replaced by word anything on client client0☾
228 | luar: write
229 | ----
230 |
231 | === Some examples
232 |
233 | The following examples are for didactic purposes. There are other ways
234 | to achieve the same results.
235 |
236 | Suppose you want to execute `ctags-update-tags` whenever you write to
237 | a file, but only if there’s already a `tags` file in the current
238 | directory. Using `:lua` you can write the following lines to your
239 | `kakrc`:
240 |
241 | ----
242 | hook global BufWritePost .* %{
243 | lua %{
244 | if io.open("tags") then kak.ctags_update_tags() end
245 | }
246 | }
247 | ----
248 |
249 | Now suppose you want to define a mapping to toggle the highlight of
250 | search patterns in the current window when you press `F2`. To achieve
251 | that, you can do something like this:
252 |
253 | ----
254 | declare-option -hidden bool highlight_search_on false
255 |
256 | define-command highlight-search-toggle %{
257 | lua %opt{highlight_search_on} %{
258 | local is_on = args()
259 |
260 | if is_on then
261 | kak.remove_highlighter("window/highlight-search")
262 | else
263 | kak.add_highlighter("window/highlight-search", "dynregex", "%reg{/}", "0:default,+ub")
264 | end
265 |
266 | kak.set_option("window", "highlight_search_on", not is_on)
267 | }
268 | }
269 |
270 | map global normal ': highlight-search-toggle'
271 | ----
272 |
273 | === Configuration
274 |
275 | You can also change the Lua interpreter used by this plugin by changing
276 | the `luar_interpreter` option, e.g.:
277 |
278 | ----
279 | # use luajit to run all Lua snippets
280 | set-option global luar_interpreter luajit
281 | ----
282 |
--------------------------------------------------------------------------------
/luar.fnl:
--------------------------------------------------------------------------------
1 | (local fennel (require :fennel))
2 | (local luar (require :luarmodule))
3 |
4 | (set _G.kak luar.kak)
5 | (set _G.args luar.args)
6 | (set _G.addpackagepath luar.addpackagepath)
7 |
8 | (fn eval [chunk]
9 | (fennel.eval chunk {:env _G :filename "fennel" :unfriendly true}))
10 |
11 | (fn abort [_ chunk err]
12 | (let [message "error while executing fennel block:\n\nfennel %%{%s}\n\n%s\n"]
13 | (luar.debug (message:format chunk err))
14 | (print "fail \"'fennel': check *debug* buffer\"")
15 | (os.exit 1)))
16 |
17 | (luar.execute eval abort)
18 |
--------------------------------------------------------------------------------
/luar.kak:
--------------------------------------------------------------------------------
1 | declare-option -hidden str luar_path %sh{ dirname "$kak_source" }
2 |
3 | declare-option -docstring "The Lua interpreter used to execute Lua code" str luar_interpreter lua
4 |
5 | provide-module luar %#
6 | define-command lua -params 1.. -docstring %{
7 | lua [] [args...] code: Execute provided Lua code as an anonymous function whose arguments are the args list.
8 | Switches:
9 | -debug Print Kakoune commands to *debug* buffer instead of executing them.
10 | } %{
11 | evaluate-commands %sh{
12 | export LUA_PATH="$kak_opt_luar_path/?.lua;$LUA_PATH"
13 | exec "$kak_opt_luar_interpreter" "$kak_opt_luar_path/luar.lua" "$@"
14 | }
15 | }
16 |
17 | define-command fennel -params 1.. -docstring %{
18 | fennel [] [args...] code: Execute provided Fennel code as an anonymous function whose arguments are the args list.
19 | Switches:
20 | -debug Print Kakoune commands to *debug* buffer instead of executing them.
21 | } %{
22 | evaluate-commands %sh{
23 | export LUA_PATH="$kak_opt_luar_path/?.lua;$LUA_PATH"
24 |
25 | if [ $kak_opt_luar_interpreter != "lua" ]; then
26 | exec fennel --lua "$kak_opt_luar_interpreter" "$kak_opt_luar_path/luar.fnl" "$@"
27 | else
28 | exec fennel "$kak_opt_luar_path/luar.fnl" "$@"
29 | fi
30 | }
31 | }
32 |
33 | require-module kak
34 | require-module lua
35 | require-module fennel
36 |
37 | add-highlighter shared/kakrc/code/lua regex (?:\s|\A)\Klua(?:(?=\s)|\z) 0:keyword
38 | add-highlighter shared/kakrc/lua1 region -recurse '\{' '(^|\h)lua([\s{}\w%/$-|''"])* %\{\K' '\}' ref lua
39 | add-highlighter shared/kakrc/lua2 region -recurse '\(' '(^|\h)lua([\s{}\w%/$-|''"])* %\(\K' '\)' ref lua
40 | add-highlighter shared/kakrc/lua3 region -recurse '\[' '(^|\h)lua([\s{}\w%/$-|''"])* %\[\K' '\]' ref lua
41 | add-highlighter shared/kakrc/lua4 region -recurse '<' '(^|\h)lua([\s{}\w%/$-|''"])* %<\K' '>' ref lua
42 |
43 | add-highlighter shared/kakrc/code/fennel regex (?:\s|\A)\Kfennel(?:(?=\s)|\z) 0:keyword
44 | add-highlighter shared/kakrc/fennel1 region -recurse '\{' '(^|\h)fennel([\s{}\w%/$-|''"])* %\{\K' '\}' ref fennel
45 | add-highlighter shared/kakrc/fennel2 region -recurse '\(' '(^|\h)fennel([\s{}\w%/$-|''"])* %\(\K' '\)' ref fennel
46 | add-highlighter shared/kakrc/fennel3 region -recurse '\[' '(^|\h)fennel([\s{}\w%/$-|''"])* %\[\K' '\]' ref fennel
47 | add-highlighter shared/kakrc/fennel4 region -recurse '<' '(^|\h)fennel([\s{}\w%/$-|''"])* %<\K' '>' ref fennel
48 | #
49 |
--------------------------------------------------------------------------------
/luar.lua:
--------------------------------------------------------------------------------
1 | local luar = require 'luarmodule'
2 |
3 | args, kak, addpackagepath = luar.args, luar.kak, luar.addpackagepath
4 |
5 | local function abort(action, chunk, err)
6 | err = err:match('%[string "luar"%]:(.+)') or err
7 | local message = "error while %s lua block:\n\nlua %%{%s}\n\nlua:%s\n"
8 | luar.debug(message:format(action, chunk, err))
9 | print([[fail "'lua': check *debug* buffer"]])
10 | os.exit(1)
11 | end
12 |
13 | local function eval(chunk)
14 | local fn, err = load(chunk, "luar")
15 | if not fn then abort("parsing", chunk, err) end
16 | return fn()
17 | end
18 |
19 | luar.execute(eval, abort)
20 |
--------------------------------------------------------------------------------
/luarmodule.lua:
--------------------------------------------------------------------------------
1 | local function debug(text)
2 | local first = true
3 |
4 | if not text:find("\n") then
5 | -- We need to insert a newline here to be able to use pattern bellow
6 | -- instead of just using `[^\n]*`. The later pattern can't be use because
7 | -- otherwise luajit would insert random newlines at the end of the match.
8 | text = text .. "\n"
9 | end
10 |
11 | for line in text:gmatch('([^\n]*)\n') do
12 | if first then
13 | print(string.format([[echo -debug %%☽luar: %s☽]], line))
14 | first = false
15 | else
16 | print(string.format([[echo -debug %%☽ %s☽]], line))
17 | end
18 | end
19 | end
20 |
21 | local function quote(words)
22 | for i, v in ipairs(words) do
23 | words[i] = string.format("%%☾%s☾", v)
24 | end
25 |
26 | return table.concat(words, " ")
27 | end
28 |
29 | local function args()
30 | local unpack = unpack or table.unpack
31 | return unpack(arg)
32 | end
33 |
34 | local function addpackagepath(path)
35 | package.path = string.format("%s/?.lua;%s", path, package.path)
36 | end
37 |
38 | local write = print
39 |
40 | local kak = setmetatable({}, {
41 | __index = function(t, command)
42 | local name = command:gsub("_", "-")
43 | t[command] = function(...)
44 | write(name .. " " .. quote { ... })
45 | end
46 |
47 | return t[command]
48 | end
49 | })
50 |
51 | local function parseargs()
52 | local chunk = arg[#arg]
53 | arg[0], arg[#arg] = nil, nil -- Hide file name and chunk
54 | local debug_flag
55 |
56 | for i, v in ipairs(arg) do
57 | if v == "-debug" then
58 | write = debug
59 | debug_flag = i
60 | elseif v == "true" then
61 | arg[i] = true
62 | elseif v == "false" then
63 | arg[i] = false
64 | else
65 | arg[i] = tonumber(v) or v
66 | end
67 | end
68 |
69 | if debug_flag then
70 | table.remove(arg, debug_flag)
71 | end
72 |
73 | return chunk
74 | end
75 |
76 | local function execute(fn, abort)
77 | local chunk = parseargs()
78 | local results = { pcall(fn, chunk) }
79 | if not results[1] then abort("executing", chunk, results[2]) end
80 |
81 | if #results > 1 then
82 | table.remove(results, 1)
83 | -- Allow returning either many values or a single table
84 | if type(results[1]) == "table" then results = results[1] end
85 |
86 | local command = string.format([[
87 | evaluate-commands -save-regs dquote %%{
88 | set-register dquote %s
89 | execute-keys R
90 | }
91 | ]], quote(results))
92 | print(command)
93 | end
94 | end
95 |
96 | return {
97 | args = args,
98 | addpackagepath = addpackagepath,
99 | kak = kak,
100 | execute = execute,
101 | debug = debug,
102 | }
103 |
--------------------------------------------------------------------------------