1 | // This is an open source non-commercial project. Dear PVS-Studio, please check |
2 | // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com |
3 | |
4 | #include <lua.h> |
5 | #include <lualib.h> |
6 | #include <lauxlib.h> |
7 | |
8 | #include "nvim/misc1.h" |
9 | #include "nvim/getchar.h" |
10 | #include "nvim/garray.h" |
11 | #include "nvim/func_attr.h" |
12 | #include "nvim/api/private/defs.h" |
13 | #include "nvim/api/private/helpers.h" |
14 | #include "nvim/api/vim.h" |
15 | #include "nvim/vim.h" |
16 | #include "nvim/ex_getln.h" |
17 | #include "nvim/ex_cmds2.h" |
18 | #include "nvim/message.h" |
19 | #include "nvim/memline.h" |
20 | #include "nvim/buffer_defs.h" |
21 | #include "nvim/macros.h" |
22 | #include "nvim/screen.h" |
23 | #include "nvim/cursor.h" |
24 | #include "nvim/undo.h" |
25 | #include "nvim/ascii.h" |
26 | #include "nvim/change.h" |
27 | |
28 | #ifdef WIN32 |
29 | #include "nvim/os/os.h" |
30 | #endif |
31 | |
32 | #include "nvim/lua/executor.h" |
33 | #include "nvim/lua/converter.h" |
34 | |
35 | #include "luv/luv.h" |
36 | |
37 | static int in_fast_callback = 0; |
38 | |
39 | typedef struct { |
40 | Error err; |
41 | String lua_err_str; |
42 | } LuaError; |
43 | |
44 | #ifdef INCLUDE_GENERATED_DECLARATIONS |
45 | # include "lua/vim_module.generated.h" |
46 | # include "lua/executor.c.generated.h" |
47 | #endif |
48 | |
49 | /// Name of the run code for use in messages |
50 | #define NLUA_EVAL_NAME "<VimL compiled string>" |
51 | |
52 | /// Convert lua error into a Vim error message |
53 | /// |
54 | /// @param lstate Lua interpreter state. |
55 | /// @param[in] msg Message base, must contain one `%s`. |
56 | static void nlua_error(lua_State *const lstate, const char *const msg) |
57 | FUNC_ATTR_NONNULL_ALL |
58 | { |
59 | size_t len; |
60 | const char *const str = lua_tolstring(lstate, -1, &len); |
61 | |
62 | msg_ext_set_kind("lua_error" ); |
63 | emsgf_multiline(msg, (int)len, str); |
64 | |
65 | lua_pop(lstate, 1); |
66 | } |
67 | |
68 | /// Compare two strings, ignoring case |
69 | /// |
70 | /// Expects two values on the stack: compared strings. Returns one of the |
71 | /// following numbers: 0, -1 or 1. |
72 | /// |
73 | /// Does no error handling: never call it with non-string or with some arguments |
74 | /// omitted. |
75 | static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL |
76 | { |
77 | size_t s1_len; |
78 | size_t s2_len; |
79 | const char *s1 = luaL_checklstring(lstate, 1, &s1_len); |
80 | const char *s2 = luaL_checklstring(lstate, 2, &s2_len); |
81 | char *nul1; |
82 | char *nul2; |
83 | int ret = 0; |
84 | assert(s1[s1_len] == NUL); |
85 | assert(s2[s2_len] == NUL); |
86 | do { |
87 | nul1 = memchr(s1, NUL, s1_len); |
88 | nul2 = memchr(s2, NUL, s2_len); |
89 | ret = STRICMP(s1, s2); |
90 | if (ret == 0) { |
91 | // Compare "a\0" greater then "a". |
92 | if ((nul1 == NULL) != (nul2 == NULL)) { |
93 | ret = ((nul1 != NULL) - (nul2 != NULL)); |
94 | break; |
95 | } |
96 | if (nul1 != NULL) { |
97 | assert(nul2 != NULL); |
98 | // Can't shift both strings by the same amount of bytes: lowercase |
99 | // letter may have different byte-length than uppercase. |
100 | s1_len -= (size_t)(nul1 - s1) + 1; |
101 | s2_len -= (size_t)(nul2 - s2) + 1; |
102 | s1 = nul1 + 1; |
103 | s2 = nul2 + 1; |
104 | } else { |
105 | break; |
106 | } |
107 | } else { |
108 | break; |
109 | } |
110 | } while (true); |
111 | lua_pop(lstate, 2); |
112 | lua_pushnumber(lstate, (lua_Number)((ret > 0) - (ret < 0))); |
113 | return 1; |
114 | } |
115 | |
116 | /// convert byte index to UTF-32 and UTF-16 indicies |
117 | /// |
118 | /// Expects a string and an optional index. If no index is supplied, the length |
119 | /// of the string is returned. |
120 | /// |
121 | /// Returns two values: the UTF-32 and UTF-16 indicies. |
122 | static int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL |
123 | { |
124 | size_t s1_len; |
125 | const char *s1 = luaL_checklstring(lstate, 1, &s1_len); |
126 | intptr_t idx; |
127 | if (lua_gettop(lstate) >= 2) { |
128 | idx = luaL_checkinteger(lstate, 2); |
129 | if (idx < 0 || idx > (intptr_t)s1_len) { |
130 | return luaL_error(lstate, "index out of range" ); |
131 | } |
132 | } else { |
133 | idx = (intptr_t)s1_len; |
134 | } |
135 | |
136 | size_t codepoints = 0, codeunits = 0; |
137 | mb_utflen((const char_u *)s1, (size_t)idx, &codepoints, &codeunits); |
138 | |
139 | lua_pushinteger(lstate, (long)codepoints); |
140 | lua_pushinteger(lstate, (long)codeunits); |
141 | |
142 | return 2; |
143 | } |
144 | |
145 | /// convert UTF-32 or UTF-16 indicies to byte index. |
146 | /// |
147 | /// Expects up to three args: string, index and use_utf16. |
148 | /// If use_utf16 is not supplied it defaults to false (use UTF-32) |
149 | /// |
150 | /// Returns the byte index. |
151 | static int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL |
152 | { |
153 | size_t s1_len; |
154 | const char *s1 = luaL_checklstring(lstate, 1, &s1_len); |
155 | intptr_t idx = luaL_checkinteger(lstate, 2); |
156 | if (idx < 0) { |
157 | return luaL_error(lstate, "index out of range" ); |
158 | } |
159 | bool use_utf16 = false; |
160 | if (lua_gettop(lstate) >= 3) { |
161 | use_utf16 = lua_toboolean(lstate, 3); |
162 | } |
163 | |
164 | ssize_t byteidx = mb_utf_index_to_bytes((const char_u *)s1, s1_len, |
165 | (size_t)idx, use_utf16); |
166 | if (byteidx == -1) { |
167 | return luaL_error(lstate, "index out of range" ); |
168 | } |
169 | |
170 | lua_pushinteger(lstate, (long)byteidx); |
171 | |
172 | return 1; |
173 | } |
174 | |
175 | static void nlua_luv_error_event(void **argv) |
176 | { |
177 | char *error = (char *)argv[0]; |
178 | msg_ext_set_kind("lua_error" ); |
179 | emsgf_multiline("Error executing luv callback:\n%s" , error); |
180 | xfree(error); |
181 | } |
182 | |
183 | static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, |
184 | int flags) |
185 | FUNC_ATTR_NONNULL_ALL |
186 | { |
187 | int retval; |
188 | |
189 | // luv callbacks might be executed at any os_breakcheck/line_breakcheck |
190 | // call, so using the API directly here is not safe. |
191 | in_fast_callback++; |
192 | |
193 | int top = lua_gettop(lstate); |
194 | int status = lua_pcall(lstate, nargs, nresult, 0); |
195 | if (status) { |
196 | if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) { |
197 | // consider out of memory errors unrecoverable, just like xmalloc() |
198 | mch_errmsg(e_outofmem); |
199 | mch_errmsg("\n" ); |
200 | preserve_exit(); |
201 | } |
202 | const char *error = lua_tostring(lstate, -1); |
203 | |
204 | multiqueue_put(main_loop.events, nlua_luv_error_event, |
205 | 1, xstrdup(error)); |
206 | lua_pop(lstate, 1); // error mesage |
207 | retval = -status; |
208 | } else { // LUA_OK |
209 | if (nresult == LUA_MULTRET) { |
210 | nresult = lua_gettop(lstate) - top + nargs + 1; |
211 | } |
212 | retval = nresult; |
213 | } |
214 | |
215 | in_fast_callback--; |
216 | return retval; |
217 | } |
218 | |
219 | static void nlua_schedule_event(void **argv) |
220 | { |
221 | LuaRef cb = (LuaRef)(ptrdiff_t)argv[0]; |
222 | lua_State *const lstate = nlua_enter(); |
223 | nlua_pushref(lstate, cb); |
224 | nlua_unref(lstate, cb); |
225 | if (lua_pcall(lstate, 0, 0, 0)) { |
226 | nlua_error(lstate, _("Error executing vim.schedule lua callback: %.*s" )); |
227 | } |
228 | } |
229 | |
230 | /// Schedule Lua callback on main loop's event queue |
231 | /// |
232 | /// @param lstate Lua interpreter state. |
233 | static int nlua_schedule(lua_State *const lstate) |
234 | FUNC_ATTR_NONNULL_ALL |
235 | { |
236 | if (lua_type(lstate, 1) != LUA_TFUNCTION) { |
237 | lua_pushliteral(lstate, "vim.schedule: expected function" ); |
238 | return lua_error(lstate); |
239 | } |
240 | |
241 | LuaRef cb = nlua_ref(lstate, 1); |
242 | |
243 | multiqueue_put(main_loop.events, nlua_schedule_event, |
244 | 1, (void *)(ptrdiff_t)cb); |
245 | return 0; |
246 | } |
247 | |
248 | /// Initialize lua interpreter state |
249 | /// |
250 | /// Called by lua interpreter itself to initialize state. |
251 | static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL |
252 | { |
253 | // print |
254 | lua_pushcfunction(lstate, &nlua_print); |
255 | lua_setglobal(lstate, "print" ); |
256 | |
257 | // debug.debug |
258 | lua_getglobal(lstate, "debug" ); |
259 | lua_pushcfunction(lstate, &nlua_debug); |
260 | lua_setfield(lstate, -2, "debug" ); |
261 | lua_pop(lstate, 1); |
262 | |
263 | #ifdef WIN32 |
264 | // os.getenv |
265 | lua_getglobal(lstate, "os" ); |
266 | lua_pushcfunction(lstate, &nlua_getenv); |
267 | lua_setfield(lstate, -2, "getenv" ); |
268 | lua_pop(lstate, 1); |
269 | #endif |
270 | |
271 | // vim |
272 | const char *code = (char *)&vim_module[0]; |
273 | if (luaL_loadbuffer(lstate, code, strlen(code), "@vim.lua" ) |
274 | || lua_pcall(lstate, 0, LUA_MULTRET, 0)) { |
275 | nlua_error(lstate, _("E5106: Error while creating vim module: %.*s" )); |
276 | return 1; |
277 | } |
278 | // vim.api |
279 | nlua_add_api_functions(lstate); |
280 | // vim.types, vim.type_idx, vim.val_idx |
281 | nlua_init_types(lstate); |
282 | // stricmp |
283 | lua_pushcfunction(lstate, &nlua_stricmp); |
284 | lua_setfield(lstate, -2, "stricmp" ); |
285 | // str_utfindex |
286 | lua_pushcfunction(lstate, &nlua_str_utfindex); |
287 | lua_setfield(lstate, -2, "str_utfindex" ); |
288 | // str_byteindex |
289 | lua_pushcfunction(lstate, &nlua_str_byteindex); |
290 | lua_setfield(lstate, -2, "str_byteindex" ); |
291 | // schedule |
292 | lua_pushcfunction(lstate, &nlua_schedule); |
293 | lua_setfield(lstate, -2, "schedule" ); |
294 | // in_fast_event |
295 | lua_pushcfunction(lstate, &nlua_in_fast_event); |
296 | lua_setfield(lstate, -2, "in_fast_event" ); |
297 | |
298 | // vim.loop |
299 | luv_set_loop(lstate, &main_loop.uv); |
300 | luv_set_callback(lstate, nlua_luv_cfpcall); |
301 | luaopen_luv(lstate); |
302 | lua_pushvalue(lstate, -1); |
303 | lua_setfield(lstate, -3, "loop" ); |
304 | |
305 | // package.loaded.luv = vim.loop |
306 | // otherwise luv will be reinitialized when require'luv' |
307 | lua_getglobal(lstate, "package" ); |
308 | lua_getfield(lstate, -1, "loaded" ); |
309 | lua_pushvalue(lstate, -3); |
310 | lua_setfield(lstate, -2, "luv" ); |
311 | lua_pop(lstate, 3); |
312 | |
313 | lua_setglobal(lstate, "vim" ); |
314 | return 0; |
315 | } |
316 | |
317 | /// Initialize lua interpreter |
318 | /// |
319 | /// Crashes Nvim if initialization fails. Should be called once per lua |
320 | /// interpreter instance. |
321 | /// |
322 | /// @return New lua interpreter instance. |
323 | static lua_State *nlua_init(void) |
324 | FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT |
325 | { |
326 | lua_State *lstate = luaL_newstate(); |
327 | if (lstate == NULL) { |
328 | EMSG(_("E970: Failed to initialize lua interpreter" )); |
329 | preserve_exit(); |
330 | } |
331 | luaL_openlibs(lstate); |
332 | nlua_state_init(lstate); |
333 | return lstate; |
334 | } |
335 | |
336 | /// Enter lua interpreter |
337 | /// |
338 | /// Calls nlua_init() if needed. Is responsible for pre-lua call initalization |
339 | /// like updating `package.[c]path` with directories derived from &runtimepath. |
340 | /// |
341 | /// @return Interpreter instance to use. Will either be initialized now or |
342 | /// taken from previous initialization. |
343 | static lua_State *nlua_enter(void) |
344 | FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT |
345 | { |
346 | static lua_State *global_lstate = NULL; |
347 | if (global_lstate == NULL) { |
348 | global_lstate = nlua_init(); |
349 | } |
350 | lua_State *const lstate = global_lstate; |
351 | // Last used p_rtp value. Must not be dereferenced because value pointed to |
352 | // may already be freed. Used to check whether &runtimepath option value |
353 | // changed. |
354 | static const void *last_p_rtp = NULL; |
355 | if (last_p_rtp != (const void *)p_rtp) { |
356 | // stack: (empty) |
357 | lua_getglobal(lstate, "vim" ); |
358 | // stack: vim |
359 | lua_getfield(lstate, -1, "_update_package_paths" ); |
360 | // stack: vim, vim._update_package_paths |
361 | if (lua_pcall(lstate, 0, 0, 0)) { |
362 | // stack: vim, error |
363 | nlua_error(lstate, _("E5117: Error while updating package paths: %.*s" )); |
364 | // stack: vim |
365 | } |
366 | // stack: vim |
367 | lua_pop(lstate, 1); |
368 | // stack: (empty) |
369 | last_p_rtp = (const void *)p_rtp; |
370 | } |
371 | return lstate; |
372 | } |
373 | |
374 | /// Execute lua string |
375 | /// |
376 | /// @param[in] str String to execute. |
377 | /// @param[out] ret_tv Location where result will be saved. |
378 | /// |
379 | /// @return Result of the execution. |
380 | void executor_exec_lua(const String str, typval_T *const ret_tv) |
381 | FUNC_ATTR_NONNULL_ALL |
382 | { |
383 | lua_State *const lstate = nlua_enter(); |
384 | |
385 | if (luaL_loadbuffer(lstate, str.data, str.size, NLUA_EVAL_NAME)) { |
386 | nlua_error(lstate, _("E5104: Error while creating lua chunk: %.*s" )); |
387 | return; |
388 | } |
389 | if (lua_pcall(lstate, 0, 1, 0)) { |
390 | nlua_error(lstate, _("E5105: Error while calling lua chunk: %.*s" )); |
391 | return; |
392 | } |
393 | |
394 | nlua_pop_typval(lstate, ret_tv); |
395 | } |
396 | |
397 | static void nlua_print_event(void **argv) |
398 | { |
399 | char *str = argv[0]; |
400 | const size_t len = (size_t)(intptr_t)argv[1]-1; // exclude final NUL |
401 | |
402 | for (size_t i = 0; i < len;) { |
403 | const size_t start = i; |
404 | while (i < len) { |
405 | switch (str[i]) { |
406 | case NUL: { |
407 | str[i] = NL; |
408 | i++; |
409 | continue; |
410 | } |
411 | case NL: { |
412 | // TODO(bfredl): use proper multiline msg? Probably should implement |
413 | // print() in lua in terms of nvim_message(), when it is available. |
414 | str[i] = NUL; |
415 | i++; |
416 | break; |
417 | } |
418 | default: { |
419 | i++; |
420 | continue; |
421 | } |
422 | } |
423 | break; |
424 | } |
425 | msg((char_u *)str + start); |
426 | } |
427 | if (len && str[len - 1] == NUL) { // Last was newline |
428 | msg((char_u *)"" ); |
429 | } |
430 | xfree(str); |
431 | } |
432 | |
433 | /// Print as a Vim message |
434 | /// |
435 | /// @param lstate Lua interpreter state. |
436 | static int nlua_print(lua_State *const lstate) |
437 | FUNC_ATTR_NONNULL_ALL |
438 | { |
439 | #define PRINT_ERROR(msg) \ |
440 | do { \ |
441 | errmsg = msg; \ |
442 | errmsg_len = sizeof(msg) - 1; \ |
443 | goto nlua_print_error; \ |
444 | } while (0) |
445 | const int nargs = lua_gettop(lstate); |
446 | lua_getglobal(lstate, "tostring" ); |
447 | const char *errmsg = NULL; |
448 | size_t errmsg_len = 0; |
449 | garray_T msg_ga; |
450 | ga_init(&msg_ga, 1, 80); |
451 | int curargidx = 1; |
452 | for (; curargidx <= nargs; curargidx++) { |
453 | lua_pushvalue(lstate, -1); // tostring |
454 | lua_pushvalue(lstate, curargidx); // arg |
455 | if (lua_pcall(lstate, 1, 1, 0)) { |
456 | errmsg = lua_tolstring(lstate, -1, &errmsg_len); |
457 | goto nlua_print_error; |
458 | } |
459 | size_t len; |
460 | const char *const s = lua_tolstring(lstate, -1, &len); |
461 | if (s == NULL) { |
462 | PRINT_ERROR( |
463 | "<Unknown error: lua_tolstring returned NULL for tostring result>" ); |
464 | } |
465 | ga_concat_len(&msg_ga, s, len); |
466 | if (curargidx < nargs) { |
467 | ga_append(&msg_ga, ' '); |
468 | } |
469 | lua_pop(lstate, 1); |
470 | } |
471 | #undef PRINT_ERROR |
472 | ga_append(&msg_ga, NUL); |
473 | |
474 | if (in_fast_callback) { |
475 | multiqueue_put(main_loop.events, nlua_print_event, |
476 | 2, msg_ga.ga_data, msg_ga.ga_len); |
477 | } else { |
478 | nlua_print_event((void *[]){ msg_ga.ga_data, |
479 | (void *)(intptr_t)msg_ga.ga_len }); |
480 | } |
481 | return 0; |
482 | |
483 | nlua_print_error: |
484 | ga_clear(&msg_ga); |
485 | const char *fmt = _("E5114: Error while converting print argument #%i: %.*s" ); |
486 | size_t len = (size_t)vim_snprintf((char *)IObuff, IOSIZE, fmt, curargidx, |
487 | (int)errmsg_len, errmsg); |
488 | lua_pushlstring(lstate, (char *)IObuff, len); |
489 | return lua_error(lstate); |
490 | } |
491 | |
492 | /// debug.debug: interaction with user while debugging. |
493 | /// |
494 | /// @param lstate Lua interpreter state. |
495 | int nlua_debug(lua_State *lstate) |
496 | FUNC_ATTR_NONNULL_ALL |
497 | { |
498 | const typval_T input_args[] = { |
499 | { |
500 | .v_lock = VAR_FIXED, |
501 | .v_type = VAR_STRING, |
502 | .vval.v_string = (char_u *)"lua_debug> " , |
503 | }, |
504 | { |
505 | .v_type = VAR_UNKNOWN, |
506 | }, |
507 | }; |
508 | for (;;) { |
509 | lua_settop(lstate, 0); |
510 | typval_T input; |
511 | get_user_input(input_args, &input, false); |
512 | msg_putchar('\n'); // Avoid outputting on input line. |
513 | if (input.v_type != VAR_STRING |
514 | || input.vval.v_string == NULL |
515 | || *input.vval.v_string == NUL |
516 | || STRCMP(input.vval.v_string, "cont" ) == 0) { |
517 | tv_clear(&input); |
518 | return 0; |
519 | } |
520 | if (luaL_loadbuffer(lstate, (const char *)input.vval.v_string, |
521 | STRLEN(input.vval.v_string), "=(debug command)" )) { |
522 | nlua_error(lstate, _("E5115: Error while loading debug string: %.*s" )); |
523 | } else if (lua_pcall(lstate, 0, 0, 0)) { |
524 | nlua_error(lstate, _("E5116: Error while calling debug string: %.*s" )); |
525 | } |
526 | tv_clear(&input); |
527 | } |
528 | return 0; |
529 | } |
530 | |
531 | int nlua_in_fast_event(lua_State *lstate) |
532 | { |
533 | lua_pushboolean(lstate, in_fast_callback > 0); |
534 | return 1; |
535 | } |
536 | |
537 | #ifdef WIN32 |
538 | /// os.getenv: override os.getenv to maintain coherency. #9681 |
539 | /// |
540 | /// uv_os_setenv uses SetEnvironmentVariableW which does not update _environ. |
541 | /// |
542 | /// @param lstate Lua interpreter state. |
543 | static int nlua_getenv(lua_State *lstate) |
544 | { |
545 | lua_pushstring(lstate, os_getenv(luaL_checkstring(lstate, 1))); |
546 | return 1; |
547 | } |
548 | #endif |
549 | |
550 | /// add the value to the registry |
551 | LuaRef nlua_ref(lua_State *lstate, int index) |
552 | { |
553 | lua_pushvalue(lstate, index); |
554 | return luaL_ref(lstate, LUA_REGISTRYINDEX); |
555 | } |
556 | |
557 | /// remove the value from the registry |
558 | void nlua_unref(lua_State *lstate, LuaRef ref) |
559 | { |
560 | if (ref > 0) { |
561 | luaL_unref(lstate, LUA_REGISTRYINDEX, ref); |
562 | } |
563 | } |
564 | |
565 | void executor_free_luaref(LuaRef ref) |
566 | { |
567 | lua_State *const lstate = nlua_enter(); |
568 | nlua_unref(lstate, ref); |
569 | } |
570 | |
571 | /// push a value referenced in the regirstry |
572 | void nlua_pushref(lua_State *lstate, LuaRef ref) |
573 | { |
574 | lua_rawgeti(lstate, LUA_REGISTRYINDEX, ref); |
575 | } |
576 | |
577 | /// Evaluate lua string |
578 | /// |
579 | /// Used for luaeval(). |
580 | /// |
581 | /// @param[in] str String to execute. |
582 | /// @param[in] arg Second argument to `luaeval()`. |
583 | /// @param[out] ret_tv Location where result will be saved. |
584 | /// |
585 | /// @return Result of the execution. |
586 | void executor_eval_lua(const String str, typval_T *const arg, |
587 | typval_T *const ret_tv) |
588 | FUNC_ATTR_NONNULL_ALL |
589 | { |
590 | lua_State *const lstate = nlua_enter(); |
591 | |
592 | garray_T str_ga; |
593 | ga_init(&str_ga, 1, 80); |
594 | #define "local _A=select(1,...) return (" |
595 | const size_t lcmd_len = sizeof(EVALHEADER) - 1 + str.size + 1; |
596 | char *lcmd; |
597 | if (lcmd_len < IOSIZE) { |
598 | lcmd = (char *)IObuff; |
599 | } else { |
600 | lcmd = xmalloc(lcmd_len); |
601 | } |
602 | memcpy(lcmd, EVALHEADER, sizeof(EVALHEADER) - 1); |
603 | memcpy(lcmd + sizeof(EVALHEADER) - 1, str.data, str.size); |
604 | lcmd[lcmd_len - 1] = ')'; |
605 | #undef EVALHEADER |
606 | if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { |
607 | nlua_error(lstate, |
608 | _("E5107: Error while creating lua chunk for luaeval(): %.*s" )); |
609 | if (lcmd != (char *)IObuff) { |
610 | xfree(lcmd); |
611 | } |
612 | return; |
613 | } |
614 | if (lcmd != (char *)IObuff) { |
615 | xfree(lcmd); |
616 | } |
617 | |
618 | if (arg->v_type == VAR_UNKNOWN) { |
619 | lua_pushnil(lstate); |
620 | } else { |
621 | nlua_push_typval(lstate, arg); |
622 | } |
623 | if (lua_pcall(lstate, 1, 1, 0)) { |
624 | nlua_error(lstate, |
625 | _("E5108: Error while calling lua chunk for luaeval(): %.*s" )); |
626 | return; |
627 | } |
628 | |
629 | nlua_pop_typval(lstate, ret_tv); |
630 | } |
631 | |
632 | /// Execute lua string |
633 | /// |
634 | /// Used for nvim_execute_lua(). |
635 | /// |
636 | /// @param[in] str String to execute. |
637 | /// @param[in] args array of ... args |
638 | /// @param[out] err Location where error will be saved. |
639 | /// |
640 | /// @return Return value of the execution. |
641 | Object executor_exec_lua_api(const String str, const Array args, Error *err) |
642 | { |
643 | lua_State *const lstate = nlua_enter(); |
644 | |
645 | if (luaL_loadbuffer(lstate, str.data, str.size, "<nvim>" )) { |
646 | size_t len; |
647 | const char *errstr = lua_tolstring(lstate, -1, &len); |
648 | api_set_error(err, kErrorTypeValidation, |
649 | "Error loading lua: %.*s" , (int)len, errstr); |
650 | return NIL; |
651 | } |
652 | |
653 | for (size_t i = 0; i < args.size; i++) { |
654 | nlua_push_Object(lstate, args.items[i], false); |
655 | } |
656 | |
657 | if (lua_pcall(lstate, (int)args.size, 1, 0)) { |
658 | size_t len; |
659 | const char *errstr = lua_tolstring(lstate, -1, &len); |
660 | api_set_error(err, kErrorTypeException, |
661 | "Error executing lua: %.*s" , (int)len, errstr); |
662 | return NIL; |
663 | } |
664 | |
665 | return nlua_pop_Object(lstate, false, err); |
666 | } |
667 | |
668 | Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args, |
669 | bool retval) |
670 | { |
671 | lua_State *const lstate = nlua_enter(); |
672 | nlua_pushref(lstate, ref); |
673 | lua_pushstring(lstate, name); |
674 | for (size_t i = 0; i < args.size; i++) { |
675 | nlua_push_Object(lstate, args.items[i], false); |
676 | } |
677 | |
678 | if (lua_pcall(lstate, (int)args.size+1, retval ? 1 : 0, 0)) { |
679 | // TODO(bfredl): callbacks:s might not always be msg-safe, for instance |
680 | // lua callbacks for redraw events. Later on let the caller deal with the |
681 | // error instead. |
682 | nlua_error(lstate, _("Error executing lua callback: %.*s" )); |
683 | return NIL; |
684 | } |
685 | Error err = ERROR_INIT; |
686 | |
687 | if (retval) { |
688 | return nlua_pop_Object(lstate, false, &err); |
689 | } else { |
690 | return NIL; |
691 | } |
692 | } |
693 | |
694 | /// check if the current execution context is safe for calling deferred API |
695 | /// methods. Luv callbacks are unsafe as they are called inside the uv loop. |
696 | bool nlua_is_deferred_safe(lua_State *lstate) |
697 | { |
698 | return in_fast_callback == 0; |
699 | } |
700 | |
701 | /// Run lua string |
702 | /// |
703 | /// Used for :lua. |
704 | /// |
705 | /// @param eap VimL command being run. |
706 | void ex_lua(exarg_T *const eap) |
707 | FUNC_ATTR_NONNULL_ALL |
708 | { |
709 | size_t len; |
710 | char *const code = script_get(eap, &len); |
711 | if (eap->skip) { |
712 | xfree(code); |
713 | return; |
714 | } |
715 | typval_T tv = { .v_type = VAR_UNKNOWN }; |
716 | executor_exec_lua((String) { .data = code, .size = len }, &tv); |
717 | tv_clear(&tv); |
718 | xfree(code); |
719 | } |
720 | |
721 | /// Run lua string for each line in range |
722 | /// |
723 | /// Used for :luado. |
724 | /// |
725 | /// @param eap VimL command being run. |
726 | void ex_luado(exarg_T *const eap) |
727 | FUNC_ATTR_NONNULL_ALL |
728 | { |
729 | if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) { |
730 | EMSG(_("cannot save undo information" )); |
731 | return; |
732 | } |
733 | const char *const cmd = (const char *)eap->arg; |
734 | const size_t cmd_len = strlen(cmd); |
735 | |
736 | lua_State *const lstate = nlua_enter(); |
737 | |
738 | #define DOSTART "return function(line, linenr) " |
739 | #define DOEND " end" |
740 | const size_t lcmd_len = (cmd_len |
741 | + (sizeof(DOSTART) - 1) |
742 | + (sizeof(DOEND) - 1)); |
743 | char *lcmd; |
744 | if (lcmd_len < IOSIZE) { |
745 | lcmd = (char *)IObuff; |
746 | } else { |
747 | lcmd = xmalloc(lcmd_len + 1); |
748 | } |
749 | memcpy(lcmd, DOSTART, sizeof(DOSTART) - 1); |
750 | memcpy(lcmd + sizeof(DOSTART) - 1, cmd, cmd_len); |
751 | memcpy(lcmd + sizeof(DOSTART) - 1 + cmd_len, DOEND, sizeof(DOEND) - 1); |
752 | #undef DOSTART |
753 | #undef DOEND |
754 | |
755 | if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { |
756 | nlua_error(lstate, _("E5109: Error while creating lua chunk: %.*s" )); |
757 | if (lcmd_len >= IOSIZE) { |
758 | xfree(lcmd); |
759 | } |
760 | return; |
761 | } |
762 | if (lcmd_len >= IOSIZE) { |
763 | xfree(lcmd); |
764 | } |
765 | if (lua_pcall(lstate, 0, 1, 0)) { |
766 | nlua_error(lstate, _("E5110: Error while creating lua function: %.*s" )); |
767 | return; |
768 | } |
769 | for (linenr_T l = eap->line1; l <= eap->line2; l++) { |
770 | if (l > curbuf->b_ml.ml_line_count) { |
771 | break; |
772 | } |
773 | lua_pushvalue(lstate, -1); |
774 | lua_pushstring(lstate, (const char *)ml_get_buf(curbuf, l, false)); |
775 | lua_pushnumber(lstate, (lua_Number)l); |
776 | if (lua_pcall(lstate, 2, 1, 0)) { |
777 | nlua_error(lstate, _("E5111: Error while calling lua function: %.*s" )); |
778 | break; |
779 | } |
780 | if (lua_isstring(lstate, -1)) { |
781 | size_t new_line_len; |
782 | const char *const new_line = lua_tolstring(lstate, -1, &new_line_len); |
783 | char *const new_line_transformed = xmemdupz(new_line, new_line_len); |
784 | for (size_t i = 0; i < new_line_len; i++) { |
785 | if (new_line_transformed[i] == NUL) { |
786 | new_line_transformed[i] = '\n'; |
787 | } |
788 | } |
789 | ml_replace(l, (char_u *)new_line_transformed, false); |
790 | changed_bytes(l, 0); |
791 | } |
792 | lua_pop(lstate, 1); |
793 | } |
794 | lua_pop(lstate, 1); |
795 | check_cursor(); |
796 | update_screen(NOT_VALID); |
797 | } |
798 | |
799 | /// Run lua file |
800 | /// |
801 | /// Used for :luafile. |
802 | /// |
803 | /// @param eap VimL command being run. |
804 | void ex_luafile(exarg_T *const eap) |
805 | FUNC_ATTR_NONNULL_ALL |
806 | { |
807 | lua_State *const lstate = nlua_enter(); |
808 | |
809 | if (luaL_loadfile(lstate, (const char *)eap->arg)) { |
810 | nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s" )); |
811 | return; |
812 | } |
813 | |
814 | if (lua_pcall(lstate, 0, 0, 0)) { |
815 | nlua_error(lstate, _("E5113: Error while calling lua chunk: %.*s" )); |
816 | return; |
817 | } |
818 | } |
819 | |