blob: 4c3f9b715fbe9d1b70744de39b9e96a202d3f4e0 [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
Bram Moolenaar2334b6d2010-07-22 21:32:16 +020044
45#ifndef WIN3264
46# include <dlfcn.h>
47# define HANDLE void*
48# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
49# define symbol_from_dll dlsym
50# define close_dll dlclose
51#else
52# define load_dll LoadLibrary
53# define symbol_from_dll GetProcAddress
54# define close_dll FreeLibrary
55#endif
56
Bram Moolenaar0ba04292010-07-14 23:23:17 +020057/* lauxlib */
58#define luaL_register dll_luaL_register
59#define luaL_typerror dll_luaL_typerror
60#define luaL_checklstring dll_luaL_checklstring
61#define luaL_checkinteger dll_luaL_checkinteger
62#define luaL_optinteger dll_luaL_optinteger
63#define luaL_checktype dll_luaL_checktype
64#define luaL_error dll_luaL_error
65#define luaL_loadfile dll_luaL_loadfile
66#define luaL_loadbuffer dll_luaL_loadbuffer
67#define luaL_newstate dll_luaL_newstate
68#define luaL_buffinit dll_luaL_buffinit
69#define luaL_prepbuffer dll_luaL_prepbuffer
70#define luaL_addlstring dll_luaL_addlstring
71#define luaL_pushresult dll_luaL_pushresult
72/* lua */
73#define lua_close dll_lua_close
74#define lua_gettop dll_lua_gettop
75#define lua_settop dll_lua_settop
76#define lua_pushvalue dll_lua_pushvalue
77#define lua_replace dll_lua_replace
78#define lua_isnumber dll_lua_isnumber
79#define lua_isstring dll_lua_isstring
80#define lua_type dll_lua_type
81#define lua_rawequal dll_lua_rawequal
82#define lua_tonumber dll_lua_tonumber
83#define lua_tointeger dll_lua_tointeger
84#define lua_toboolean dll_lua_toboolean
85#define lua_tolstring dll_lua_tolstring
86#define lua_touserdata dll_lua_touserdata
87#define lua_pushnil dll_lua_pushnil
88#define lua_pushnumber dll_lua_pushnumber
89#define lua_pushinteger dll_lua_pushinteger
90#define lua_pushlstring dll_lua_pushlstring
91#define lua_pushstring dll_lua_pushstring
92#define lua_pushfstring dll_lua_pushfstring
93#define lua_pushcclosure dll_lua_pushcclosure
94#define lua_pushboolean dll_lua_pushboolean
95#define lua_pushlightuserdata dll_lua_pushlightuserdata
96#define lua_getfield dll_lua_getfield
97#define lua_rawget dll_lua_rawget
98#define lua_createtable dll_lua_createtable
99#define lua_newuserdata dll_lua_newuserdata
100#define lua_getmetatable dll_lua_getmetatable
101#define lua_setfield dll_lua_setfield
102#define lua_rawset dll_lua_rawset
103#define lua_rawseti dll_lua_rawseti
104#define lua_setmetatable dll_lua_setmetatable
105#define lua_call dll_lua_call
106#define lua_pcall dll_lua_pcall
107/* libs */
108#define luaopen_base dll_luaopen_base
109#define luaopen_table dll_luaopen_table
110#define luaopen_string dll_luaopen_string
111#define luaopen_math dll_luaopen_math
112#define luaopen_os dll_luaopen_os
113#define luaopen_package dll_luaopen_package
114#define luaopen_debug dll_luaopen_debug
115
116/* lauxlib */
117void (*dll_luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l);
118int (*dll_luaL_typerror) (lua_State *L, int narg, const char *tname);
119const char *(*dll_luaL_checklstring) (lua_State *L, int numArg, size_t *l);
120lua_Integer (*dll_luaL_checkinteger) (lua_State *L, int numArg);
121lua_Integer (*dll_luaL_optinteger) (lua_State *L, int nArg, lua_Integer def);
122void (*dll_luaL_checktype) (lua_State *L, int narg, int t);
123int (*dll_luaL_error) (lua_State *L, const char *fmt, ...);
124int (*dll_luaL_loadfile) (lua_State *L, const char *filename);
125int (*dll_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name);
126lua_State *(*dll_luaL_newstate) (void);
127void (*dll_luaL_buffinit) (lua_State *L, luaL_Buffer *B);
128char *(*dll_luaL_prepbuffer) (luaL_Buffer *B);
129void (*dll_luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
130void (*dll_luaL_pushresult) (luaL_Buffer *B);
131/* lua */
132void (*dll_lua_close) (lua_State *L);
133int (*dll_lua_gettop) (lua_State *L);
134void (*dll_lua_settop) (lua_State *L, int idx);
135void (*dll_lua_pushvalue) (lua_State *L, int idx);
136void (*dll_lua_replace) (lua_State *L, int idx);
137int (*dll_lua_isnumber) (lua_State *L, int idx);
138int (*dll_lua_isstring) (lua_State *L, int idx);
139int (*dll_lua_type) (lua_State *L, int idx);
140int (*dll_lua_rawequal) (lua_State *L, int idx1, int idx2);
141lua_Number (*dll_lua_tonumber) (lua_State *L, int idx);
142lua_Integer (*dll_lua_tointeger) (lua_State *L, int idx);
143int (*dll_lua_toboolean) (lua_State *L, int idx);
144const char *(*dll_lua_tolstring) (lua_State *L, int idx, size_t *len);
145void *(*dll_lua_touserdata) (lua_State *L, int idx);
146void (*dll_lua_pushnil) (lua_State *L);
147void (*dll_lua_pushnumber) (lua_State *L, lua_Number n);
148void (*dll_lua_pushinteger) (lua_State *L, lua_Integer n);
149void (*dll_lua_pushlstring) (lua_State *L, const char *s, size_t l);
150void (*dll_lua_pushstring) (lua_State *L, const char *s);
151const char *(*dll_lua_pushfstring) (lua_State *L, const char *fmt, ...);
152void (*dll_lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
153void (*dll_lua_pushboolean) (lua_State *L, int b);
154void (*dll_lua_pushlightuserdata) (lua_State *L, void *p);
155void (*dll_lua_getfield) (lua_State *L, int idx, const char *k);
156void (*dll_lua_rawget) (lua_State *L, int idx);
157void (*dll_lua_createtable) (lua_State *L, int narr, int nrec);
158void *(*dll_lua_newuserdata) (lua_State *L, size_t sz);
159int (*dll_lua_getmetatable) (lua_State *L, int objindex);
160void (*dll_lua_setfield) (lua_State *L, int idx, const char *k);
161void (*dll_lua_rawset) (lua_State *L, int idx);
162void (*dll_lua_rawseti) (lua_State *L, int idx, int n);
163int (*dll_lua_setmetatable) (lua_State *L, int objindex);
164void (*dll_lua_call) (lua_State *L, int nargs, int nresults);
165int (*dll_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
166/* libs */
167int (*dll_luaopen_base) (lua_State *L);
168int (*dll_luaopen_table) (lua_State *L);
169int (*dll_luaopen_string) (lua_State *L);
170int (*dll_luaopen_math) (lua_State *L);
171int (*dll_luaopen_os) (lua_State *L);
172int (*dll_luaopen_package) (lua_State *L);
173int (*dll_luaopen_debug) (lua_State *L);
174
175typedef void **luaV_function;
176typedef struct {
177 const char *name;
178 luaV_function func;
179} luaV_Reg;
180
181static const luaV_Reg luaV_dll[] = {
182 /* lauxlib */
183 {"luaL_register", (luaV_function) &dll_luaL_register},
184 {"luaL_typerror", (luaV_function) &dll_luaL_typerror},
185 {"luaL_checklstring", (luaV_function) &dll_luaL_checklstring},
186 {"luaL_checkinteger", (luaV_function) &dll_luaL_checkinteger},
187 {"luaL_optinteger", (luaV_function) &dll_luaL_optinteger},
188 {"luaL_checktype", (luaV_function) &dll_luaL_checktype},
189 {"luaL_error", (luaV_function) &dll_luaL_error},
190 {"luaL_loadfile", (luaV_function) &dll_luaL_loadfile},
191 {"luaL_loadbuffer", (luaV_function) &dll_luaL_loadbuffer},
192 {"luaL_newstate", (luaV_function) &dll_luaL_newstate},
193 {"luaL_buffinit", (luaV_function) &dll_luaL_buffinit},
194 {"luaL_prepbuffer", (luaV_function) &dll_luaL_prepbuffer},
195 {"luaL_addlstring", (luaV_function) &dll_luaL_addlstring},
196 {"luaL_pushresult", (luaV_function) &dll_luaL_pushresult},
197 /* lua */
198 {"lua_close", (luaV_function) &dll_lua_close},
199 {"lua_gettop", (luaV_function) &dll_lua_gettop},
200 {"lua_settop", (luaV_function) &dll_lua_settop},
201 {"lua_pushvalue", (luaV_function) &dll_lua_pushvalue},
202 {"lua_replace", (luaV_function) &dll_lua_replace},
203 {"lua_isnumber", (luaV_function) &dll_lua_isnumber},
204 {"lua_isstring", (luaV_function) &dll_lua_isstring},
205 {"lua_type", (luaV_function) &dll_lua_type},
206 {"lua_rawequal", (luaV_function) &dll_lua_rawequal},
207 {"lua_tonumber", (luaV_function) &dll_lua_tonumber},
208 {"lua_tointeger", (luaV_function) &dll_lua_tointeger},
209 {"lua_toboolean", (luaV_function) &dll_lua_toboolean},
210 {"lua_tolstring", (luaV_function) &dll_lua_tolstring},
211 {"lua_touserdata", (luaV_function) &dll_lua_touserdata},
212 {"lua_pushnil", (luaV_function) &dll_lua_pushnil},
213 {"lua_pushnumber", (luaV_function) &dll_lua_pushnumber},
214 {"lua_pushinteger", (luaV_function) &dll_lua_pushinteger},
215 {"lua_pushlstring", (luaV_function) &dll_lua_pushlstring},
216 {"lua_pushstring", (luaV_function) &dll_lua_pushstring},
217 {"lua_pushfstring", (luaV_function) &dll_lua_pushfstring},
218 {"lua_pushcclosure", (luaV_function) &dll_lua_pushcclosure},
219 {"lua_pushboolean", (luaV_function) &dll_lua_pushboolean},
220 {"lua_pushlightuserdata", (luaV_function) &dll_lua_pushlightuserdata},
221 {"lua_getfield", (luaV_function) &dll_lua_getfield},
222 {"lua_rawget", (luaV_function) &dll_lua_rawget},
223 {"lua_createtable", (luaV_function) &dll_lua_createtable},
224 {"lua_newuserdata", (luaV_function) &dll_lua_newuserdata},
225 {"lua_getmetatable", (luaV_function) &dll_lua_getmetatable},
226 {"lua_setfield", (luaV_function) &dll_lua_setfield},
227 {"lua_rawset", (luaV_function) &dll_lua_rawset},
228 {"lua_rawseti", (luaV_function) &dll_lua_rawseti},
229 {"lua_setmetatable", (luaV_function) &dll_lua_setmetatable},
230 {"lua_call", (luaV_function) &dll_lua_call},
231 {"lua_pcall", (luaV_function) &dll_lua_pcall},
232 /* libs */
233 {"luaopen_base", (luaV_function) &dll_luaopen_base},
234 {"luaopen_table", (luaV_function) &dll_luaopen_table},
235 {"luaopen_string", (luaV_function) &dll_luaopen_string},
236 {"luaopen_math", (luaV_function) &dll_luaopen_math},
237 {"luaopen_os", (luaV_function) &dll_luaopen_os},
238 {"luaopen_package", (luaV_function) &dll_luaopen_package},
239 {"luaopen_debug", (luaV_function) &dll_luaopen_debug},
240 {NULL, NULL}
241};
242
Bram Moolenaar2334b6d2010-07-22 21:32:16 +0200243static HANDLE hinstLua = NULL;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200244
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200245 static void
246end_dynamic_lua(void)
247{
248 if (hinstLua)
249 {
Bram Moolenaar2334b6d2010-07-22 21:32:16 +0200250 close_dll(hinstLua);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200251 hinstLua = 0;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200252 }
253}
254
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200255 static int
256lua_link_init(char *libname, int verbose)
257{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200258 const luaV_Reg *reg;
259 if (hinstLua) return OK;
Bram Moolenaar2334b6d2010-07-22 21:32:16 +0200260 hinstLua = load_dll(libname);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200261 if (!hinstLua)
262 {
263 if (verbose)
264 EMSG2(_(e_loadlib), libname);
265 return FAIL;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200266 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200267 for (reg = luaV_dll; reg->func; reg++)
268 {
Bram Moolenaar2334b6d2010-07-22 21:32:16 +0200269 if ((*reg->func = symbol_from_dll(hinstLua, reg->name)) == NULL)
270 {
271 close_dll(hinstLua);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200272 hinstLua = 0;
273 if (verbose)
274 EMSG2(_(e_loadfunc), reg->name);
275 return FAIL;
276 }
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200277 }
278 return OK;
279}
280
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200281 int
282lua_enabled(int verbose)
283{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200284 return lua_link_init(DYNAMIC_LUA_DLL, verbose) == OK;
285}
286
287#endif /* DYNAMIC_LUA */
288
289
290/* ======= Internal ======= */
291
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200292 static void
293luaV_newmetatable(lua_State *L, const char *tname)
294{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200295 lua_newtable(L);
296 lua_pushlightuserdata(L, (void *) tname);
297 lua_pushvalue(L, -2);
298 lua_rawset(L, LUA_REGISTRYINDEX);
299}
300
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200301 static void *
302luaV_toudata(lua_State *L, int ud, const char *tname)
303{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200304 void *p = lua_touserdata(L, ud);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200305
306 if (p != NULL) /* value is userdata? */
307 {
308 if (lua_getmetatable(L, ud)) /* does it have a metatable? */
309 {
310 luaV_getfield(L, tname); /* get metatable */
311 if (lua_rawequal(L, -1, -2)) /* MTs match? */
312 {
313 lua_pop(L, 2); /* MTs */
314 return p;
315 }
316 }
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200317 }
318 return NULL;
319}
320
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200321 static void *
322luaV_checkudata(lua_State *L, int ud, const char *tname)
323{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200324 void *p = luaV_toudata(L, ud, tname);
325 if (p == NULL) luaL_typerror(L, ud, tname);
326 return p;
327}
328
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200329 static void
330luaV_pushtypval(lua_State *L, typval_T *tv)
331{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200332 if (tv == NULL) luaL_error(L, "null type");
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200333 switch (tv->v_type)
334 {
335 case VAR_STRING:
336 lua_pushstring(L, (char *) tv->vval.v_string);
337 break;
338 case VAR_NUMBER:
339 lua_pushinteger(L, (int) tv->vval.v_number);
340 break;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200341#ifdef FEAT_FLOAT
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200342 case VAR_FLOAT:
343 lua_pushnumber(L, (lua_Number) tv->vval.v_float);
344 break;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200345#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200346 case VAR_LIST: {
347 list_T *l = tv->vval.v_list;
348
349 if (l != NULL)
350 {
351 /* check cache */
352 lua_pushlightuserdata(L, (void *) l);
353 lua_rawget(L, LUA_ENVIRONINDEX);
354 if (lua_isnil(L, -1)) /* not interned? */
355 {
356 listitem_T *li;
357 int n = 0;
358 lua_pop(L, 1); /* nil */
359 lua_newtable(L);
360 lua_pushlightuserdata(L, (void *) l);
361 lua_pushvalue(L, -2);
362 lua_rawset(L, LUA_ENVIRONINDEX);
363 for (li = l->lv_first; li != NULL; li = li->li_next)
364 {
365 luaV_pushtypval(L, &li->li_tv);
366 lua_rawseti(L, -2, ++n);
367 }
368 }
369 }
370 else lua_pushnil(L);
371 break;
372 }
373 case VAR_DICT: {
374 dict_T *d = tv->vval.v_dict;
375
376 if (d != NULL)
377 {
378 /* check cache */
379 lua_pushlightuserdata(L, (void *) d);
380 lua_rawget(L, LUA_ENVIRONINDEX);
Bram Moolenaar2334b6d2010-07-22 21:32:16 +0200381 if (lua_isnil(L, -1)) /* not interned? */
382 {
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200383 hashtab_T *ht = &d->dv_hashtab;
384 hashitem_T *hi;
385 int n = ht->ht_used; /* remaining items */
386 lua_pop(L, 1); /* nil */
387 lua_newtable(L);
388 lua_pushlightuserdata(L, (void *) d);
389 lua_pushvalue(L, -2);
390 lua_rawset(L, LUA_ENVIRONINDEX);
391 for (hi = ht->ht_array; n > 0; hi++)
392 {
393 if (!HASHITEM_EMPTY(hi))
394 {
395 dictitem_T *di = dict_lookup(hi);
396 luaV_pushtypval(L, &di->di_tv);
397 lua_setfield(L, -2, (char *) hi->hi_key);
398 n--;
399 }
400 }
401 }
402 }
403 else lua_pushnil(L);
404 break;
405 }
406 default:
407 luaL_error(L, "invalid type");
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200408 }
409}
410
411/* similar to luaL_addlstring, but replaces \0 with \n if toline and
412 * \n with \0 otherwise */
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200413 static void
414luaV_addlstring(luaL_Buffer *b, const char *s, size_t l, int toline)
415{
416 while (l--)
417 {
418 if (*s == '\0' && toline)
419 luaL_addchar(b, '\n');
420 else if (*s == '\n' && !toline)
421 luaL_addchar(b, '\0');
422 else
423 luaL_addchar(b, *s);
424 s++;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200425 }
426}
427
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200428 static void
429luaV_pushline(lua_State *L, buf_T *buf, linenr_T n)
430{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200431 const char *s = (const char *) ml_get_buf(buf, n, FALSE);
432 luaL_Buffer b;
433 luaL_buffinit(L, &b);
434 luaV_addlstring(&b, s, strlen(s), 0);
435 luaL_pushresult(&b);
436}
437
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200438 static char_u *
439luaV_toline(lua_State *L, int pos)
440{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200441 size_t l;
442 const char *s = lua_tolstring(L, pos, &l);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200443
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200444 luaL_Buffer b;
445 luaL_buffinit(L, &b);
446 luaV_addlstring(&b, s, l, 1);
447 luaL_pushresult(&b);
448 return (char_u *) lua_tostring(L, -1);
449}
450
451/* pops a string s from the top of the stack and calls mf(t) for pieces t of
452 * s separated by newlines */
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200453 static void
454luaV_msgfunc(lua_State *L, msgfunc_T mf)
455{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200456 luaL_Buffer b;
457 size_t l;
458 const char *p, *s = lua_tolstring(L, -1, &l);
459 luaL_buffinit(L, &b);
460 luaV_addlstring(&b, s, l, 0);
461 luaL_pushresult(&b);
462 /* break string */
463 p = s = lua_tolstring(L, -1, &l);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200464 while (l--)
465 {
466 if (*p++ == '\0') /* break? */
467 {
468 mf((char_u *) s);
469 s = p;
470 }
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200471 }
472 mf((char_u *) s);
473 lua_pop(L, 2); /* original and modified strings */
474}
475
476
477/* ======= Buffer type ======= */
478
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200479 static luaV_Buffer *
480luaV_newbuffer(lua_State *L, buf_T *buf)
481{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200482 luaV_Buffer *b = (luaV_Buffer *) lua_newuserdata(L, sizeof(luaV_Buffer));
483 *b = buf;
484 lua_pushlightuserdata(L, (void *) buf);
485 lua_pushvalue(L, -2);
486 lua_rawset(L, LUA_ENVIRONINDEX); /* env[buf] = udata */
487 /* to avoid GC, store as key in env */
488 lua_pushvalue(L, -1);
489 lua_pushboolean(L, 1);
490 lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = true */
491 /* set metatable */
492 luaV_getfield(L, LUAVIM_BUFFER);
493 lua_setmetatable(L, -2);
494 return b;
495}
496
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200497 static luaV_Buffer *
498luaV_pushbuffer (lua_State *L, buf_T *buf)
499{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200500 luaV_Buffer *b = NULL;
501 if (buf == NULL)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200502 lua_pushnil(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200503 else {
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200504 lua_pushlightuserdata(L, (void *) buf);
505 lua_rawget(L, LUA_ENVIRONINDEX);
506 if (lua_isnil(L, -1)) /* not interned? */
507 {
508 lua_pop(L, 1);
509 b = luaV_newbuffer(L, buf);
510 }
511 else
512 b = (luaV_Buffer *) lua_touserdata(L, -1);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200513 }
514 return b;
515}
516
517/* Buffer metamethods */
518
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200519 static int
520luaV_buffer_tostring(lua_State *L)
521{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200522 lua_pushfstring(L, "%s: %p", LUAVIM_BUFFER, lua_touserdata(L, 1));
523 return 1;
524}
525
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200526 static int
527luaV_buffer_len(lua_State *L)
528{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200529 luaV_Buffer *b = lua_touserdata(L, 1);
530 lua_pushinteger(L, (*b)->b_ml.ml_line_count);
531 return 1;
532}
533
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200534 static int
535luaV_buffer_call(lua_State *L)
536{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200537 luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1);
538 lua_settop(L, 1);
539 set_curbuf(*b, DOBUF_SPLIT);
540 return 1;
541}
542
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200543 static int
544luaV_buffer_index(lua_State *L)
545{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200546 luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1);
547 linenr_T n = (linenr_T) lua_tointeger(L, 2);
548 if (n > 0 && n <= (*b)->b_ml.ml_line_count)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200549 luaV_pushline(L, *b, n);
550 else if (lua_isstring(L, 2))
551 {
552 const char *s = lua_tostring(L, 2);
553 if (strncmp(s, "name", 4) == 0)
554 lua_pushstring(L, (char *) (*b)->b_sfname);
555 else if (strncmp(s, "fname", 5) == 0)
556 lua_pushstring(L, (char *) (*b)->b_ffname);
557 else if (strncmp(s, "number", 6) == 0)
558 lua_pushinteger(L, (*b)->b_fnum);
559 /* methods */
560 else if (strncmp(s, "insert", 6) == 0
561 || strncmp(s, "next", 4) == 0
562 || strncmp(s, "previous", 8) == 0
563 || strncmp(s, "isvalid", 7) == 0)
564 {
565 lua_getmetatable(L, 1);
566 lua_getfield(L, -1, s);
567 }
568 else
569 lua_pushnil(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200570 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200571 else
572 lua_pushnil(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200573 return 1;
574}
575
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200576 static int
577luaV_buffer_newindex(lua_State *L)
578{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200579 luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1);
580 linenr_T n = (linenr_T) luaL_checkinteger(L, 2);
581#ifdef HAVE_SANDBOX
582 luaV_checksandbox(L);
583#endif
584 if (n < 1 || n > (*b)->b_ml.ml_line_count)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200585 luaL_error(L, "invalid line number");
586 if (lua_isnil(L, 3)) /* delete line */
587 {
588 buf_T *buf = curbuf;
589 curbuf = *b;
590 if (u_savedel(n, 1L) == FAIL)
591 {
592 curbuf = buf;
593 luaL_error(L, "cannot save undo information");
594 }
595 else if (ml_delete(n, FALSE) == FAIL)
596 {
597 curbuf = buf;
598 luaL_error(L, "cannot delete line");
599 }
600 else {
601 deleted_lines_mark(n, 1L);
602 if (*b == curwin->w_buffer) /* fix cursor in current window? */
603 {
604 if (curwin->w_cursor.lnum >= n)
605 {
606 if (curwin->w_cursor.lnum > n)
607 {
608 curwin->w_cursor.lnum -= 1;
609 check_cursor_col();
610 }
611 else check_cursor();
612 changed_cline_bef_curs();
613 }
614 invalidate_botline();
615 }
616 }
617 curbuf = buf;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200618 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200619 else if (lua_isstring(L, 3)) /* update line */
620 {
621 buf_T *buf = curbuf;
622 curbuf = *b;
623 if (u_savesub(n) == FAIL)
624 {
625 curbuf = buf;
626 luaL_error(L, "cannot save undo information");
627 }
628 else if (ml_replace(n, luaV_toline(L, 3), TRUE) == FAIL)
629 {
630 curbuf = buf;
631 luaL_error(L, "cannot replace line");
632 }
633 else changed_bytes(n, 0);
634 curbuf = buf;
635 if (*b == curwin->w_buffer)
636 check_cursor_col();
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200637 }
638 else
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200639 luaL_error(L, "wrong argument to change line");
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200640 return 0;
641}
642
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200643 static int
644luaV_buffer_insert(lua_State *L)
645{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200646 luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
647 linenr_T last = (*b)->b_ml.ml_line_count;
648 linenr_T n = (linenr_T) luaL_optinteger(L, 3, last);
649 buf_T *buf;
650 luaL_checktype(L, 2, LUA_TSTRING);
651#ifdef HAVE_SANDBOX
652 luaV_checksandbox(L);
653#endif
654 /* fix insertion line */
655 if (n < 0) n = 0;
656 if (n > last) n = last;
657 /* insert */
658 buf = curbuf;
659 curbuf = *b;
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200660 if (u_save(n, n + 1) == FAIL)
661 {
662 curbuf = buf;
663 luaL_error(L, "cannot save undo information");
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200664 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200665 else if (ml_append(n, luaV_toline(L, 2), 0, FALSE) == FAIL)
666 {
667 curbuf = buf;
668 luaL_error(L, "cannot insert line");
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200669 }
670 else
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200671 appended_lines_mark(n, 1L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200672 curbuf = buf;
673 update_screen(VALID);
674 return 0;
675}
676
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200677 static int
678luaV_buffer_next(lua_State *L)
679{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200680 luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
681 luaV_pushbuffer(L, (*b)->b_next);
682 return 1;
683}
684
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200685 static int
686luaV_buffer_previous(lua_State *L)
687{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200688 luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
689 luaV_pushbuffer(L, (*b)->b_prev);
690 return 1;
691}
692
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200693 static int
694luaV_buffer_isvalid(lua_State *L)
695{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200696 luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
697 lua_pushlightuserdata(L, (void *) (*b));
698 lua_rawget(L, LUA_ENVIRONINDEX);
699 lua_pushboolean(L, !lua_isnil(L, -1));
700 return 1;
701}
702
703static const luaL_Reg luaV_Buffer_mt[] = {
704 {"__tostring", luaV_buffer_tostring},
705 {"__len", luaV_buffer_len},
706 {"__call", luaV_buffer_call},
707 {"__index", luaV_buffer_index},
708 {"__newindex", luaV_buffer_newindex},
709 {"insert", luaV_buffer_insert},
710 {"next", luaV_buffer_next},
711 {"previous", luaV_buffer_previous},
712 {"isvalid", luaV_buffer_isvalid},
713 {NULL, NULL}
714};
715
716
717/* ======= Window type ======= */
718
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200719 static luaV_Window *
720luaV_newwindow(lua_State *L, win_T *win)
721{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200722 luaV_Window *w = (luaV_Window *) lua_newuserdata(L, sizeof(luaV_Window));
723 *w = win;
724 lua_pushlightuserdata(L, (void *) win);
725 lua_pushvalue(L, -2);
726 lua_rawset(L, LUA_ENVIRONINDEX); /* env[win] = udata */
727 /* to avoid GC, store as key in env */
728 lua_pushvalue(L, -1);
729 lua_pushboolean(L, 1);
730 lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = true */
731 /* set metatable */
732 luaV_getfield(L, LUAVIM_WINDOW);
733 lua_setmetatable(L, -2);
734 return w;
735}
736
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200737 static luaV_Window *
738luaV_pushwindow(lua_State *L, win_T *win)
739{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200740 luaV_Window *w = NULL;
741 if (win == NULL)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200742 lua_pushnil(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200743 else {
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200744 lua_pushlightuserdata(L, (void *) win);
745 lua_rawget(L, LUA_ENVIRONINDEX);
746 if (lua_isnil(L, -1)) /* not interned? */
747 {
748 lua_pop(L, 1);
749 w = luaV_newwindow(L, win);
750 }
751 else w = (luaV_Window *) lua_touserdata(L, -1);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200752 }
753 return w;
754}
755
756/* Window metamethods */
757
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200758 static int
759luaV_window_tostring(lua_State *L)
760{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200761 lua_pushfstring(L, "%s: %p", LUAVIM_WINDOW, lua_touserdata(L, 1));
762 return 1;
763}
764
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200765 static int
766luaV_window_call(lua_State *L)
767{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200768 luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
769 lua_settop(L, 1);
770 win_goto(*w);
771 return 1;
772}
773
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200774 static int
775luaV_window_index(lua_State *L)
776{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200777 luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
778 const char *s = luaL_checkstring(L, 2);
779 if (strncmp(s, "buffer", 6) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200780 luaV_pushbuffer(L, (*w)->w_buffer);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200781 else if (strncmp(s, "line", 4) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200782 lua_pushinteger(L, (*w)->w_cursor.lnum);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200783 else if (strncmp(s, "col", 3) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200784 lua_pushinteger(L, (*w)->w_cursor.col + 1);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200785#ifdef FEAT_VERTSPLIT
786 else if (strncmp(s, "width", 5) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200787 lua_pushinteger(L, W_WIDTH((*w)));
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200788#endif
789 else if (strncmp(s, "height", 6) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200790 lua_pushinteger(L, (*w)->w_height);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200791 /* methods */
792 else if (strncmp(s, "next", 4) == 0
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200793 || strncmp(s, "previous", 8) == 0
794 || strncmp(s, "isvalid", 7) == 0)
795 {
796 lua_getmetatable(L, 1);
797 lua_getfield(L, -1, s);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200798 }
799 else
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200800 lua_pushnil(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200801 return 1;
802}
803
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200804 static int
805luaV_window_newindex (lua_State *L)
806{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200807 luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
808 const char *s = luaL_checkstring(L, 2);
809 int v = luaL_checkinteger(L, 3);
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200810 if (strncmp(s, "line", 4) == 0)
811 {
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200812#ifdef HAVE_SANDBOX
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200813 luaV_checksandbox(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200814#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200815 if (v < 1 || v > (*w)->w_buffer->b_ml.ml_line_count)
816 luaL_error(L, "line out of range");
817 (*w)->w_cursor.lnum = v;
818 update_screen(VALID);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200819 }
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200820 else if (strncmp(s, "col", 3) == 0)
821 {
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200822#ifdef HAVE_SANDBOX
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200823 luaV_checksandbox(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200824#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200825 (*w)->w_cursor.col = v - 1;
826 update_screen(VALID);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200827 }
828#ifdef FEAT_VERTSPLIT
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200829 else if (strncmp(s, "width", 5) == 0)
830 {
831 win_T *win = curwin;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200832#ifdef FEAT_GUI
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200833 need_mouse_correct = TRUE;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200834#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200835 curwin = *w;
836 win_setwidth(v);
837 curwin = win;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200838 }
839#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200840 else if (strncmp(s, "height", 6) == 0)
841 {
842 win_T *win = curwin;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200843#ifdef FEAT_GUI
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200844 need_mouse_correct = TRUE;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200845#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200846 curwin = *w;
847 win_setheight(v);
848 curwin = win;
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200849 }
850 else
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200851 luaL_error(L, "invalid window property: `%s'", s);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200852 return 0;
853}
854
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200855 static int
856luaV_window_next(lua_State *L)
857{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200858 luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
859 luaV_pushwindow(L, (*w)->w_next);
860 return 1;
861}
862
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200863 static int
864luaV_window_previous(lua_State *L)
865{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200866 luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
867 luaV_pushwindow(L, (*w)->w_prev);
868 return 1;
869}
870
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200871 static int
872luaV_window_isvalid(lua_State *L)
873{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200874 luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
875 lua_pushlightuserdata(L, (void *) (*w));
876 lua_rawget(L, LUA_ENVIRONINDEX);
877 lua_pushboolean(L, !lua_isnil(L, -1));
878 return 1;
879}
880
881static const luaL_Reg luaV_Window_mt[] = {
882 {"__tostring", luaV_window_tostring},
883 {"__call", luaV_window_call},
884 {"__index", luaV_window_index},
885 {"__newindex", luaV_window_newindex},
886 {"next", luaV_window_next},
887 {"previous", luaV_window_previous},
888 {"isvalid", luaV_window_isvalid},
889 {NULL, NULL}
890};
891
892
893/* ======= Vim module ======= */
894
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200895 static int
896luaV_print(lua_State *L)
897{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200898 int i, n = lua_gettop(L); /* nargs */
899 const char *s;
900 size_t l;
901 luaL_Buffer b;
902 luaL_buffinit(L, &b);
903 lua_getglobal(L, "tostring");
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200904 for (i = 1; i <= n; i++)
905 {
906 lua_pushvalue(L, -1); /* tostring */
907 lua_pushvalue(L, i); /* arg */
908 lua_call(L, 1, 1);
909 s = lua_tolstring(L, -1, &l);
910 if (s == NULL)
911 return luaL_error(L, "cannot convert to string");
912 if (i > 1) luaL_addchar(&b, ' '); /* use space instead of tab */
913 luaV_addlstring(&b, s, l, 0);
914 lua_pop(L, 1);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200915 }
916 luaL_pushresult(&b);
917 luaV_msg(L);
918 return 0;
919}
920
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200921 static int
922luaV_command(lua_State *L)
923{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200924 do_cmdline_cmd((char_u *) luaL_checkstring(L, 1));
925 update_screen(VALID);
926 return 0;
927}
928
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200929 static int
930luaV_eval(lua_State *L)
931{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200932 typval_T *tv = eval_expr((char_u *) luaL_checkstring(L, 1), NULL);
933 if (tv == NULL) luaL_error(L, "invalid expression");
934 luaV_pushtypval(L, tv);
935 return 1;
936}
937
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200938 static int
Bram Moolenaar0d2e4fc2010-07-18 12:35:47 +0200939luaV_beep(lua_State *L UNUSED)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200940{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200941 vim_beep();
942 return 0;
943}
944
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200945 static int
946luaV_line(lua_State *L)
947{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200948 luaV_pushline(L, curbuf, curwin->w_cursor.lnum);
949 return 1;
950}
951
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200952 static int
953luaV_buffer(lua_State *L)
954{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200955 buf_T *buf;
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200956 if (lua_isstring(L, 1)) /* get by number or name? */
957 {
958 if (lua_isnumber(L, 1)) /* by number? */
959 {
960 int n = lua_tointeger(L, 1);
961 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
962 if (buf->b_fnum == n) break;
963 }
964 else { /* by name */
965 size_t l;
966 const char *s = lua_tolstring(L, 1, &l);
967 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
968 {
969 if (buf->b_ffname == NULL || buf->b_sfname == NULL)
970 {
971 if (l == 0) break;
972 }
Bram Moolenaar0d2e4fc2010-07-18 12:35:47 +0200973 else if (strncmp(s, (char *)buf->b_ffname, l) == 0
974 || strncmp(s, (char *)buf->b_sfname, l) == 0)
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200975 break;
976 }
977 }
978 if (buf == NULL) /* not found? */
979 lua_pushnil(L);
980 else
981 luaV_pushbuffer(L, buf);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200982 }
983 else {
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200984 buf = (lua_toboolean(L, 1)) ? firstbuf : curbuf; /* first buffer? */
985 luaV_pushbuffer(L, buf);
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200986 }
987 return 1;
988}
989
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200990 static int
991luaV_window(lua_State *L)
992{
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200993 win_T *win;
Bram Moolenaar55d5c032010-07-17 23:52:29 +0200994 if (lua_isnumber(L, 1)) /* get by number? */
995 {
996 int n = lua_tointeger(L, 1);
997 for (win = firstwin; win != NULL; win = win->w_next, n--)
998 if (n == 1) break;
999 if (win == NULL) /* not found? */
1000 lua_pushnil(L);
1001 else
1002 luaV_pushwindow(L, win);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001003 }
1004 else {
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001005 win = (lua_toboolean(L, 1)) ? firstwin : curwin; /* first window? */
1006 luaV_pushwindow(L, win);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001007 }
1008 return 1;
1009}
1010
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001011 static int
1012luaV_open(lua_State *L)
1013{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001014 luaV_Buffer *b;
1015 char_u *s = NULL;
1016#ifdef HAVE_SANDBOX
1017 luaV_checksandbox(L);
1018#endif
1019 if (lua_isstring(L, 1)) s = (char_u *) lua_tostring(L, 1);
1020 b = luaV_pushbuffer(L, buflist_new(s, NULL, 1L, BLN_LISTED));
1021 return 1;
1022}
1023
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001024 static int
1025luaV_isbuffer(lua_State *L)
1026{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001027 lua_pushboolean(L, luaV_toudata(L, 1, LUAVIM_BUFFER) != NULL);
1028 return 1;
1029}
1030
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001031 static int
1032luaV_iswindow(lua_State *L)
1033{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001034 lua_pushboolean(L, luaV_toudata(L, 1, LUAVIM_WINDOW) != NULL);
1035 return 1;
1036}
1037
1038/* for freeing buffer and window objects; lightuserdata as arg */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001039 static int
1040luaV_free(lua_State *L)
1041{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001042 lua_pushvalue(L, 1); /* lightudata */
1043 lua_rawget(L, LUA_ENVIRONINDEX);
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001044 if (!lua_isnil(L, -1))
1045 {
1046 lua_pushnil(L);
1047 lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = nil */
1048 lua_pushnil(L);
1049 lua_rawset(L, LUA_ENVIRONINDEX); /* env[lightudata] = nil */
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001050 }
1051 return 0;
1052}
1053
1054static const luaL_Reg luaV_module[] = {
1055 {"command", luaV_command},
1056 {"eval", luaV_eval},
1057 {"beep", luaV_beep},
1058 {"line", luaV_line},
1059 {"buffer", luaV_buffer},
1060 {"window", luaV_window},
1061 {"open", luaV_open},
1062 {"isbuffer", luaV_isbuffer},
1063 {"iswindow", luaV_iswindow},
1064 {NULL, NULL}
1065};
1066
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001067 static int
1068luaopen_vim(lua_State *L)
1069{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001070 /* set environment */
1071 lua_newtable(L);
1072 lua_newtable(L);
1073 lua_pushliteral(L, "v");
1074 lua_setfield(L, -2, "__mode");
1075 lua_setmetatable(L, -2);
1076 lua_replace(L, LUA_ENVIRONINDEX);
1077 /* print */
1078 lua_pushcfunction(L, luaV_print);
1079 lua_setglobal(L, "print");
1080 /* free */
1081 lua_pushlightuserdata(L, (void *) LUAVIM_FREE);
1082 lua_pushcfunction(L, luaV_free);
1083 lua_rawset(L, LUA_REGISTRYINDEX);
1084 /* register */
1085 luaV_newmetatable(L, LUAVIM_BUFFER);
1086 luaL_register(L, NULL, luaV_Buffer_mt);
1087 luaV_newmetatable(L, LUAVIM_WINDOW);
1088 luaL_register(L, NULL, luaV_Window_mt);
1089 luaL_register(L, LUAVIM_NAME, luaV_module);
1090 return 0;
1091}
1092
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001093 static lua_State *
1094luaV_newstate(void)
1095{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001096 lua_State *L = luaL_newstate();
1097 const luaL_Reg luaV_core_libs[] = {
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001098 {"", luaopen_base},
1099 {LUA_TABLIBNAME, luaopen_table},
1100 {LUA_STRLIBNAME, luaopen_string},
1101 {LUA_MATHLIBNAME, luaopen_math},
1102 {LUA_OSLIBNAME, luaopen_os}, /* restricted */
1103 {LUA_LOADLIBNAME, luaopen_package},
1104 {LUA_DBLIBNAME, luaopen_debug},
1105 {NULL, NULL}
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001106 };
1107 const char *os_funcs[] = {
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001108 "date", "clock", "time", "difftime", "getenv", NULL
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001109 };
1110 const luaL_Reg *reg = luaV_core_libs;
1111 const char **s = os_funcs;
1112 /* core libs */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001113 for ( ; reg->func; reg++)
1114 {
1115 lua_pushcfunction(L, reg->func);
1116 lua_pushstring(L, reg->name);
1117 lua_call(L, 1, 0);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001118 }
1119 /* restricted os lib */
1120 lua_getglobal(L, LUA_OSLIBNAME);
1121 lua_newtable(L);
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001122 for ( ; *s; s++)
1123 {
1124 lua_getfield(L, -2, *s);
1125 lua_setfield(L, -2, *s);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001126 }
1127 lua_setglobal(L, LUA_OSLIBNAME);
1128 lua_pop(L, 1); /* os table */
1129 /* vim */
1130 lua_pushcfunction(L, luaopen_vim);
1131 lua_call(L, 0, 0);
1132 return L;
1133}
1134
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001135 static void
1136luaV_setrange(lua_State *L, int line1, int line2)
1137{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001138 lua_getglobal(L, LUAVIM_NAME);
1139 lua_pushinteger(L, line1);
1140 lua_setfield(L, -2, "firstline");
1141 lua_pushinteger(L, line2);
1142 lua_setfield(L, -2, "lastline");
1143 lua_pop(L, 1); /* vim table */
1144}
1145
1146
1147/* ======= Interface ======= */
1148
1149static lua_State *L = NULL;
1150
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001151 static int
1152lua_init(void)
1153{
1154 if (L == NULL)
1155 {
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001156#ifdef DYNAMIC_LUA
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001157 if (!lua_enabled(TRUE))
1158 {
1159 EMSG(_("Lua library cannot be loaded."));
1160 return FAIL;
1161 }
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001162#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001163 L = luaV_newstate();
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001164 }
1165 return OK;
1166}
1167
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001168 void
1169lua_end(void)
1170{
1171 if (L != NULL)
1172 {
1173 lua_close(L);
1174 L = NULL;
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001175#ifdef DYNAMIC_LUA
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001176 end_dynamic_lua();
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001177#endif
1178 }
1179}
1180
1181/* ex commands */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001182 void
1183ex_lua(exarg_T *eap)
1184{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001185 char *script;
1186 if (lua_init() == FAIL) return;
1187 script = (char *) script_get(eap, eap->arg);
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001188 if (!eap->skip)
1189 {
1190 char *s = (script) ? script : (char *) eap->arg;
1191 luaV_setrange(L, eap->line1, eap->line2);
1192 if (luaL_loadbuffer(L, s, strlen(s), LUAVIM_CHUNKNAME)
1193 || lua_pcall(L, 0, 0, 0))
1194 luaV_emsg(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001195 }
1196 if (script != NULL) vim_free(script);
1197}
1198
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001199 void
1200ex_luado(exarg_T *eap)
1201{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001202 linenr_T l;
1203 const char *s = (const char *) eap->arg;
1204 luaL_Buffer b;
1205 size_t len;
1206 if (lua_init() == FAIL) return;
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001207 if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL)
1208 {
1209 EMSG(_("cannot save undo information"));
1210 return;
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001211 }
1212 luaV_setrange(L, eap->line1, eap->line2);
1213 luaL_buffinit(L, &b);
1214 luaL_addlstring(&b, "return function(line) ", 22); /* header */
1215 luaL_addlstring(&b, s, strlen(s));
1216 luaL_addlstring(&b, " end", 4); /* footer */
1217 luaL_pushresult(&b);
1218 s = lua_tolstring(L, -1, &len);
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001219 if (luaL_loadbuffer(L, s, len, LUAVIM_CHUNKNAME))
1220 {
1221 luaV_emsg(L);
1222 lua_pop(L, 1); /* function body */
1223 return;
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001224 }
1225 lua_call(L, 0, 1);
1226 lua_replace(L, -2); /* function -> body */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001227 for (l = eap->line1; l <= eap->line2; l++)
1228 {
1229 lua_pushvalue(L, -1); /* function */
1230 luaV_pushline(L, curbuf, l); /* current line as arg */
1231 if (lua_pcall(L, 1, 1, 0))
1232 {
1233 luaV_emsg(L);
1234 break;
1235 }
1236 if (lua_isstring(L, -1)) /* update line? */
1237 {
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001238#ifdef HAVE_SANDBOX
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001239 luaV_checksandbox(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001240#endif
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001241 ml_replace(l, luaV_toline(L, -1), TRUE);
1242 changed_bytes(l, 0);
1243 lua_pop(L, 1); /* result from luaV_toline */
1244 }
1245 lua_pop(L, 1); /* line */
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001246 }
1247 lua_pop(L, 1); /* function */
1248 check_cursor();
1249 update_screen(NOT_VALID);
1250}
1251
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001252 void
1253ex_luafile(exarg_T *eap)
1254{
1255 if (lua_init() == FAIL)
1256 return;
1257 if (!eap->skip)
1258 {
1259 luaV_setrange(L, eap->line1, eap->line2);
1260 if (luaL_loadfile(L, (char *) eap->arg) || lua_pcall(L, 0, 0, 0))
1261 luaV_emsg(L);
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001262 }
1263}
1264
1265/* buffer */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001266 void
1267lua_buffer_free(buf_T *buf)
1268{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001269 if (lua_init() == FAIL) return;
1270 luaV_getfield(L, LUAVIM_FREE);
1271 lua_pushlightuserdata(L, (void *) buf);
1272 lua_call(L, 1, 0);
1273}
1274
1275/* window */
Bram Moolenaar55d5c032010-07-17 23:52:29 +02001276 void
1277lua_window_free(win_T *win)
1278{
Bram Moolenaar0ba04292010-07-14 23:23:17 +02001279 if (lua_init() == FAIL) return;
1280 luaV_getfield(L, LUAVIM_FREE);
1281 lua_pushlightuserdata(L, (void *) win);
1282 lua_call(L, 1, 0);
1283}
1284
1285#endif