1 #include <inttypes.h>
2 #include "mle.h"
3
4 #define MLE_USCRIPT_KEY "_uscript"
5
6 #define MLE_USCRIPT_GET(pl, pu) do { \
7 lua_getglobal((pl), MLE_USCRIPT_KEY); \
8 (pu) = luaL_optpointer((pl), -1, NULL); \
9 if (!(pu)) return 0; \
10 } while(0)
11
12 #define luaL_pushkey(pL, pt, pk, pv) do { \
13 lua_pushstring((pL), (pk)); \
14 (lua_push ## pt) ((pL), (pv)); \
15 lua_settable((pL), -3); \
16 } while (0)
17
18 #define luaL_pushkey2(pL, pt, pk, pv1, pv2) do { \
19 lua_pushstring((pL), (pk)); \
20 (lua_push ## pt) ((pL), (pv1), (pv2)); \
21 lua_settable((pL), -3); \
22 } while (0)
23
24 static int _uscript_panic(lua_State *L);
25 static int _uscript_cmd_cb(cmd_context_t *ctx);
26 static int _uscript_observer_cb(char *event_name, void *event_data, void *udata);
27 static int _uscript_write(lua_State *L);
28 static void _uscript_push_event_map(uscript_t *uscript, char *event_name, void *event_data);
29 static void _uscript_push_cmd_map(lua_State *L, cmd_context_t *ctx);
30 static void _uscript_push_baction_map(lua_State *L, baction_t *baction);
31 static int _uscript_func_editor_prompt(lua_State *L);
32 static int _uscript_func_editor_register_cmd(lua_State *L);
33 static int _uscript_func_editor_register_observer(lua_State *L);
34 static int _uscript_func_util_escape_shell_arg(lua_State *L);
35 static int _uscript_func_util_shell_exec(lua_State *L);
36 static int _uscript_func_editor_get_input(lua_State *L);
37 static int _uscript_func_editor_menu(lua_State *L);
38 static int _uscript_func_bview_pop_kmap(lua_State *L);
39 static int _uscript_func_bview_push_kmap(lua_State *L);
40 static int _uscript_func_buffer_set_callback(lua_State *L);
41 static int _uscript_func_buffer_add_srule(lua_State *L);
42 static int _uscript_func_buffer_remove_srule(lua_State *L);
43 static int _uscript_func_buffer_write_to_file(lua_State *L);
44 static int _uscript_func_editor_input_to_key(lua_State *L);
45 static void *luaL_checkpointer(lua_State *L, int arg);
46 static void *luaL_optpointer(lua_State *L, int arg, void *def);
47 static void lua_pushpointer(lua_State *L, void *ptr);
48 static int luaL_checkfunction(lua_State *L, int arg);
49 static int luaopen_mle(lua_State *L);
50
51 #include "uscript.inc"
52
53 // Run uscript
uscript_run(editor_t * editor,char * path)54 uscript_t *uscript_run(editor_t *editor, char *path) {
55 lua_State *L;
56 uscript_t *uscript;
57 L = luaL_newstate();
58 luaL_openlibs(L);
59 luaL_requiref(L, "mle", luaopen_mle, 1);
60
61 uscript = calloc(1, sizeof(uscript_t));
62 uscript->editor = editor;
63 uscript->L = L;
64
65 lua_pushpointer(L, (void*)uscript);
66 lua_setglobal(L, MLE_USCRIPT_KEY);
67 lua_pop(L, 1);
68
69 lua_getglobal(L, "_G");
70 lua_pushcfunction(L, _uscript_write);
71 lua_setfield(L, -2, "print");
72 lua_pop(L, 1);
73
74 lua_atpanic(L, _uscript_panic);
75
76
77 luaL_loadfile(L, path); // TODO err
78
79 lua_pcall(L, 0, 0, 0);
80 return uscript;
81 }
82
83 // Destroy uscript
uscript_destroy(uscript_t * uscript)84 int uscript_destroy(uscript_t *uscript) {
85 lua_close(uscript->L);
86 return MLE_OK;
87 }
88
_uscript_panic(lua_State * L)89 static int _uscript_panic(lua_State *L) {
90 MLE_SET_ERR(&_editor, "uscript panic: %s", lua_tostring(L, -1));
91 return 0;
92 }
93
94 // Invoke cmd in uscript
_uscript_cmd_cb(cmd_context_t * ctx)95 static int _uscript_cmd_cb(cmd_context_t *ctx) {
96 int rv;
97 lua_State *L;
98 uhandle_t *uhandle;
99 int top;
100
101 uhandle = (uhandle_t*)(ctx->cmd->udata);
102 L = uhandle->uscript->L;
103 top = lua_gettop(L);
104 lua_rawgeti(L, LUA_REGISTRYINDEX, uhandle->callback_ref);
105 _uscript_push_cmd_map(L, ctx);
106
107 if (lua_pcall(L, 1, 1, 0) != LUA_OK) {
108 printf("err[%s]\n", luaL_checkstring(L, -1));
109 rv = MLE_ERR;
110 } else if (lua_isboolean(L, -1) && !lua_toboolean(L, -1)) {
111 rv = MLE_ERR;
112 } else {
113 rv = MLE_OK;
114 }
115
116 lua_settop(L, top);
117 return rv;
118 }
119
_uscript_observer_cb(char * event_name,void * event_data,void * udata)120 static int _uscript_observer_cb(char *event_name, void *event_data, void *udata) {
121 int rv;
122 lua_State *L;
123 uhandle_t *uhandle;
124 uhandle = (uhandle_t*)(udata);
125 L = uhandle->uscript->L;
126
127 lua_rawgeti(L, LUA_REGISTRYINDEX, uhandle->callback_ref);
128 _uscript_push_event_map(uhandle->uscript, event_name, event_data);
129
130 if (lua_pcall(L, 1, 1, 0) != LUA_OK) {
131 printf("err[%s]\n", luaL_checkstring(L, -1));
132 rv = MLE_ERR;
133 } else if (lua_isboolean(L, -1) && !lua_toboolean(L, -1)) {
134 rv = MLE_ERR;
135 } else {
136 rv = MLE_OK;
137 }
138
139 return rv;
140 }
141
142 // Handle write from uscript
_uscript_write(lua_State * L)143 static int _uscript_write(lua_State *L) {
144 uscript_t *uscript;
145 char *str;
146 mark_t *mark;
147 int i, nargs;
148 nargs = lua_gettop(L);
149 MLE_USCRIPT_GET(L, uscript);
150 if (!uscript->editor->active_edit
151 || !uscript->editor->active_edit->active_cursor
152 ) {
153 return 0;
154 }
155 mark = uscript->editor->active_edit->active_cursor->mark;
156 for (i = 1; i <= nargs; i++) {
157 str = (char*)lua_tostring(L, i);
158 mark_insert_before(mark, str, strlen(str));
159 }
160 return 0;
161 }
162
_uscript_push_event_map(uscript_t * uscript,char * event_name,void * event_data)163 static void _uscript_push_event_map(uscript_t *uscript, char *event_name, void *event_data) {
164 lua_State *L;
165 L = uscript->L;
166 if (strcmp(event_name, "buffer:baction") == 0) {
167 _uscript_push_baction_map(L, (baction_t*)event_data);
168 return;
169 } else if (strcmp(event_name, "buffer:save") == 0) {
170 lua_createtable(L, 0, 1);
171 luaL_pushkey(L, pointer, "bview", event_data);
172 return;
173 } else if (strncmp(event_name, "cmd:", 4) == 0) {
174 _uscript_push_cmd_map(L, (cmd_context_t*)event_data);
175 return;
176 }
177 lua_pushnil(uscript->L); // TODO
178 }
179
_uscript_push_cmd_map(lua_State * L,cmd_context_t * ctx)180 static void _uscript_push_cmd_map(lua_State *L, cmd_context_t *ctx) {
181 char input_str[16];
182 editor_input_to_key(ctx->editor, &ctx->input, input_str);
183 lua_createtable(L, 0, 1);
184 luaL_pushkey(L, pointer, "editor", (void*)ctx->editor);
185 luaL_pushkey(L, pointer, "loop_ctx", (void*)ctx->loop_ctx);
186 luaL_pushkey(L, pointer, "cmd", (void*)ctx->cmd);
187 luaL_pushkey(L, pointer, "buffer", (void*)ctx->buffer);
188 luaL_pushkey(L, pointer, "bview", (void*)ctx->bview);
189 luaL_pushkey(L, pointer, "cursor", (void*)ctx->cursor);
190 luaL_pushkey(L, pointer, "mark", (void*)ctx->cursor->mark);
191 luaL_pushkey(L, string, "static_param", (const char*)ctx->static_param);
192 luaL_pushkey(L, string, "input", (const char*)input_str);
193 }
194
_uscript_push_baction_map(lua_State * L,baction_t * baction)195 static void _uscript_push_baction_map(lua_State *L, baction_t *baction) {
196 lua_createtable(L, 0, 1);
197 luaL_pushkey(L, integer, "type", baction->type);
198 luaL_pushkey(L, pointer, "buffer", (void*)baction->buffer);
199 luaL_pushkey(L, integer, "start_line_index", baction->start_line_index);
200 luaL_pushkey(L, integer, "start_col", baction->start_col);
201 luaL_pushkey(L, integer, "maybe_end_line_index", baction->maybe_end_line_index);
202 luaL_pushkey(L, integer, "maybe_end_col", baction->maybe_end_col);
203 luaL_pushkey(L, integer, "byte_delta", baction->byte_delta);
204 luaL_pushkey(L, integer, "char_delta", baction->char_delta);
205 luaL_pushkey(L, integer, "line_delta", baction->line_delta);
206 luaL_pushkey2(L, lstring, "data", (const char*)baction->data, baction->data_len);
207 }
208
209 // foreign static string _uscript_func_editor_prompt(prompt)
_uscript_func_editor_prompt(lua_State * L)210 static int _uscript_func_editor_prompt(lua_State *L) {
211 uscript_t *uscript;
212 char *prompt;
213 char *answer = NULL;
214 MLE_USCRIPT_GET(L, uscript);
215 prompt = (char*)luaL_checkstring(L, 1);
216 if (editor_prompt(uscript->editor, prompt, NULL, &answer) == MLE_OK && answer) {
217 lua_pushstring(L, answer);
218 free(answer);
219 } else {
220 lua_pushnil(L);
221 }
222 return 1;
223 }
224
225 int editor_register_cmd(editor_t *editor, cmd_t *cmd);
226
227 // foreign static int _uscript_func_editor_register_cmd(cmd_name, fn_callback)
_uscript_func_editor_register_cmd(lua_State * L)228 static int _uscript_func_editor_register_cmd(lua_State *L) {
229 uscript_t *uscript;
230 uhandle_t *uhandle;
231 int rv;
232 char *cmd_name;
233 int fn_callback;
234 cmd_t cmd = {0};
235 MLE_USCRIPT_GET(L, uscript);
236
237 cmd_name = (char*)luaL_checkstring(L, 1); // strdup'd by editor_register_cmd
238 fn_callback = luaL_checkfunction(L, 2);
239
240 uhandle = calloc(1, sizeof(uhandle_t));
241 uhandle->uscript = uscript;
242 uhandle->callback_ref = fn_callback;
243 DL_APPEND(uscript->uhandles, uhandle);
244
245 cmd.name = cmd_name;
246 cmd.func = _uscript_cmd_cb;
247 cmd.udata = (void*)uhandle;
248 rv = editor_register_cmd(uscript->editor, &cmd);
249
250 lua_createtable(L, 0, 1);
251 luaL_pushkey(L, integer, "rv", rv);
252 lua_pushvalue(L, -1);
253 return 1;
254 }
255
256 // foreign static int _uscript_func_editor_register_observer(event_name, fn_callback)
_uscript_func_editor_register_observer(lua_State * L)257 static int _uscript_func_editor_register_observer(lua_State *L) {
258 int rv;
259 char *event_name;
260 int fn_callback;
261 uscript_t *uscript;
262 uhandle_t *uhandle;
263 MLE_USCRIPT_GET(L, uscript);
264
265 event_name = (char*)luaL_checkstring(L, 1);
266 fn_callback = luaL_checkfunction(L, 2);
267
268 uhandle = calloc(1, sizeof(uhandle_t));
269 uhandle->uscript = uscript;
270 uhandle->callback_ref = fn_callback;
271 DL_APPEND(uscript->uhandles, uhandle);
272
273 rv = editor_register_observer(uscript->editor, event_name, (void*)uhandle, _uscript_observer_cb, NULL);
274
275 lua_createtable(L, 0, 1);
276 luaL_pushkey(L, integer, "rv", rv);
277 lua_pushvalue(L, -1);
278 return 1;
279 }
280
281 // foreign static int _uscript_func_util_escape_shell_arg(arg)
_uscript_func_util_escape_shell_arg(lua_State * L)282 static int _uscript_func_util_escape_shell_arg(lua_State *L) {
283 (void)L;
284 return 0;
285 }
286
287 // foreign static int _uscript_func_util_shell_exec(cmd, timeout_s)
_uscript_func_util_shell_exec(lua_State * L)288 static int _uscript_func_util_shell_exec(lua_State *L) {
289 int rv;
290 char *cmd;
291 long timeout_s;
292 uscript_t *uscript;
293 char *output;
294 size_t output_len;
295 MLE_USCRIPT_GET(L, uscript);
296
297 cmd = (char*)luaL_checkstring(L, 1);
298 timeout_s = (long)luaL_checkinteger(L, 2);
299 output = NULL;
300 output_len = 0;
301 rv = util_shell_exec(uscript->editor, cmd, timeout_s, NULL, 0, 0, NULL, &output, &output_len);
302
303 lua_createtable(L, 0, 1);
304 luaL_pushkey(L, integer, "rv", rv);
305 luaL_pushkey2(L, lstring, "output", (output ? output : ""), output_len);
306 lua_pushvalue(L, -1);
307 if (output) free(output);
308 return 1;
309 }
310
311 // foreign static int _uscript_func_editor_get_input(x, y, z)
_uscript_func_editor_get_input(lua_State * L)312 static int _uscript_func_editor_get_input(lua_State *L) {
313 // TODO
314 (void)L;
315 return 0;
316 }
317
318 // foreign static int _uscript_func_editor_menu(x, y, z)
_uscript_func_editor_menu(lua_State * L)319 static int _uscript_func_editor_menu(lua_State *L) {
320 // TODO
321 (void)L;
322 return 0;
323 }
324
325 // foreign static int _uscript_func_bview_pop_kmap(x, y, z)
_uscript_func_bview_pop_kmap(lua_State * L)326 static int _uscript_func_bview_pop_kmap(lua_State *L) {
327 // TODO
328 (void)L;
329 return 0;
330 }
331
332 // foreign static int _uscript_func_bview_push_kmap(x, y, z)
_uscript_func_bview_push_kmap(lua_State * L)333 static int _uscript_func_bview_push_kmap(lua_State *L) {
334 // TODO
335 (void)L;
336 return 0;
337 }
338
339 // foreign static int _uscript_func_buffer_set_callback(x, y, z)
_uscript_func_buffer_set_callback(lua_State * L)340 static int _uscript_func_buffer_set_callback(lua_State *L) {
341 // TODO
342 (void)L;
343 return 0;
344 }
345
346 // foreign static int _uscript_func_buffer_add_srule(x, y, z)
_uscript_func_buffer_add_srule(lua_State * L)347 static int _uscript_func_buffer_add_srule(lua_State *L) {
348 // TODO
349 (void)L;
350 return 0;
351 }
352
353 // foreign static int _uscript_func_buffer_remove_srule(x, y, z)
_uscript_func_buffer_remove_srule(lua_State * L)354 static int _uscript_func_buffer_remove_srule(lua_State *L) {
355 // TODO
356 (void)L;
357 return 0;
358 }
359
360 // foreign static int _uscript_func_buffer_write_to_file(x, y, z)
_uscript_func_buffer_write_to_file(lua_State * L)361 static int _uscript_func_buffer_write_to_file(lua_State *L) {
362 // TODO
363 (void)L;
364 return 0;
365 }
366
367 // foreign static int _uscript_func_editor_input_to_key(x, y, z)
_uscript_func_editor_input_to_key(lua_State * L)368 static int _uscript_func_editor_input_to_key(lua_State *L) {
369 // TODO
370 (void)L;
371 return 0;
372 }
373
luaL_checkpointer(lua_State * L,int arg)374 static void *luaL_checkpointer(lua_State *L, int arg) {
375 luaL_checktype(L, arg, LUA_TSTRING);
376 return luaL_optpointer(L, arg, NULL);
377 }
378
luaL_optpointer(lua_State * L,int arg,void * def)379 static void *luaL_optpointer(lua_State *L, int arg, void *def) {
380 const char *ptr;
381 uintptr_t ptr_as_int;
382 ptr = luaL_optstring(L, arg, NULL);
383 if (ptr && strlen(ptr) > 0) {
384 ptr_as_int = (uintptr_t)strtoull(ptr, NULL, 16);
385 return (void*)ptr_as_int;
386 }
387 return def;
388 }
389
lua_pushpointer(lua_State * L,void * ptr)390 static void lua_pushpointer(lua_State *L, void *ptr) {
391 char ptrbuf[32];
392 if (ptr == NULL) {
393 lua_pushnil(L);
394 } else {
395 snprintf(ptrbuf, 32, "%" PRIxPTR, (uintptr_t)ptr);
396 lua_pushstring(L, ptrbuf);
397 }
398 }
399
luaL_checkfunction(lua_State * L,int arg)400 static int luaL_checkfunction(lua_State *L, int arg) {
401 luaL_checktype(L, arg, LUA_TFUNCTION);
402 lua_pushvalue(L, arg);
403 return luaL_ref(L, LUA_REGISTRYINDEX);
404 }
405
luaopen_mle(lua_State * L)406 static int luaopen_mle(lua_State *L) {
407 luaL_newlib(L, mle_lib);
408 return 1;
409 }
410