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