blob: d05c1e33575890ace4bf09bdd9a137b65f443a6c [file] [log] [blame]
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001/* 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
26typedef buf_T *luaV_Buffer;
27typedef win_T *luaV_Window;
28typedef void (*msgfunc_T)(char_u *);
29
30static const char LUAVIM_BUFFER[] = "buffer";
31static const char LUAVIM_WINDOW[] = "window";
32static 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 */
104void (*dll_luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l);
105int (*dll_luaL_typerror) (lua_State *L, int narg, const char *tname);
106const char *(*dll_luaL_checklstring) (lua_State *L, int numArg, size_t *l);
107lua_Integer (*dll_luaL_checkinteger) (lua_State *L, int numArg);
108lua_Integer (*dll_luaL_optinteger) (lua_State *L, int nArg, lua_Integer def);
109void (*dll_luaL_checktype) (lua_State *L, int narg, int t);
110int (*dll_luaL_error) (lua_State *L, const char *fmt, ...);
111int (*dll_luaL_loadfile) (lua_State *L, const char *filename);
112int (*dll_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name);
113lua_State *(*dll_luaL_newstate) (void);
114void (*dll_luaL_buffinit) (lua_State *L, luaL_Buffer *B);
115char *(*dll_luaL_prepbuffer) (luaL_Buffer *B);
116void (*dll_luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
117void (*dll_luaL_pushresult) (luaL_Buffer *B);
118/* lua */
119void (*dll_lua_close) (lua_State *L);
120int (*dll_lua_gettop) (lua_State *L);
121void (*dll_lua_settop) (lua_State *L, int idx);
122void (*dll_lua_pushvalue) (lua_State *L, int idx);
123void (*dll_lua_replace) (lua_State *L, int idx);
124int (*dll_lua_isnumber) (lua_State *L, int idx);
125int (*dll_lua_isstring) (lua_State *L, int idx);
126int (*dll_lua_type) (lua_State *L, int idx);
127int (*dll_lua_rawequal) (lua_State *L, int idx1, int idx2);
128lua_Number (*dll_lua_tonumber) (lua_State *L, int idx);
129lua_Integer (*dll_lua_tointeger) (lua_State *L, int idx);
130int (*dll_lua_toboolean) (lua_State *L, int idx);
131const char *(*dll_lua_tolstring) (lua_State *L, int idx, size_t *len);
132void *(*dll_lua_touserdata) (lua_State *L, int idx);
133void (*dll_lua_pushnil) (lua_State *L);
134void (*dll_lua_pushnumber) (lua_State *L, lua_Number n);
135void (*dll_lua_pushinteger) (lua_State *L, lua_Integer n);
136void (*dll_lua_pushlstring) (lua_State *L, const char *s, size_t l);
137void (*dll_lua_pushstring) (lua_State *L, const char *s);
138const char *(*dll_lua_pushfstring) (lua_State *L, const char *fmt, ...);
139void (*dll_lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
140void (*dll_lua_pushboolean) (lua_State *L, int b);
141void (*dll_lua_pushlightuserdata) (lua_State *L, void *p);
142void (*dll_lua_getfield) (lua_State *L, int idx, const char *k);
143void (*dll_lua_rawget) (lua_State *L, int idx);
144void (*dll_lua_createtable) (lua_State *L, int narr, int nrec);
145void *(*dll_lua_newuserdata) (lua_State *L, size_t sz);
146int (*dll_lua_getmetatable) (lua_State *L, int objindex);
147void (*dll_lua_setfield) (lua_State *L, int idx, const char *k);
148void (*dll_lua_rawset) (lua_State *L, int idx);
149void (*dll_lua_rawseti) (lua_State *L, int idx, int n);
150int (*dll_lua_setmetatable) (lua_State *L, int objindex);
151void (*dll_lua_call) (lua_State *L, int nargs, int nresults);
152int (*dll_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
153/* libs */
154int (*dll_luaopen_base) (lua_State *L);
155int (*dll_luaopen_table) (lua_State *L);
156int (*dll_luaopen_string) (lua_State *L);
157int (*dll_luaopen_math) (lua_State *L);
158int (*dll_luaopen_os) (lua_State *L);
159int (*dll_luaopen_package) (lua_State *L);
160int (*dll_luaopen_debug) (lua_State *L);
161
162typedef void **luaV_function;
163typedef struct {
164 const char *name;
165 luaV_function func;
166} luaV_Reg;
167
168static 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
230static HINSTANCE hinstLua = 0;
231
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200232 static void
233end_dynamic_lua(void)
234{
235 if (hinstLua)
236 {
237 FreeLibrary(hinstLua);
238 hinstLua = 0;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200239 }
240}
241
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200242 static int
243lua_link_init(char *libname, int verbose)
244{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200245 const luaV_Reg *reg;
246 if (hinstLua) return OK;
247 hinstLua = LoadLibrary(libname);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200248 if (!hinstLua)
249 {
250 if (verbose)
251 EMSG2(_(e_loadlib), libname);
252 return FAIL;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200253 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200254 for (reg = luaV_dll; reg->func; reg++)
255 {
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200256 if ((*reg->func = GetProcAddress(hinstLua, reg->name)) == NULL) {
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200257 FreeLibrary(hinstLua);
258 hinstLua = 0;
259 if (verbose)
260 EMSG2(_(e_loadfunc), reg->name);
261 return FAIL;
262 }
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200263 }
264 return OK;
265}
266
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200267 int
268lua_enabled(int verbose)
269{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200270 return lua_link_init(DYNAMIC_LUA_DLL, verbose) == OK;
271}
272
273#endif /* DYNAMIC_LUA */
274
275
276/* ======= Internal ======= */
277
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200278 static void
279luaV_newmetatable(lua_State *L, const char *tname)
280{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200281 lua_newtable(L);
282 lua_pushlightuserdata(L, (void *) tname);
283 lua_pushvalue(L, -2);
284 lua_rawset(L, LUA_REGISTRYINDEX);
285}
286
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200287 static void *
288luaV_toudata(lua_State *L, int ud, const char *tname)
289{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200290 void *p = lua_touserdata(L, ud);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200291
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 }
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200303 }
304 return NULL;
305}
306
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200307 static void *
308luaV_checkudata(lua_State *L, int ud, const char *tname)
309{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200310 void *p = luaV_toudata(L, ud, tname);
311 if (p == NULL) luaL_typerror(L, ud, tname);
312 return p;
313}
314
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200315 static void
316luaV_pushtypval(lua_State *L, typval_T *tv)
317{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200318 if (tv == NULL) luaL_error(L, "null type");
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200319 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;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200327#ifdef FEAT_FLOAT
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200328 case VAR_FLOAT:
329 lua_pushnumber(L, (lua_Number) tv->vval.v_float);
330 break;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200331#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200332 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");
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200393 }
394}
395
396/* similar to luaL_addlstring, but replaces \0 with \n if toline and
397 * \n with \0 otherwise */
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200398 static void
399luaV_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++;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200410 }
411}
412
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200413 static void
414luaV_pushline(lua_State *L, buf_T *buf, linenr_T n)
415{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200416 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200423 static char_u *
424luaV_toline(lua_State *L, int pos)
425{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200426 size_t l;
427 const char *s = lua_tolstring(L, pos, &l);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200428
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200429 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 */
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200438 static void
439luaV_msgfunc(lua_State *L, msgfunc_T mf)
440{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200441 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);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200449 while (l--)
450 {
451 if (*p++ == '\0') /* break? */
452 {
453 mf((char_u *) s);
454 s = p;
455 }
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200456 }
457 mf((char_u *) s);
458 lua_pop(L, 2); /* original and modified strings */
459}
460
461
462/* ======= Buffer type ======= */
463
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200464 static luaV_Buffer *
465luaV_newbuffer(lua_State *L, buf_T *buf)
466{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200467 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200482 static luaV_Buffer *
483luaV_pushbuffer (lua_State *L, buf_T *buf)
484{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200485 luaV_Buffer *b = NULL;
486 if (buf == NULL)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200487 lua_pushnil(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200488 else {
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200489 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);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200498 }
499 return b;
500}
501
502/* Buffer metamethods */
503
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200504 static int
505luaV_buffer_tostring(lua_State *L)
506{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200507 lua_pushfstring(L, "%s: %p", LUAVIM_BUFFER, lua_touserdata(L, 1));
508 return 1;
509}
510
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200511 static int
512luaV_buffer_len(lua_State *L)
513{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200514 luaV_Buffer *b = lua_touserdata(L, 1);
515 lua_pushinteger(L, (*b)->b_ml.ml_line_count);
516 return 1;
517}
518
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200519 static int
520luaV_buffer_call(lua_State *L)
521{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200522 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200528 static int
529luaV_buffer_index(lua_State *L)
530{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200531 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)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200534 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);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200555 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200556 else
557 lua_pushnil(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200558 return 1;
559}
560
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200561 static int
562luaV_buffer_newindex(lua_State *L)
563{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200564 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)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200570 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;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200603 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200604 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();
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200622 }
623 else
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200624 luaL_error(L, "wrong argument to change line");
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200625 return 0;
626}
627
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200628 static int
629luaV_buffer_insert(lua_State *L)
630{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200631 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;
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200645 if (u_save(n, n + 1) == FAIL)
646 {
647 curbuf = buf;
648 luaL_error(L, "cannot save undo information");
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200649 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200650 else if (ml_append(n, luaV_toline(L, 2), 0, FALSE) == FAIL)
651 {
652 curbuf = buf;
653 luaL_error(L, "cannot insert line");
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200654 }
655 else
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200656 appended_lines_mark(n, 1L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200657 curbuf = buf;
658 update_screen(VALID);
659 return 0;
660}
661
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200662 static int
663luaV_buffer_next(lua_State *L)
664{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200665 luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
666 luaV_pushbuffer(L, (*b)->b_next);
667 return 1;
668}
669
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200670 static int
671luaV_buffer_previous(lua_State *L)
672{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200673 luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
674 luaV_pushbuffer(L, (*b)->b_prev);
675 return 1;
676}
677
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200678 static int
679luaV_buffer_isvalid(lua_State *L)
680{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200681 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
688static 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200704 static luaV_Window *
705luaV_newwindow(lua_State *L, win_T *win)
706{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200707 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200722 static luaV_Window *
723luaV_pushwindow(lua_State *L, win_T *win)
724{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200725 luaV_Window *w = NULL;
726 if (win == NULL)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200727 lua_pushnil(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200728 else {
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200729 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);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200737 }
738 return w;
739}
740
741/* Window metamethods */
742
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200743 static int
744luaV_window_tostring(lua_State *L)
745{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200746 lua_pushfstring(L, "%s: %p", LUAVIM_WINDOW, lua_touserdata(L, 1));
747 return 1;
748}
749
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200750 static int
751luaV_window_call(lua_State *L)
752{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200753 luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
754 lua_settop(L, 1);
755 win_goto(*w);
756 return 1;
757}
758
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200759 static int
760luaV_window_index(lua_State *L)
761{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200762 luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
763 const char *s = luaL_checkstring(L, 2);
764 if (strncmp(s, "buffer", 6) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200765 luaV_pushbuffer(L, (*w)->w_buffer);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200766 else if (strncmp(s, "line", 4) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200767 lua_pushinteger(L, (*w)->w_cursor.lnum);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200768 else if (strncmp(s, "col", 3) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200769 lua_pushinteger(L, (*w)->w_cursor.col + 1);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200770#ifdef FEAT_VERTSPLIT
771 else if (strncmp(s, "width", 5) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200772 lua_pushinteger(L, W_WIDTH((*w)));
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200773#endif
774 else if (strncmp(s, "height", 6) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200775 lua_pushinteger(L, (*w)->w_height);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200776 /* methods */
777 else if (strncmp(s, "next", 4) == 0
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200778 || strncmp(s, "previous", 8) == 0
779 || strncmp(s, "isvalid", 7) == 0)
780 {
781 lua_getmetatable(L, 1);
782 lua_getfield(L, -1, s);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200783 }
784 else
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200785 lua_pushnil(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200786 return 1;
787}
788
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200789 static int
790luaV_window_newindex (lua_State *L)
791{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200792 luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
793 const char *s = luaL_checkstring(L, 2);
794 int v = luaL_checkinteger(L, 3);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200795 if (strncmp(s, "line", 4) == 0)
796 {
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200797#ifdef HAVE_SANDBOX
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200798 luaV_checksandbox(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200799#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200800 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);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200804 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200805 else if (strncmp(s, "col", 3) == 0)
806 {
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200807#ifdef HAVE_SANDBOX
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200808 luaV_checksandbox(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200809#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200810 (*w)->w_cursor.col = v - 1;
811 update_screen(VALID);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200812 }
813#ifdef FEAT_VERTSPLIT
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200814 else if (strncmp(s, "width", 5) == 0)
815 {
816 win_T *win = curwin;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200817#ifdef FEAT_GUI
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200818 need_mouse_correct = TRUE;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200819#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200820 curwin = *w;
821 win_setwidth(v);
822 curwin = win;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200823 }
824#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200825 else if (strncmp(s, "height", 6) == 0)
826 {
827 win_T *win = curwin;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200828#ifdef FEAT_GUI
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200829 need_mouse_correct = TRUE;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200830#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200831 curwin = *w;
832 win_setheight(v);
833 curwin = win;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200834 }
835 else
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200836 luaL_error(L, "invalid window property: `%s'", s);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200837 return 0;
838}
839
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200840 static int
841luaV_window_next(lua_State *L)
842{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200843 luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
844 luaV_pushwindow(L, (*w)->w_next);
845 return 1;
846}
847
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200848 static int
849luaV_window_previous(lua_State *L)
850{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200851 luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
852 luaV_pushwindow(L, (*w)->w_prev);
853 return 1;
854}
855
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200856 static int
857luaV_window_isvalid(lua_State *L)
858{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200859 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
866static 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200880 static int
881luaV_print(lua_State *L)
882{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200883 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");
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200889 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);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200900 }
901 luaL_pushresult(&b);
902 luaV_msg(L);
903 return 0;
904}
905
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200906 static int
907luaV_command(lua_State *L)
908{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200909 do_cmdline_cmd((char_u *) luaL_checkstring(L, 1));
910 update_screen(VALID);
911 return 0;
912}
913
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200914 static int
915luaV_eval(lua_State *L)
916{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200917 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200923 static int
924luaV_beep(lua_State *L)
925{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200926 vim_beep();
927 return 0;
928}
929
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200930 static int
931luaV_line(lua_State *L)
932{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200933 luaV_pushline(L, curbuf, curwin->w_cursor.lnum);
934 return 1;
935}
936
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200937 static int
938luaV_buffer(lua_State *L)
939{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200940 buf_T *buf;
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200941 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, buf->b_ffname, l) == 0
959 || strncmp(s, 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);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200967 }
968 else {
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200969 buf = (lua_toboolean(L, 1)) ? firstbuf : curbuf; /* first buffer? */
970 luaV_pushbuffer(L, buf);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200971 }
972 return 1;
973}
974
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200975 static int
976luaV_window(lua_State *L)
977{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200978 win_T *win;
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200979 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);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200988 }
989 else {
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200990 win = (lua_toboolean(L, 1)) ? firstwin : curwin; /* first window? */
991 luaV_pushwindow(L, win);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200992 }
993 return 1;
994}
995
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200996 static int
997luaV_open(lua_State *L)
998{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200999 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001009 static int
1010luaV_isbuffer(lua_State *L)
1011{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001012 lua_pushboolean(L, luaV_toudata(L, 1, LUAVIM_BUFFER) != NULL);
1013 return 1;
1014}
1015
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001016 static int
1017luaV_iswindow(lua_State *L)
1018{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001019 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 */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001024 static int
1025luaV_free(lua_State *L)
1026{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001027 lua_pushvalue(L, 1); /* lightudata */
1028 lua_rawget(L, LUA_ENVIRONINDEX);
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001029 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 */
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001035 }
1036 return 0;
1037}
1038
1039static 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001052 static int
1053luaopen_vim(lua_State *L)
1054{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001055 /* 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
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001078 static lua_State *
1079luaV_newstate(void)
1080{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001081 lua_State *L = luaL_newstate();
1082 const luaL_Reg luaV_core_libs[] = {
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001083 {"", 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}
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001091 };
1092 const char *os_funcs[] = {
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001093 "date", "clock", "time", "difftime", "getenv", NULL
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001094 };
1095 const luaL_Reg *reg = luaV_core_libs;
1096 const char **s = os_funcs;
1097 /* core libs */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001098 for ( ; reg->func; reg++)
1099 {
1100 lua_pushcfunction(L, reg->func);
1101 lua_pushstring(L, reg->name);
1102 lua_call(L, 1, 0);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001103 }
1104 /* restricted os lib */
1105 lua_getglobal(L, LUA_OSLIBNAME);
1106 lua_newtable(L);
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001107 for ( ; *s; s++)
1108 {
1109 lua_getfield(L, -2, *s);
1110 lua_setfield(L, -2, *s);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001111 }
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
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001120 static void
1121luaV_setrange(lua_State *L, int line1, int line2)
1122{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001123 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
1134static lua_State *L = NULL;
1135
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001136 static int
1137lua_init(void)
1138{
1139 if (L == NULL)
1140 {
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001141#ifdef DYNAMIC_LUA
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001142 if (!lua_enabled(TRUE))
1143 {
1144 EMSG(_("Lua library cannot be loaded."));
1145 return FAIL;
1146 }
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001147#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001148 L = luaV_newstate();
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001149 }
1150 return OK;
1151}
1152
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001153 void
1154lua_end(void)
1155{
1156 if (L != NULL)
1157 {
1158 lua_close(L);
1159 L = NULL;
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001160#ifdef DYNAMIC_LUA
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001161 end_dynamic_lua();
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001162#endif
1163 }
1164}
1165
1166/* ex commands */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001167 void
1168ex_lua(exarg_T *eap)
1169{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001170 char *script;
1171 if (lua_init() == FAIL) return;
1172 script = (char *) script_get(eap, eap->arg);
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001173 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);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001180 }
1181 if (script != NULL) vim_free(script);
1182}
1183
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001184 void
1185ex_luado(exarg_T *eap)
1186{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001187 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;
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001192 if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL)
1193 {
1194 EMSG(_("cannot save undo information"));
1195 return;
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001196 }
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);
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001204 if (luaL_loadbuffer(L, s, len, LUAVIM_CHUNKNAME))
1205 {
1206 luaV_emsg(L);
1207 lua_pop(L, 1); /* function body */
1208 return;
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001209 }
1210 lua_call(L, 0, 1);
1211 lua_replace(L, -2); /* function -> body */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001212 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 {
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001223#ifdef HAVE_SANDBOX
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001224 luaV_checksandbox(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001225#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001226 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 */
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001231 }
1232 lua_pop(L, 1); /* function */
1233 check_cursor();
1234 update_screen(NOT_VALID);
1235}
1236
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001237 void
1238ex_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);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001247 }
1248}
1249
1250/* buffer */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001251 void
1252lua_buffer_free(buf_T *buf)
1253{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001254 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 */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001261 void
1262lua_window_free(win_T *win)
1263{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001264 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