xref: /vim-8.2.3635/src/if_lua.c (revision 607cc1e0)
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Lua interface by Luis Carvalho
6  *
7  * Do ":help uganda"  in Vim to read copying and usage conditions.
8  * Do ":help credits" in Vim to see a list of people who contributed.
9  * See README.txt for an overview of the Vim source code.
10  */
11 
12 #include <stdio.h>
13 #include <string.h>
14 #include <lua.h>
15 #include <lualib.h>
16 #include <lauxlib.h>
17 #include "vim.h"
18 
19 /* Only do the following when the feature is enabled.  Needed for "make
20  * depend". */
21 #if defined(FEAT_LUA) || defined(PROTO)
22 
23 #define LUAVIM_CHUNKNAME "vim chunk"
24 #define LUAVIM_NAME "vim"
25 
26 typedef buf_T *luaV_Buffer;
27 typedef win_T *luaV_Window;
28 typedef void (*msgfunc_T)(char_u *);
29 
30 static const char LUAVIM_BUFFER[] = "buffer";
31 static const char LUAVIM_WINDOW[] = "window";
32 static const char LUAVIM_FREE[] = "luaV_free";
33 
34 #define luaV_getfield(L, s) \
35     lua_pushlightuserdata((L), (void *)(s)); \
36     lua_rawget((L), LUA_REGISTRYINDEX)
37 #define luaV_checksandbox(L) \
38     if (sandbox) luaL_error((L), "not allowed in sandbox")
39 #define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg)
40 #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg)
41 
42 
43 #ifdef DYNAMIC_LUA
44 /* lauxlib */
45 #define luaL_register dll_luaL_register
46 #define luaL_typerror dll_luaL_typerror
47 #define luaL_checklstring dll_luaL_checklstring
48 #define luaL_checkinteger dll_luaL_checkinteger
49 #define luaL_optinteger dll_luaL_optinteger
50 #define luaL_checktype dll_luaL_checktype
51 #define luaL_error dll_luaL_error
52 #define luaL_loadfile dll_luaL_loadfile
53 #define luaL_loadbuffer dll_luaL_loadbuffer
54 #define luaL_newstate dll_luaL_newstate
55 #define luaL_buffinit dll_luaL_buffinit
56 #define luaL_prepbuffer dll_luaL_prepbuffer
57 #define luaL_addlstring dll_luaL_addlstring
58 #define luaL_pushresult dll_luaL_pushresult
59 /* lua */
60 #define lua_close dll_lua_close
61 #define lua_gettop dll_lua_gettop
62 #define lua_settop dll_lua_settop
63 #define lua_pushvalue dll_lua_pushvalue
64 #define lua_replace dll_lua_replace
65 #define lua_isnumber dll_lua_isnumber
66 #define lua_isstring dll_lua_isstring
67 #define lua_type dll_lua_type
68 #define lua_rawequal dll_lua_rawequal
69 #define lua_tonumber dll_lua_tonumber
70 #define lua_tointeger dll_lua_tointeger
71 #define lua_toboolean dll_lua_toboolean
72 #define lua_tolstring dll_lua_tolstring
73 #define lua_touserdata dll_lua_touserdata
74 #define lua_pushnil dll_lua_pushnil
75 #define lua_pushnumber dll_lua_pushnumber
76 #define lua_pushinteger dll_lua_pushinteger
77 #define lua_pushlstring dll_lua_pushlstring
78 #define lua_pushstring dll_lua_pushstring
79 #define lua_pushfstring dll_lua_pushfstring
80 #define lua_pushcclosure dll_lua_pushcclosure
81 #define lua_pushboolean dll_lua_pushboolean
82 #define lua_pushlightuserdata dll_lua_pushlightuserdata
83 #define lua_getfield dll_lua_getfield
84 #define lua_rawget dll_lua_rawget
85 #define lua_createtable dll_lua_createtable
86 #define lua_newuserdata dll_lua_newuserdata
87 #define lua_getmetatable dll_lua_getmetatable
88 #define lua_setfield dll_lua_setfield
89 #define lua_rawset dll_lua_rawset
90 #define lua_rawseti dll_lua_rawseti
91 #define lua_setmetatable dll_lua_setmetatable
92 #define lua_call dll_lua_call
93 #define lua_pcall dll_lua_pcall
94 /* libs */
95 #define luaopen_base dll_luaopen_base
96 #define luaopen_table dll_luaopen_table
97 #define luaopen_string dll_luaopen_string
98 #define luaopen_math dll_luaopen_math
99 #define luaopen_os dll_luaopen_os
100 #define luaopen_package dll_luaopen_package
101 #define luaopen_debug dll_luaopen_debug
102 
103 /* lauxlib */
104 void (*dll_luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l);
105 int (*dll_luaL_typerror) (lua_State *L, int narg, const char *tname);
106 const char *(*dll_luaL_checklstring) (lua_State *L, int numArg, size_t *l);
107 lua_Integer (*dll_luaL_checkinteger) (lua_State *L, int numArg);
108 lua_Integer (*dll_luaL_optinteger) (lua_State *L, int nArg, lua_Integer def);
109 void (*dll_luaL_checktype) (lua_State *L, int narg, int t);
110 int (*dll_luaL_error) (lua_State *L, const char *fmt, ...);
111 int (*dll_luaL_loadfile) (lua_State *L, const char *filename);
112 int (*dll_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name);
113 lua_State *(*dll_luaL_newstate) (void);
114 void (*dll_luaL_buffinit) (lua_State *L, luaL_Buffer *B);
115 char *(*dll_luaL_prepbuffer) (luaL_Buffer *B);
116 void (*dll_luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
117 void (*dll_luaL_pushresult) (luaL_Buffer *B);
118 /* lua */
119 void       (*dll_lua_close) (lua_State *L);
120 int (*dll_lua_gettop) (lua_State *L);
121 void (*dll_lua_settop) (lua_State *L, int idx);
122 void (*dll_lua_pushvalue) (lua_State *L, int idx);
123 void (*dll_lua_replace) (lua_State *L, int idx);
124 int (*dll_lua_isnumber) (lua_State *L, int idx);
125 int (*dll_lua_isstring) (lua_State *L, int idx);
126 int (*dll_lua_type) (lua_State *L, int idx);
127 int (*dll_lua_rawequal) (lua_State *L, int idx1, int idx2);
128 lua_Number (*dll_lua_tonumber) (lua_State *L, int idx);
129 lua_Integer (*dll_lua_tointeger) (lua_State *L, int idx);
130 int (*dll_lua_toboolean) (lua_State *L, int idx);
131 const char *(*dll_lua_tolstring) (lua_State *L, int idx, size_t *len);
132 void *(*dll_lua_touserdata) (lua_State *L, int idx);
133 void (*dll_lua_pushnil) (lua_State *L);
134 void (*dll_lua_pushnumber) (lua_State *L, lua_Number n);
135 void (*dll_lua_pushinteger) (lua_State *L, lua_Integer n);
136 void (*dll_lua_pushlstring) (lua_State *L, const char *s, size_t l);
137 void (*dll_lua_pushstring) (lua_State *L, const char *s);
138 const char *(*dll_lua_pushfstring) (lua_State *L, const char *fmt, ...);
139 void (*dll_lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
140 void (*dll_lua_pushboolean) (lua_State *L, int b);
141 void (*dll_lua_pushlightuserdata) (lua_State *L, void *p);
142 void (*dll_lua_getfield) (lua_State *L, int idx, const char *k);
143 void (*dll_lua_rawget) (lua_State *L, int idx);
144 void (*dll_lua_createtable) (lua_State *L, int narr, int nrec);
145 void *(*dll_lua_newuserdata) (lua_State *L, size_t sz);
146 int (*dll_lua_getmetatable) (lua_State *L, int objindex);
147 void (*dll_lua_setfield) (lua_State *L, int idx, const char *k);
148 void (*dll_lua_rawset) (lua_State *L, int idx);
149 void (*dll_lua_rawseti) (lua_State *L, int idx, int n);
150 int (*dll_lua_setmetatable) (lua_State *L, int objindex);
151 void (*dll_lua_call) (lua_State *L, int nargs, int nresults);
152 int (*dll_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
153 /* libs */
154 int (*dll_luaopen_base) (lua_State *L);
155 int (*dll_luaopen_table) (lua_State *L);
156 int (*dll_luaopen_string) (lua_State *L);
157 int (*dll_luaopen_math) (lua_State *L);
158 int (*dll_luaopen_os) (lua_State *L);
159 int (*dll_luaopen_package) (lua_State *L);
160 int (*dll_luaopen_debug) (lua_State *L);
161 
162 typedef void **luaV_function;
163 typedef struct {
164     const char *name;
165     luaV_function func;
166 } luaV_Reg;
167 
168 static const luaV_Reg luaV_dll[] = {
169     /* lauxlib */
170     {"luaL_register", (luaV_function) &dll_luaL_register},
171     {"luaL_typerror", (luaV_function) &dll_luaL_typerror},
172     {"luaL_checklstring", (luaV_function) &dll_luaL_checklstring},
173     {"luaL_checkinteger", (luaV_function) &dll_luaL_checkinteger},
174     {"luaL_optinteger", (luaV_function) &dll_luaL_optinteger},
175     {"luaL_checktype", (luaV_function) &dll_luaL_checktype},
176     {"luaL_error", (luaV_function) &dll_luaL_error},
177     {"luaL_loadfile", (luaV_function) &dll_luaL_loadfile},
178     {"luaL_loadbuffer", (luaV_function) &dll_luaL_loadbuffer},
179     {"luaL_newstate", (luaV_function) &dll_luaL_newstate},
180     {"luaL_buffinit", (luaV_function) &dll_luaL_buffinit},
181     {"luaL_prepbuffer", (luaV_function) &dll_luaL_prepbuffer},
182     {"luaL_addlstring", (luaV_function) &dll_luaL_addlstring},
183     {"luaL_pushresult", (luaV_function) &dll_luaL_pushresult},
184     /* lua */
185     {"lua_close", (luaV_function) &dll_lua_close},
186     {"lua_gettop", (luaV_function) &dll_lua_gettop},
187     {"lua_settop", (luaV_function) &dll_lua_settop},
188     {"lua_pushvalue", (luaV_function) &dll_lua_pushvalue},
189     {"lua_replace", (luaV_function) &dll_lua_replace},
190     {"lua_isnumber", (luaV_function) &dll_lua_isnumber},
191     {"lua_isstring", (luaV_function) &dll_lua_isstring},
192     {"lua_type", (luaV_function) &dll_lua_type},
193     {"lua_rawequal", (luaV_function) &dll_lua_rawequal},
194     {"lua_tonumber", (luaV_function) &dll_lua_tonumber},
195     {"lua_tointeger", (luaV_function) &dll_lua_tointeger},
196     {"lua_toboolean", (luaV_function) &dll_lua_toboolean},
197     {"lua_tolstring", (luaV_function) &dll_lua_tolstring},
198     {"lua_touserdata", (luaV_function) &dll_lua_touserdata},
199     {"lua_pushnil", (luaV_function) &dll_lua_pushnil},
200     {"lua_pushnumber", (luaV_function) &dll_lua_pushnumber},
201     {"lua_pushinteger", (luaV_function) &dll_lua_pushinteger},
202     {"lua_pushlstring", (luaV_function) &dll_lua_pushlstring},
203     {"lua_pushstring", (luaV_function) &dll_lua_pushstring},
204     {"lua_pushfstring", (luaV_function) &dll_lua_pushfstring},
205     {"lua_pushcclosure", (luaV_function) &dll_lua_pushcclosure},
206     {"lua_pushboolean", (luaV_function) &dll_lua_pushboolean},
207     {"lua_pushlightuserdata", (luaV_function) &dll_lua_pushlightuserdata},
208     {"lua_getfield", (luaV_function) &dll_lua_getfield},
209     {"lua_rawget", (luaV_function) &dll_lua_rawget},
210     {"lua_createtable", (luaV_function) &dll_lua_createtable},
211     {"lua_newuserdata", (luaV_function) &dll_lua_newuserdata},
212     {"lua_getmetatable", (luaV_function) &dll_lua_getmetatable},
213     {"lua_setfield", (luaV_function) &dll_lua_setfield},
214     {"lua_rawset", (luaV_function) &dll_lua_rawset},
215     {"lua_rawseti", (luaV_function) &dll_lua_rawseti},
216     {"lua_setmetatable", (luaV_function) &dll_lua_setmetatable},
217     {"lua_call", (luaV_function) &dll_lua_call},
218     {"lua_pcall", (luaV_function) &dll_lua_pcall},
219     /* libs */
220     {"luaopen_base", (luaV_function) &dll_luaopen_base},
221     {"luaopen_table", (luaV_function) &dll_luaopen_table},
222     {"luaopen_string", (luaV_function) &dll_luaopen_string},
223     {"luaopen_math", (luaV_function) &dll_luaopen_math},
224     {"luaopen_os", (luaV_function) &dll_luaopen_os},
225     {"luaopen_package", (luaV_function) &dll_luaopen_package},
226     {"luaopen_debug", (luaV_function) &dll_luaopen_debug},
227     {NULL, NULL}
228 };
229 
230 static HINSTANCE hinstLua = 0;
231 
232     static void
233 end_dynamic_lua(void)
234 {
235     if (hinstLua)
236     {
237 	FreeLibrary(hinstLua);
238 	hinstLua = 0;
239     }
240 }
241 
242     static int
243 lua_link_init(char *libname, int verbose)
244 {
245     const luaV_Reg *reg;
246     if (hinstLua) return OK;
247     hinstLua = LoadLibrary(libname);
248     if (!hinstLua)
249     {
250 	if (verbose)
251 	    EMSG2(_(e_loadlib), libname);
252 	return FAIL;
253     }
254     for (reg = luaV_dll; reg->func; reg++)
255     {
256 	if ((*reg->func = GetProcAddress(hinstLua, reg->name)) == NULL) {
257 	    FreeLibrary(hinstLua);
258 	    hinstLua = 0;
259 	    if (verbose)
260 		EMSG2(_(e_loadfunc), reg->name);
261 	    return FAIL;
262 	}
263     }
264     return OK;
265 }
266 
267     int
268 lua_enabled(int verbose)
269 {
270     return lua_link_init(DYNAMIC_LUA_DLL, verbose) == OK;
271 }
272 
273 #endif /* DYNAMIC_LUA */
274 
275 
276 /* =======   Internal   ======= */
277 
278     static void
279 luaV_newmetatable(lua_State *L, const char *tname)
280 {
281     lua_newtable(L);
282     lua_pushlightuserdata(L, (void *) tname);
283     lua_pushvalue(L, -2);
284     lua_rawset(L, LUA_REGISTRYINDEX);
285 }
286 
287     static void *
288 luaV_toudata(lua_State *L, int ud, const char *tname)
289 {
290     void *p = lua_touserdata(L, ud);
291 
292     if (p != NULL) /* value is userdata? */
293     {
294 	if (lua_getmetatable(L, ud)) /* does it have a metatable? */
295 	{
296 	    luaV_getfield(L, tname); /* get metatable */
297 	    if (lua_rawequal(L, -1, -2)) /* MTs match? */
298 	    {
299 		lua_pop(L, 2); /* MTs */
300 		return p;
301 	    }
302 	}
303     }
304     return NULL;
305 }
306 
307     static void *
308 luaV_checkudata(lua_State *L, int ud, const char *tname)
309 {
310     void *p = luaV_toudata(L, ud, tname);
311     if (p == NULL) luaL_typerror(L, ud, tname);
312     return p;
313 }
314 
315     static void
316 luaV_pushtypval(lua_State *L, typval_T *tv)
317 {
318     if (tv == NULL) luaL_error(L, "null type");
319     switch (tv->v_type)
320     {
321 	case VAR_STRING:
322 	    lua_pushstring(L, (char *) tv->vval.v_string);
323 	    break;
324 	case VAR_NUMBER:
325 	    lua_pushinteger(L, (int) tv->vval.v_number);
326 	    break;
327 #ifdef FEAT_FLOAT
328 	case VAR_FLOAT:
329 	    lua_pushnumber(L, (lua_Number) tv->vval.v_float);
330 	    break;
331 #endif
332 	case VAR_LIST: {
333 	    list_T *l = tv->vval.v_list;
334 
335 	    if (l != NULL)
336 	    {
337 		/* check cache */
338 		lua_pushlightuserdata(L, (void *) l);
339 		lua_rawget(L, LUA_ENVIRONINDEX);
340 		if (lua_isnil(L, -1)) /* not interned? */
341 		{
342 		    listitem_T *li;
343 		    int n = 0;
344 		    lua_pop(L, 1); /* nil */
345 		    lua_newtable(L);
346 		    lua_pushlightuserdata(L, (void *) l);
347 		    lua_pushvalue(L, -2);
348 		    lua_rawset(L, LUA_ENVIRONINDEX);
349 		    for (li = l->lv_first; li != NULL; li = li->li_next)
350 		    {
351 			luaV_pushtypval(L, &li->li_tv);
352 			lua_rawseti(L, -2, ++n);
353 		    }
354 		}
355 	    }
356 	    else lua_pushnil(L);
357 	    break;
358 		       }
359 	case VAR_DICT: {
360 	    dict_T *d = tv->vval.v_dict;
361 
362 	    if (d != NULL)
363 	    {
364 		/* check cache */
365 		lua_pushlightuserdata(L, (void *) d);
366 		lua_rawget(L, LUA_ENVIRONINDEX);
367 		if (lua_isnil(L, -1)) { /* not interned? */
368 		    hashtab_T *ht = &d->dv_hashtab;
369 		    hashitem_T *hi;
370 		    int n = ht->ht_used; /* remaining items */
371 		    lua_pop(L, 1); /* nil */
372 		    lua_newtable(L);
373 		    lua_pushlightuserdata(L, (void *) d);
374 		    lua_pushvalue(L, -2);
375 		    lua_rawset(L, LUA_ENVIRONINDEX);
376 		    for (hi = ht->ht_array; n > 0; hi++)
377 		    {
378 			if (!HASHITEM_EMPTY(hi))
379 			{
380 			    dictitem_T *di = dict_lookup(hi);
381 			    luaV_pushtypval(L, &di->di_tv);
382 			    lua_setfield(L, -2, (char *) hi->hi_key);
383 			    n--;
384 			}
385 		    }
386 		}
387 	    }
388 	    else lua_pushnil(L);
389 	    break;
390 	}
391 	default:
392 	    luaL_error(L, "invalid type");
393     }
394 }
395 
396 /* similar to luaL_addlstring, but replaces \0 with \n if toline and
397  * \n with \0 otherwise */
398     static void
399 luaV_addlstring(luaL_Buffer *b, const char *s, size_t l, int toline)
400 {
401     while (l--)
402     {
403 	if (*s == '\0' && toline)
404 	    luaL_addchar(b, '\n');
405 	else if (*s == '\n' && !toline)
406 	    luaL_addchar(b, '\0');
407 	else
408 	    luaL_addchar(b, *s);
409 	s++;
410     }
411 }
412 
413     static void
414 luaV_pushline(lua_State *L, buf_T *buf, linenr_T n)
415 {
416     const char *s = (const char *) ml_get_buf(buf, n, FALSE);
417     luaL_Buffer b;
418     luaL_buffinit(L, &b);
419     luaV_addlstring(&b, s, strlen(s), 0);
420     luaL_pushresult(&b);
421 }
422 
423     static char_u *
424 luaV_toline(lua_State *L, int pos)
425 {
426     size_t l;
427     const char *s = lua_tolstring(L, pos, &l);
428 
429     luaL_Buffer b;
430     luaL_buffinit(L, &b);
431     luaV_addlstring(&b, s, l, 1);
432     luaL_pushresult(&b);
433     return (char_u *) lua_tostring(L, -1);
434 }
435 
436 /* pops a string s from the top of the stack and calls mf(t) for pieces t of
437  * s separated by newlines */
438     static void
439 luaV_msgfunc(lua_State *L, msgfunc_T mf)
440 {
441     luaL_Buffer b;
442     size_t l;
443     const char *p, *s = lua_tolstring(L, -1, &l);
444     luaL_buffinit(L, &b);
445     luaV_addlstring(&b, s, l, 0);
446     luaL_pushresult(&b);
447     /* break string */
448     p = s = lua_tolstring(L, -1, &l);
449     while (l--)
450     {
451 	if (*p++ == '\0') /* break? */
452 	{
453 	    mf((char_u *) s);
454 	    s = p;
455 	}
456     }
457     mf((char_u *) s);
458     lua_pop(L, 2); /* original and modified strings */
459 }
460 
461 
462 /* =======   Buffer type   ======= */
463 
464     static luaV_Buffer *
465 luaV_newbuffer(lua_State *L, buf_T *buf)
466 {
467     luaV_Buffer *b = (luaV_Buffer *) lua_newuserdata(L, sizeof(luaV_Buffer));
468     *b = buf;
469     lua_pushlightuserdata(L, (void *) buf);
470     lua_pushvalue(L, -2);
471     lua_rawset(L, LUA_ENVIRONINDEX); /* env[buf] = udata */
472     /* to avoid GC, store as key in env */
473     lua_pushvalue(L, -1);
474     lua_pushboolean(L, 1);
475     lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = true */
476     /* set metatable */
477     luaV_getfield(L, LUAVIM_BUFFER);
478     lua_setmetatable(L, -2);
479     return b;
480 }
481 
482     static luaV_Buffer *
483 luaV_pushbuffer (lua_State *L, buf_T *buf)
484 {
485     luaV_Buffer *b = NULL;
486     if (buf == NULL)
487 	lua_pushnil(L);
488     else {
489 	lua_pushlightuserdata(L, (void *) buf);
490 	lua_rawget(L, LUA_ENVIRONINDEX);
491 	if (lua_isnil(L, -1)) /* not interned? */
492 	{
493 	    lua_pop(L, 1);
494 	    b = luaV_newbuffer(L, buf);
495 	}
496 	else
497 	    b = (luaV_Buffer *) lua_touserdata(L, -1);
498     }
499     return b;
500 }
501 
502 /* Buffer metamethods */
503 
504     static int
505 luaV_buffer_tostring(lua_State *L)
506 {
507     lua_pushfstring(L, "%s: %p", LUAVIM_BUFFER, lua_touserdata(L, 1));
508     return 1;
509 }
510 
511     static int
512 luaV_buffer_len(lua_State *L)
513 {
514     luaV_Buffer *b = lua_touserdata(L, 1);
515     lua_pushinteger(L, (*b)->b_ml.ml_line_count);
516     return 1;
517 }
518 
519     static int
520 luaV_buffer_call(lua_State *L)
521 {
522     luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1);
523     lua_settop(L, 1);
524     set_curbuf(*b, DOBUF_SPLIT);
525     return 1;
526 }
527 
528     static int
529 luaV_buffer_index(lua_State *L)
530 {
531     luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1);
532     linenr_T n = (linenr_T) lua_tointeger(L, 2);
533     if (n > 0 && n <= (*b)->b_ml.ml_line_count)
534 	luaV_pushline(L, *b, n);
535     else if (lua_isstring(L, 2))
536     {
537 	const char *s = lua_tostring(L, 2);
538 	if (strncmp(s, "name", 4) == 0)
539 	    lua_pushstring(L, (char *) (*b)->b_sfname);
540 	else if (strncmp(s, "fname", 5) == 0)
541 	    lua_pushstring(L, (char *) (*b)->b_ffname);
542 	else if (strncmp(s, "number", 6) == 0)
543 	    lua_pushinteger(L, (*b)->b_fnum);
544 	/* methods */
545 	else if (strncmp(s,   "insert", 6) == 0
546 		|| strncmp(s, "next", 4) == 0
547 		|| strncmp(s, "previous", 8) == 0
548 		|| strncmp(s, "isvalid", 7) == 0)
549 	{
550 	    lua_getmetatable(L, 1);
551 	    lua_getfield(L, -1, s);
552 	}
553 	else
554 	    lua_pushnil(L);
555     }
556     else
557 	lua_pushnil(L);
558     return 1;
559 }
560 
561     static int
562 luaV_buffer_newindex(lua_State *L)
563 {
564     luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1);
565     linenr_T n = (linenr_T) luaL_checkinteger(L, 2);
566 #ifdef HAVE_SANDBOX
567     luaV_checksandbox(L);
568 #endif
569     if (n < 1 || n > (*b)->b_ml.ml_line_count)
570 	luaL_error(L, "invalid line number");
571     if (lua_isnil(L, 3)) /* delete line */
572     {
573 	buf_T *buf = curbuf;
574 	curbuf = *b;
575 	if (u_savedel(n, 1L) == FAIL)
576 	{
577 	    curbuf = buf;
578 	    luaL_error(L, "cannot save undo information");
579 	}
580 	else if (ml_delete(n, FALSE) == FAIL)
581 	{
582 	    curbuf = buf;
583 	    luaL_error(L, "cannot delete line");
584 	}
585 	else {
586 	    deleted_lines_mark(n, 1L);
587 	    if (*b == curwin->w_buffer) /* fix cursor in current window? */
588 	    {
589 		if (curwin->w_cursor.lnum >= n)
590 		{
591 		    if (curwin->w_cursor.lnum > n)
592 		    {
593 			curwin->w_cursor.lnum -= 1;
594 			check_cursor_col();
595 		    }
596 		    else check_cursor();
597 		    changed_cline_bef_curs();
598 		}
599 		invalidate_botline();
600 	    }
601 	}
602 	curbuf = buf;
603     }
604     else if (lua_isstring(L, 3)) /* update line */
605     {
606 	buf_T *buf = curbuf;
607 	curbuf = *b;
608 	if (u_savesub(n) == FAIL)
609 	{
610 	    curbuf = buf;
611 	    luaL_error(L, "cannot save undo information");
612 	}
613 	else if (ml_replace(n, luaV_toline(L, 3), TRUE) == FAIL)
614 	{
615 	    curbuf = buf;
616 	    luaL_error(L, "cannot replace line");
617 	}
618 	else changed_bytes(n, 0);
619 	curbuf = buf;
620 	if (*b == curwin->w_buffer)
621 	    check_cursor_col();
622     }
623     else
624 	luaL_error(L, "wrong argument to change line");
625     return 0;
626 }
627 
628     static int
629 luaV_buffer_insert(lua_State *L)
630 {
631     luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
632     linenr_T last = (*b)->b_ml.ml_line_count;
633     linenr_T n = (linenr_T) luaL_optinteger(L, 3, last);
634     buf_T *buf;
635     luaL_checktype(L, 2, LUA_TSTRING);
636 #ifdef HAVE_SANDBOX
637     luaV_checksandbox(L);
638 #endif
639     /* fix insertion line */
640     if (n < 0) n = 0;
641     if (n > last) n = last;
642     /* insert */
643     buf = curbuf;
644     curbuf = *b;
645     if (u_save(n, n + 1) == FAIL)
646     {
647 	curbuf = buf;
648 	luaL_error(L, "cannot save undo information");
649     }
650     else if (ml_append(n, luaV_toline(L, 2), 0, FALSE) == FAIL)
651     {
652 	curbuf = buf;
653 	luaL_error(L, "cannot insert line");
654     }
655     else
656 	appended_lines_mark(n, 1L);
657     curbuf = buf;
658     update_screen(VALID);
659     return 0;
660 }
661 
662     static int
663 luaV_buffer_next(lua_State *L)
664 {
665     luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
666     luaV_pushbuffer(L, (*b)->b_next);
667     return 1;
668 }
669 
670     static int
671 luaV_buffer_previous(lua_State *L)
672 {
673     luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
674     luaV_pushbuffer(L, (*b)->b_prev);
675     return 1;
676 }
677 
678     static int
679 luaV_buffer_isvalid(lua_State *L)
680 {
681     luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
682     lua_pushlightuserdata(L, (void *) (*b));
683     lua_rawget(L, LUA_ENVIRONINDEX);
684     lua_pushboolean(L, !lua_isnil(L, -1));
685     return 1;
686 }
687 
688 static const luaL_Reg luaV_Buffer_mt[] = {
689     {"__tostring", luaV_buffer_tostring},
690     {"__len", luaV_buffer_len},
691     {"__call", luaV_buffer_call},
692     {"__index", luaV_buffer_index},
693     {"__newindex", luaV_buffer_newindex},
694     {"insert", luaV_buffer_insert},
695     {"next", luaV_buffer_next},
696     {"previous", luaV_buffer_previous},
697     {"isvalid", luaV_buffer_isvalid},
698     {NULL, NULL}
699 };
700 
701 
702 /* =======   Window type   ======= */
703 
704     static luaV_Window *
705 luaV_newwindow(lua_State *L, win_T *win)
706 {
707     luaV_Window *w = (luaV_Window *) lua_newuserdata(L, sizeof(luaV_Window));
708     *w = win;
709     lua_pushlightuserdata(L, (void *) win);
710     lua_pushvalue(L, -2);
711     lua_rawset(L, LUA_ENVIRONINDEX); /* env[win] = udata */
712     /* to avoid GC, store as key in env */
713     lua_pushvalue(L, -1);
714     lua_pushboolean(L, 1);
715     lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = true */
716     /* set metatable */
717     luaV_getfield(L, LUAVIM_WINDOW);
718     lua_setmetatable(L, -2);
719     return w;
720 }
721 
722     static luaV_Window *
723 luaV_pushwindow(lua_State *L, win_T *win)
724 {
725     luaV_Window *w = NULL;
726     if (win == NULL)
727 	lua_pushnil(L);
728     else {
729 	lua_pushlightuserdata(L, (void *) win);
730 	lua_rawget(L, LUA_ENVIRONINDEX);
731 	if (lua_isnil(L, -1)) /* not interned? */
732 	{
733 	    lua_pop(L, 1);
734 	    w = luaV_newwindow(L, win);
735 	}
736 	else w = (luaV_Window *) lua_touserdata(L, -1);
737     }
738     return w;
739 }
740 
741 /* Window metamethods */
742 
743     static int
744 luaV_window_tostring(lua_State *L)
745 {
746     lua_pushfstring(L, "%s: %p", LUAVIM_WINDOW, lua_touserdata(L, 1));
747     return 1;
748 }
749 
750     static int
751 luaV_window_call(lua_State *L)
752 {
753     luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
754     lua_settop(L, 1);
755     win_goto(*w);
756     return 1;
757 }
758 
759     static int
760 luaV_window_index(lua_State *L)
761 {
762     luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
763     const char *s = luaL_checkstring(L, 2);
764     if (strncmp(s, "buffer", 6) == 0)
765 	luaV_pushbuffer(L, (*w)->w_buffer);
766     else if (strncmp(s, "line", 4) == 0)
767 	lua_pushinteger(L, (*w)->w_cursor.lnum);
768     else if (strncmp(s, "col", 3) == 0)
769 	lua_pushinteger(L, (*w)->w_cursor.col + 1);
770 #ifdef FEAT_VERTSPLIT
771     else if (strncmp(s, "width", 5) == 0)
772 	lua_pushinteger(L, W_WIDTH((*w)));
773 #endif
774     else if (strncmp(s, "height", 6) == 0)
775 	lua_pushinteger(L, (*w)->w_height);
776     /* methods */
777     else if (strncmp(s,   "next", 4) == 0
778 	    || strncmp(s, "previous", 8) == 0
779 	    || strncmp(s, "isvalid", 7) == 0)
780     {
781 	lua_getmetatable(L, 1);
782 	lua_getfield(L, -1, s);
783     }
784     else
785 	lua_pushnil(L);
786     return 1;
787 }
788 
789     static int
790 luaV_window_newindex (lua_State *L)
791 {
792     luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
793     const char *s = luaL_checkstring(L, 2);
794     int v = luaL_checkinteger(L, 3);
795     if (strncmp(s, "line", 4) == 0)
796     {
797 #ifdef HAVE_SANDBOX
798 	luaV_checksandbox(L);
799 #endif
800 	if (v < 1 || v > (*w)->w_buffer->b_ml.ml_line_count)
801 	    luaL_error(L, "line out of range");
802 	(*w)->w_cursor.lnum = v;
803 	update_screen(VALID);
804     }
805     else if (strncmp(s, "col", 3) == 0)
806     {
807 #ifdef HAVE_SANDBOX
808 	luaV_checksandbox(L);
809 #endif
810 	(*w)->w_cursor.col = v - 1;
811 	update_screen(VALID);
812     }
813 #ifdef FEAT_VERTSPLIT
814     else if (strncmp(s, "width", 5) == 0)
815     {
816 	win_T *win = curwin;
817 #ifdef FEAT_GUI
818 	need_mouse_correct = TRUE;
819 #endif
820 	curwin = *w;
821 	win_setwidth(v);
822 	curwin = win;
823     }
824 #endif
825     else if (strncmp(s, "height", 6) == 0)
826     {
827 	win_T *win = curwin;
828 #ifdef FEAT_GUI
829 	need_mouse_correct = TRUE;
830 #endif
831 	curwin = *w;
832 	win_setheight(v);
833 	curwin = win;
834     }
835     else
836 	luaL_error(L, "invalid window property: `%s'", s);
837     return 0;
838 }
839 
840     static int
841 luaV_window_next(lua_State *L)
842 {
843     luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
844     luaV_pushwindow(L, (*w)->w_next);
845     return 1;
846 }
847 
848     static int
849 luaV_window_previous(lua_State *L)
850 {
851     luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
852     luaV_pushwindow(L, (*w)->w_prev);
853     return 1;
854 }
855 
856     static int
857 luaV_window_isvalid(lua_State *L)
858 {
859     luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
860     lua_pushlightuserdata(L, (void *) (*w));
861     lua_rawget(L, LUA_ENVIRONINDEX);
862     lua_pushboolean(L, !lua_isnil(L, -1));
863     return 1;
864 }
865 
866 static const luaL_Reg luaV_Window_mt[] = {
867     {"__tostring", luaV_window_tostring},
868     {"__call", luaV_window_call},
869     {"__index", luaV_window_index},
870     {"__newindex", luaV_window_newindex},
871     {"next", luaV_window_next},
872     {"previous", luaV_window_previous},
873     {"isvalid", luaV_window_isvalid},
874     {NULL, NULL}
875 };
876 
877 
878 /* =======   Vim module   ======= */
879 
880     static int
881 luaV_print(lua_State *L)
882 {
883     int i, n = lua_gettop(L); /* nargs */
884     const char *s;
885     size_t l;
886     luaL_Buffer b;
887     luaL_buffinit(L, &b);
888     lua_getglobal(L, "tostring");
889     for (i = 1; i <= n; i++)
890     {
891 	lua_pushvalue(L, -1); /* tostring */
892 	lua_pushvalue(L, i); /* arg */
893 	lua_call(L, 1, 1);
894 	s = lua_tolstring(L, -1, &l);
895 	if (s == NULL)
896 	    return luaL_error(L, "cannot convert to string");
897 	if (i > 1) luaL_addchar(&b, ' '); /* use space instead of tab */
898 	luaV_addlstring(&b, s, l, 0);
899 	lua_pop(L, 1);
900     }
901     luaL_pushresult(&b);
902     luaV_msg(L);
903     return 0;
904 }
905 
906     static int
907 luaV_command(lua_State *L)
908 {
909     do_cmdline_cmd((char_u *) luaL_checkstring(L, 1));
910     update_screen(VALID);
911     return 0;
912 }
913 
914     static int
915 luaV_eval(lua_State *L)
916 {
917     typval_T *tv = eval_expr((char_u *) luaL_checkstring(L, 1), NULL);
918     if (tv == NULL) luaL_error(L, "invalid expression");
919     luaV_pushtypval(L, tv);
920     return 1;
921 }
922 
923     static int
924 luaV_beep(lua_State *L UNUSED)
925 {
926     vim_beep();
927     return 0;
928 }
929 
930     static int
931 luaV_line(lua_State *L)
932 {
933     luaV_pushline(L, curbuf, curwin->w_cursor.lnum);
934     return 1;
935 }
936 
937     static int
938 luaV_buffer(lua_State *L)
939 {
940     buf_T *buf;
941     if (lua_isstring(L, 1)) /* get by number or name? */
942     {
943 	if (lua_isnumber(L, 1)) /* by number? */
944 	{
945 	    int n = lua_tointeger(L, 1);
946 	    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
947 		if (buf->b_fnum == n) break;
948 	}
949 	else { /* by name */
950 	    size_t l;
951 	    const char *s = lua_tolstring(L, 1, &l);
952 	    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
953 	    {
954 		if (buf->b_ffname == NULL || buf->b_sfname == NULL)
955 		{
956 		    if (l == 0) break;
957 		}
958 		else if (strncmp(s, (char *)buf->b_ffname, l) == 0
959 			|| strncmp(s, (char *)buf->b_sfname, l) == 0)
960 		    break;
961 	    }
962 	}
963 	if (buf == NULL) /* not found? */
964 	    lua_pushnil(L);
965 	else
966 	    luaV_pushbuffer(L, buf);
967     }
968     else {
969 	buf = (lua_toboolean(L, 1)) ? firstbuf : curbuf; /* first buffer? */
970 	luaV_pushbuffer(L, buf);
971     }
972     return 1;
973 }
974 
975     static int
976 luaV_window(lua_State *L)
977 {
978     win_T *win;
979     if (lua_isnumber(L, 1)) /* get by number? */
980     {
981 	int n = lua_tointeger(L, 1);
982 	for (win = firstwin; win != NULL; win = win->w_next, n--)
983 	    if (n == 1) break;
984 	if (win == NULL) /* not found? */
985 	    lua_pushnil(L);
986 	else
987 	    luaV_pushwindow(L, win);
988     }
989     else {
990 	win = (lua_toboolean(L, 1)) ? firstwin : curwin; /* first window? */
991 	luaV_pushwindow(L, win);
992     }
993     return 1;
994 }
995 
996     static int
997 luaV_open(lua_State *L)
998 {
999     luaV_Buffer *b;
1000     char_u *s = NULL;
1001 #ifdef HAVE_SANDBOX
1002     luaV_checksandbox(L);
1003 #endif
1004     if (lua_isstring(L, 1)) s = (char_u *) lua_tostring(L, 1);
1005     b = luaV_pushbuffer(L, buflist_new(s, NULL, 1L, BLN_LISTED));
1006     return 1;
1007 }
1008 
1009     static int
1010 luaV_isbuffer(lua_State *L)
1011 {
1012     lua_pushboolean(L, luaV_toudata(L, 1, LUAVIM_BUFFER) != NULL);
1013     return 1;
1014 }
1015 
1016     static int
1017 luaV_iswindow(lua_State *L)
1018 {
1019     lua_pushboolean(L, luaV_toudata(L, 1, LUAVIM_WINDOW) != NULL);
1020     return 1;
1021 }
1022 
1023 /* for freeing buffer and window objects; lightuserdata as arg */
1024     static int
1025 luaV_free(lua_State *L)
1026 {
1027     lua_pushvalue(L, 1); /* lightudata */
1028     lua_rawget(L, LUA_ENVIRONINDEX);
1029     if (!lua_isnil(L, -1))
1030     {
1031 	lua_pushnil(L);
1032 	lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = nil */
1033 	lua_pushnil(L);
1034 	lua_rawset(L, LUA_ENVIRONINDEX); /* env[lightudata] = nil */
1035     }
1036     return 0;
1037 }
1038 
1039 static const luaL_Reg luaV_module[] = {
1040     {"command", luaV_command},
1041     {"eval", luaV_eval},
1042     {"beep", luaV_beep},
1043     {"line", luaV_line},
1044     {"buffer", luaV_buffer},
1045     {"window", luaV_window},
1046     {"open", luaV_open},
1047     {"isbuffer", luaV_isbuffer},
1048     {"iswindow", luaV_iswindow},
1049     {NULL, NULL}
1050 };
1051 
1052     static int
1053 luaopen_vim(lua_State *L)
1054 {
1055     /* set environment */
1056     lua_newtable(L);
1057     lua_newtable(L);
1058     lua_pushliteral(L, "v");
1059     lua_setfield(L, -2, "__mode");
1060     lua_setmetatable(L, -2);
1061     lua_replace(L, LUA_ENVIRONINDEX);
1062     /* print */
1063     lua_pushcfunction(L, luaV_print);
1064     lua_setglobal(L, "print");
1065     /* free */
1066     lua_pushlightuserdata(L, (void *) LUAVIM_FREE);
1067     lua_pushcfunction(L, luaV_free);
1068     lua_rawset(L, LUA_REGISTRYINDEX);
1069     /* register */
1070     luaV_newmetatable(L, LUAVIM_BUFFER);
1071     luaL_register(L, NULL, luaV_Buffer_mt);
1072     luaV_newmetatable(L, LUAVIM_WINDOW);
1073     luaL_register(L, NULL, luaV_Window_mt);
1074     luaL_register(L, LUAVIM_NAME, luaV_module);
1075     return 0;
1076 }
1077 
1078     static lua_State *
1079 luaV_newstate(void)
1080 {
1081     lua_State *L = luaL_newstate();
1082     const luaL_Reg luaV_core_libs[] = {
1083 	{"", luaopen_base},
1084 	{LUA_TABLIBNAME, luaopen_table},
1085 	{LUA_STRLIBNAME, luaopen_string},
1086 	{LUA_MATHLIBNAME, luaopen_math},
1087 	{LUA_OSLIBNAME, luaopen_os}, /* restricted */
1088 	{LUA_LOADLIBNAME, luaopen_package},
1089 	{LUA_DBLIBNAME, luaopen_debug},
1090 	{NULL, NULL}
1091     };
1092     const char *os_funcs[] = {
1093 	"date", "clock", "time", "difftime", "getenv", NULL
1094     };
1095     const luaL_Reg *reg = luaV_core_libs;
1096     const char **s = os_funcs;
1097     /* core libs */
1098     for ( ; reg->func; reg++)
1099     {
1100 	lua_pushcfunction(L, reg->func);
1101 	lua_pushstring(L, reg->name);
1102 	lua_call(L, 1, 0);
1103     }
1104     /* restricted os lib */
1105     lua_getglobal(L, LUA_OSLIBNAME);
1106     lua_newtable(L);
1107     for ( ; *s; s++)
1108     {
1109 	lua_getfield(L, -2, *s);
1110 	lua_setfield(L, -2, *s);
1111     }
1112     lua_setglobal(L, LUA_OSLIBNAME);
1113     lua_pop(L, 1); /* os table */
1114     /* vim */
1115     lua_pushcfunction(L, luaopen_vim);
1116     lua_call(L, 0, 0);
1117     return L;
1118 }
1119 
1120     static void
1121 luaV_setrange(lua_State *L, int line1, int line2)
1122 {
1123     lua_getglobal(L, LUAVIM_NAME);
1124     lua_pushinteger(L, line1);
1125     lua_setfield(L, -2, "firstline");
1126     lua_pushinteger(L, line2);
1127     lua_setfield(L, -2, "lastline");
1128     lua_pop(L, 1); /* vim table */
1129 }
1130 
1131 
1132 /* =======   Interface   ======= */
1133 
1134 static lua_State *L = NULL;
1135 
1136     static int
1137 lua_init(void)
1138 {
1139     if (L == NULL)
1140     {
1141 #ifdef DYNAMIC_LUA
1142 	if (!lua_enabled(TRUE))
1143 	{
1144 	    EMSG(_("Lua library cannot be loaded."));
1145 	    return FAIL;
1146 	}
1147 #endif
1148 	L = luaV_newstate();
1149     }
1150     return OK;
1151 }
1152 
1153     void
1154 lua_end(void)
1155 {
1156     if (L != NULL)
1157     {
1158 	lua_close(L);
1159 	L = NULL;
1160 #ifdef DYNAMIC_LUA
1161 	end_dynamic_lua();
1162 #endif
1163     }
1164 }
1165 
1166 /* ex commands */
1167     void
1168 ex_lua(exarg_T *eap)
1169 {
1170     char *script;
1171     if (lua_init() == FAIL) return;
1172     script = (char *) script_get(eap, eap->arg);
1173     if (!eap->skip)
1174     {
1175 	char *s = (script) ? script :  (char *) eap->arg;
1176 	luaV_setrange(L, eap->line1, eap->line2);
1177 	if (luaL_loadbuffer(L, s, strlen(s), LUAVIM_CHUNKNAME)
1178 		|| lua_pcall(L, 0, 0, 0))
1179 	    luaV_emsg(L);
1180     }
1181     if (script != NULL) vim_free(script);
1182 }
1183 
1184     void
1185 ex_luado(exarg_T *eap)
1186 {
1187     linenr_T l;
1188     const char *s = (const char *) eap->arg;
1189     luaL_Buffer b;
1190     size_t len;
1191     if (lua_init() == FAIL) return;
1192     if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL)
1193     {
1194 	EMSG(_("cannot save undo information"));
1195 	return;
1196     }
1197     luaV_setrange(L, eap->line1, eap->line2);
1198     luaL_buffinit(L, &b);
1199     luaL_addlstring(&b, "return function(line) ", 22); /* header */
1200     luaL_addlstring(&b, s, strlen(s));
1201     luaL_addlstring(&b, " end", 4); /* footer */
1202     luaL_pushresult(&b);
1203     s = lua_tolstring(L, -1, &len);
1204     if (luaL_loadbuffer(L, s, len, LUAVIM_CHUNKNAME))
1205     {
1206 	luaV_emsg(L);
1207 	lua_pop(L, 1); /* function body */
1208 	return;
1209     }
1210     lua_call(L, 0, 1);
1211     lua_replace(L, -2); /* function -> body */
1212     for (l = eap->line1; l <= eap->line2; l++)
1213     {
1214 	lua_pushvalue(L, -1); /* function */
1215 	luaV_pushline(L, curbuf, l); /* current line as arg */
1216 	if (lua_pcall(L, 1, 1, 0))
1217 	{
1218 	    luaV_emsg(L);
1219 	    break;
1220 	}
1221 	if (lua_isstring(L, -1)) /* update line? */
1222 	{
1223 #ifdef HAVE_SANDBOX
1224 	    luaV_checksandbox(L);
1225 #endif
1226 	    ml_replace(l, luaV_toline(L, -1), TRUE);
1227 	    changed_bytes(l, 0);
1228 	    lua_pop(L, 1); /* result from luaV_toline */
1229 	}
1230 	lua_pop(L, 1); /* line */
1231     }
1232     lua_pop(L, 1); /* function */
1233     check_cursor();
1234     update_screen(NOT_VALID);
1235 }
1236 
1237     void
1238 ex_luafile(exarg_T *eap)
1239 {
1240     if (lua_init() == FAIL)
1241 	return;
1242     if (!eap->skip)
1243     {
1244 	luaV_setrange(L, eap->line1, eap->line2);
1245 	if (luaL_loadfile(L, (char *) eap->arg) || lua_pcall(L, 0, 0, 0))
1246 	    luaV_emsg(L);
1247     }
1248 }
1249 
1250 /* buffer */
1251     void
1252 lua_buffer_free(buf_T *buf)
1253 {
1254     if (lua_init() == FAIL) return;
1255     luaV_getfield(L, LUAVIM_FREE);
1256     lua_pushlightuserdata(L, (void *) buf);
1257     lua_call(L, 1, 0);
1258 }
1259 
1260 /* window */
1261     void
1262 lua_window_free(win_T *win)
1263 {
1264     if (lua_init() == FAIL) return;
1265     luaV_getfield(L, LUAVIM_FREE);
1266     lua_pushlightuserdata(L, (void *) win);
1267     lua_call(L, 1, 0);
1268 }
1269 
1270 #endif
1271