vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

vis-lua.c

(101943B)


      1 /***
      2  * Lua Extension API for the [Vis Editor](https://github.com/martanne/vis).
      3  *
      4  * *WARNING:* there is no stability guarantee at this time, the API might
      5  * change without notice!
      6  *
      7  * This document might be out of date, run `make luadoc` to regenerate it.
      8  *
      9  * @module vis
     10  * @author Marc André Tanner
     11  * @license ISC
     12  * @release RELEASE
     13  */
     14 #include <stddef.h>
     15 #include <stdarg.h>
     16 #include <stdio.h>
     17 #include <string.h>
     18 #include <limits.h>
     19 #include <unistd.h>
     20 #include <libgen.h>
     21 #include <sys/types.h>
     22 #include <pwd.h>
     23 
     24 #include "vis-lua.h"
     25 #include "vis-core.h"
     26 #include "text-motions.h"
     27 #include "util.h"
     28 
     29 #ifndef VIS_PATH
     30 #define VIS_PATH "/usr/local/share/vis"
     31 #endif
     32 
     33 #define VIS_LUA_TYPE_VIS "vis"
     34 #define VIS_LUA_TYPE_WIN_OPTS "winoptions"
     35 #define VIS_LUA_TYPE_VIS_OPTS "visoptions"
     36 #define VIS_LUA_TYPE_FILE "file"
     37 #define VIS_LUA_TYPE_TEXT "text"
     38 #define VIS_LUA_TYPE_MARK "mark"
     39 #define VIS_LUA_TYPE_MARKS "marks"
     40 #define VIS_LUA_TYPE_WINDOW "window"
     41 #define VIS_LUA_TYPE_SELECTION "selection"
     42 #define VIS_LUA_TYPE_SELECTIONS "selections"
     43 #define VIS_LUA_TYPE_UI "ui"
     44 #define VIS_LUA_TYPE_REGISTERS "registers"
     45 #define VIS_LUA_TYPE_KEYACTION "keyaction"
     46 
     47 #ifndef DEBUG_LUA
     48 #define DEBUG_LUA 0
     49 #endif
     50 
     51 #if DEBUG_LUA
     52 #define debug(...) do { printf(__VA_ARGS__); fflush(stdout); } while (0)
     53 #else
     54 #define debug(...) do { } while (0)
     55 #endif
     56 
     57 
     58 #if !CONFIG_LUA
     59 
     60 bool vis_lua_path_add(Vis *vis, const char *path) { return true; }
     61 bool vis_lua_paths_get(Vis *vis, char **lpath, char **cpath) { return false; }
     62 void vis_lua_process_response(Vis *vis, const char *name,
     63                               char *buffer, size_t len, ResponseType rtype) { }
     64 
     65 #else
     66 
     67 #if DEBUG_LUA
     68 static void stack_dump_entry(lua_State *L, int i) {
     69 	int t = lua_type(L, i);
     70 	switch (t) {
     71 	case LUA_TNIL:
     72 		printf("nil");
     73 		break;
     74 	case LUA_TBOOLEAN:
     75 		printf(lua_toboolean(L, i) ? "true" : "false");
     76 		break;
     77 	case LUA_TLIGHTUSERDATA:
     78 		printf("lightuserdata(%p)", lua_touserdata(L, i));
     79 		break;
     80 	case LUA_TNUMBER:
     81 		printf("%g", lua_tonumber(L, i));
     82 		break;
     83 	case LUA_TSTRING:
     84 		printf("`%s'", lua_tostring(L, i));
     85 		break;
     86 	case LUA_TTABLE:
     87 		printf("table[");
     88 		lua_pushnil(L); /* first key */
     89 		while (lua_next(L, i > 0 ? i : i - 1)) {
     90 			stack_dump_entry(L, -2);
     91 			printf("=");
     92 			stack_dump_entry(L, -1);
     93 			printf(",");
     94 			lua_pop(L, 1); /* remove value, keep key */
     95 		}
     96 		printf("]");
     97 		break;
     98 	case LUA_TUSERDATA:
     99 		printf("userdata(%p)", lua_touserdata(L, i));
    100 		break;
    101 	default:  /* other values */
    102 		printf("%s", lua_typename(L, t));
    103 		break;
    104 	}
    105 }
    106 
    107 static void stack_dump(lua_State *L, const char *format, ...) {
    108 	va_list ap;
    109 	va_start(ap, format);
    110 	vprintf(format, ap);
    111 	va_end(ap);
    112 	int top = lua_gettop(L);
    113 	for (int i = 1; i <= top; i++) {
    114 		printf("%d: ", i);
    115 		stack_dump_entry(L, i);
    116 		printf("\n");
    117 	}
    118 	printf("\n\n");
    119 	fflush(stdout);
    120 }
    121 
    122 #endif
    123 
    124 static int panic_handler(lua_State *L) {
    125 	void *ud = NULL;
    126 	lua_getallocf(L, &ud);
    127 	if (ud) {
    128 		Vis *vis = ud;
    129 		vis->lua = NULL;
    130 		const char *msg = NULL;
    131 		if (lua_type(L, -1) == LUA_TSTRING)
    132 			msg = lua_tostring(L, -1);
    133 		vis_info_show(vis, "Fatal Lua error: %s", msg ? msg : "unknown reason");
    134 		lua_close(L);
    135 		if (vis->running)
    136 			siglongjmp(vis->sigbus_jmpbuf, 1);
    137 	}
    138 	return 0;
    139 }
    140 
    141 static int error_handler(lua_State *L) {
    142 	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
    143 	if (vis->errorhandler)
    144 		return 1;
    145 	vis->errorhandler = true;
    146 	size_t len;
    147 	const char *msg = lua_tostring(L, 1);
    148 	if (msg)
    149 		luaL_traceback(L, L, msg, 1);
    150 	msg = lua_tolstring(L, 1, &len);
    151 	vis_message_show(vis, msg);
    152 	vis->errorhandler = false;
    153 	return 1;
    154 }
    155 
    156 static int pcall(Vis *vis, lua_State *L, int nargs, int nresults) {
    157 	/* insert a custom error function below all arguments */
    158 	int msgh = lua_gettop(L) - nargs;
    159 	lua_pushlightuserdata(L, vis);
    160 	lua_pushcclosure(L, error_handler, 1);
    161 	lua_insert(L, msgh);
    162 	int ret = lua_pcall(L, nargs, nresults, msgh);
    163 	lua_remove(L, msgh);
    164 	return ret;
    165 }
    166 
    167 /* expects a lua function at stack position `narg` and stores a
    168  * reference to it in the registry. The return value can be used
    169  * to look it up.
    170  *
    171  *   registry["vis.functions"][(void*)(function)] = function
    172  */
    173 static const void *func_ref_new(lua_State *L, int narg) {
    174 	const void *addr = lua_topointer(L, narg);
    175 	if (!lua_isfunction(L, narg) || !addr)
    176 		luaL_argerror(L, narg, "function expected");
    177 	lua_getfield(L, LUA_REGISTRYINDEX, "vis.functions");
    178 	lua_pushlightuserdata(L, (void*)addr);
    179 	lua_pushvalue(L, narg);
    180 	lua_settable(L, -3);
    181 	lua_pop(L, 1);
    182 	return addr;
    183 }
    184 
    185 /* retrieve function from registry and place it at the top of the stack */
    186 static bool func_ref_get(lua_State *L, const void *addr) {
    187 	if (!addr)
    188 		return false;
    189 	lua_getfield(L, LUA_REGISTRYINDEX, "vis.functions");
    190 	lua_pushlightuserdata(L, (void*)addr);
    191 	lua_gettable(L, -2);
    192 	lua_remove(L, -2);
    193 	if (!lua_isfunction(L, -1)) {
    194 		lua_pop(L, 1);
    195 		return false;
    196 	}
    197 	return true;
    198 }
    199 
    200 /* creates a new metatable for a given type and stores a mapping:
    201  *
    202  *   registry["vis.types"][metatable] = type
    203  *
    204  * leaves the metatable at the top of the stack.
    205  */
    206 static void obj_type_new(lua_State *L, const char *type) {
    207 	luaL_newmetatable(L, type);
    208 	lua_getglobal(L, "vis");
    209 	if (!lua_isnil(L, -1)) {
    210 		lua_getfield(L, -1, "types");
    211 		lua_pushvalue(L, -3);
    212 		lua_setfield(L, -2, type);
    213 		lua_pop(L, 1);
    214 	}
    215 	lua_pop(L, 1);
    216 	lua_getfield(L, LUA_REGISTRYINDEX, "vis.types");
    217 	lua_pushvalue(L, -2);
    218 	lua_pushstring(L, type);
    219 	lua_settable(L, -3);
    220 	lua_pop(L, 1);
    221 }
    222 
    223 /* get type of userdatum at the top of the stack:
    224  *
    225  *   return registry["vis.types"][getmetatable(userdata)]
    226  */
    227 const char *obj_type_get(lua_State *L) {
    228 	if (lua_isnil(L, -1))
    229 		return "nil";
    230 	lua_getfield(L, LUA_REGISTRYINDEX, "vis.types");
    231 	lua_getmetatable(L, -2);
    232 	lua_gettable(L, -2);
    233 	// XXX: in theory string might become invalid when popped from stack
    234 	const char *type = lua_tostring(L, -1);
    235 	lua_pop(L, 2);
    236 	return type;
    237 }
    238 
    239 static void *obj_new(lua_State *L, size_t size, const char *type) {
    240 	void *obj = lua_newuserdata(L, size);
    241 	luaL_getmetatable(L, type);
    242 	lua_setmetatable(L, -2);
    243 	lua_newtable(L);
    244 	lua_setuservalue(L, -2);
    245 	return obj;
    246 }
    247 
    248 /* returns registry["vis.objects"][addr] if it is of correct type */
    249 static void *obj_ref_get(lua_State *L, void *addr, const char *type) {
    250 	lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
    251 	lua_pushlightuserdata(L, addr);
    252 	lua_gettable(L, -2);
    253 	lua_remove(L, -2);
    254 	if (lua_isnil(L, -1)) {
    255 		debug("get: vis.objects[%p] = nil\n", addr);
    256 		lua_pop(L, 1);
    257 		return NULL;
    258 	}
    259 	if (DEBUG_LUA) {
    260 		const char *actual_type = obj_type_get(L);
    261 		if (strcmp(type, actual_type) != 0)
    262 			debug("get: vis.objects[%p] = %s (BUG: expected %s)\n", addr, actual_type, type);
    263 		void **handle = luaL_checkudata(L, -1, type);
    264 		if (!handle)
    265 			debug("get: vis.objects[%p] = %s (BUG: invalid handle)\n", addr, type);
    266 		else if (*handle != addr)
    267 			debug("get: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr, type, *handle);
    268 	}
    269 	/* verify that obj is correct type then unmodify the stack */
    270 	luaL_checkudata(L, -1, type);
    271 	lua_pop(L, 1);
    272 	return addr;
    273 }
    274 
    275 /* expects a userdatum at the top of the stack and sets
    276  *
    277  *   registry["vis.objects"][addr] = userdata
    278  */
    279 static void obj_ref_set(lua_State *L, void *addr) {
    280 	//debug("set: vis.objects[%p] = %s\n", addr, obj_type_get(L));
    281 	lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
    282 	lua_pushlightuserdata(L, addr);
    283 	lua_pushvalue(L, -3);
    284 	lua_settable(L, -3);
    285 	lua_pop(L, 1);
    286 }
    287 
    288 /* invalidates an object reference
    289  *
    290  *   registry["vis.objects"][addr] = nil
    291  */
    292 static void obj_ref_free(lua_State *L, void *addr) {
    293 	if (DEBUG_LUA) {
    294 		lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
    295 		lua_pushlightuserdata(L, addr);
    296 		lua_gettable(L, -2);
    297 		lua_remove(L, -2);
    298 		if (lua_isnil(L, -1))
    299 			debug("free-unused: %p\n", addr);
    300 		else
    301 			debug("free: vis.objects[%p] = %s\n", addr, obj_type_get(L));
    302 		lua_pop(L, 1);
    303 	}
    304 	lua_pushnil(L);
    305 	obj_ref_set(L, addr);
    306 }
    307 
    308 /* creates a new object reference of given type if it does not already exist in the registry:
    309  *
    310  *  if (registry["vis.types"][metatable(registry["vis.objects"][addr])] != type) {
    311  *      // XXX: should not happen
    312  *      registry["vis.objects"][addr] = new_obj(addr, type)
    313  *  }
    314  *  return registry["vis.objects"][addr];
    315  */
    316 static void *obj_ref_new(lua_State *L, void *addr, const char *type) {
    317 	if (!addr) {
    318 		lua_pushnil(L);
    319 		return NULL;
    320 	}
    321 	lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
    322 	lua_pushlightuserdata(L, addr);
    323 	lua_gettable(L, -2);
    324 	lua_remove(L, -2);
    325 	const char *old_type = obj_type_get(L);
    326 	if (strcmp(type, old_type) == 0) {
    327 		debug("new: vis.objects[%p] = %s (returning existing object)\n", addr, old_type);
    328 		void **handle = luaL_checkudata(L, -1, type);
    329 		if (!handle)
    330 			debug("new: vis.objects[%p] = %s (BUG: invalid handle)\n", addr, old_type);
    331 		else if (*handle != addr)
    332 			debug("new: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr, old_type, *handle);
    333 		return addr;
    334 	}
    335 	if (!lua_isnil(L, -1))
    336 		debug("new: vis.objects[%p] = %s (WARNING: changing object type from %s)\n", addr, type, old_type);
    337 	else
    338 		debug("new: vis.objects[%p] = %s (creating new object)\n", addr, type);
    339 	lua_pop(L, 1);
    340 	void **handle = obj_new(L, sizeof(addr), type);
    341 	obj_ref_set(L, addr);
    342 	*handle = addr;
    343 	return addr;
    344 }
    345 
    346 /* (type) check validity of object reference at stack location `idx' and retrieve it */
    347 static void *obj_ref_check(lua_State *L, int idx, const char *type) {
    348 	void **addr = luaL_checkudata(L, idx, type);
    349 	if (!obj_ref_get(L, *addr, type))
    350 		luaL_argerror(L, idx, "invalid object reference");
    351 	return *addr;
    352 }
    353 
    354 static void *obj_ref_check_containerof(lua_State *L, int idx, const char *type, size_t offset) {
    355 	void *obj = obj_ref_check(L, idx, type);
    356 	return obj ? ((char*)obj-offset) : obj;
    357 }
    358 
    359 static void *obj_lightref_new(lua_State *L, void *addr, const char *type) {
    360 	if (!addr)
    361 		return NULL;
    362 	void **handle = obj_new(L, sizeof(addr), type);
    363 	*handle = addr;
    364 	return addr;
    365 }
    366 
    367 static void *obj_lightref_check(lua_State *L, int idx, const char *type) {
    368 	void **addr = luaL_checkudata(L, idx, type);
    369 	return *addr;
    370 }
    371 
    372 static int index_common(lua_State *L) {
    373 	lua_getmetatable(L, 1);
    374 	lua_pushvalue(L, 2);
    375 	lua_gettable(L, -2);
    376 	if (lua_isnil(L, -1)) {
    377 		lua_getuservalue(L, 1);
    378 		lua_pushvalue(L, 2);
    379 		lua_gettable(L, -2);
    380 	}
    381 	return 1;
    382 }
    383 
    384 static int newindex_common(lua_State *L) {
    385 	lua_getuservalue(L, 1);
    386 	lua_pushvalue(L, 2);
    387 	lua_pushvalue(L, 3);
    388 	lua_settable(L, -3);
    389 	return 0;
    390 }
    391 
    392 static size_t getpos(lua_State *L, int narg) {
    393 	return lua_tounsigned(L, narg);
    394 }
    395 
    396 static size_t checkpos(lua_State *L, int narg) {
    397 	lua_Number n = luaL_checknumber(L, narg);
    398 	/* on most systems SIZE_MAX can't be represented in lua_Number.
    399 	 * using < avoids undefined behaviour when n == SIZE_MAX+1
    400 	 * which can be represented in lua_Number
    401 	 */
    402 	if (n >= 0 && n < (lua_Number)SIZE_MAX && n == (size_t)n)
    403 		return n;
    404 	return luaL_argerror(L, narg, "expected position, got number");
    405 }
    406 
    407 static void pushpos(lua_State *L, size_t pos) {
    408 	if (pos == EPOS)
    409 		lua_pushnil(L);
    410 	else
    411 		lua_pushunsigned(L, pos);
    412 }
    413 
    414 static void pushrange(lua_State *L, Filerange *r) {
    415 	if (!r || !text_range_valid(r)) {
    416 		lua_pushnil(L);
    417 		return;
    418 	}
    419 	lua_createtable(L, 0, 2);
    420 	lua_pushstring(L, "start");
    421 	lua_pushunsigned(L, r->start);
    422 	lua_settable(L, -3);
    423 	lua_pushstring(L, "finish");
    424 	lua_pushunsigned(L, r->end);
    425 	lua_settable(L, -3);
    426 }
    427 
    428 static Filerange getrange(lua_State *L, int index) {
    429 	Filerange range = text_range_empty();
    430 	if (lua_istable(L, index)) {
    431 		lua_getfield(L, index, "start");
    432 		range.start = checkpos(L, -1);
    433 		lua_pop(L, 1);
    434 		lua_getfield(L, index, "finish");
    435 		range.end = checkpos(L, -1);
    436 		lua_pop(L, 1);
    437 	} else {
    438 		range.start = checkpos(L, index);
    439 		range.end = range.start + checkpos(L, index+1);
    440 	}
    441 	return range;
    442 }
    443 
    444 static const char *keymapping(Vis *vis, const char *keys, const Arg *arg) {
    445 	lua_State *L = vis->lua;
    446 	if (!func_ref_get(L, arg->v))
    447 		return keys;
    448 	lua_pushstring(L, keys);
    449 	if (pcall(vis, L, 1, 1) != 0)
    450 		return keys;
    451 	if (lua_type(L, -1) != LUA_TNUMBER)
    452 		return keys; /* invalid or no return value, assume zero */
    453 	lua_Number number = lua_tonumber(L, -1);
    454 	lua_Integer integer = lua_tointeger(L, -1);
    455 	if (number != integer)
    456 		return keys;
    457 	if (integer < 0)
    458 		return NULL; /* need more input */
    459 	size_t len = integer;
    460 	size_t max = strlen(keys);
    461 	return (len <= max) ? keys+len : keys;
    462 }
    463 
    464 /***
    465  * The main editor object.
    466  * @type Vis
    467  */
    468 
    469 /***
    470  * Version information.
    471  * @tfield string VERSION
    472  * version information in `git describe` format, same as reported by `vis -v`.
    473  */
    474 /***
    475  * Lua API object types
    476  * @field types meta tables of userdata objects used for type checking
    477  * @local
    478  */
    479 /***
    480  * User interface.
    481  * @tfield Ui ui the user interface being used
    482  */
    483 /***
    484  * Mode constants.
    485  * @tfield modes modes
    486  */
    487 /***
    488  * Events.
    489  * @tfield events events
    490  */
    491 /***
    492  * Registers.
    493  * @field registers array to access the register by single letter name
    494  */
    495 /***
    496  * Scintillua lexer module.
    497  * @field lexers might be `nil` if module is not found
    498  */
    499 /***
    500  * LPeg lexer module.
    501  * @field lpeg might be `nil` if module is not found
    502  */
    503 /***
    504  * Current count.
    505  * @tfield int count the specified count for the current command or `nil` if none was given
    506  */
    507 
    508 /***
    509  * Create an iterator over all windows.
    510  * @function windows
    511  * @return the new iterator
    512  * @see win
    513  * @usage
    514  * for win in vis:windows() do
    515  * 	-- do something with win
    516  * end
    517  */
    518 static int windows_iter(lua_State *L);
    519 static int windows(lua_State *L) {
    520 	Vis *vis = obj_ref_check(L, 1, "vis");
    521 	Win **handle = lua_newuserdata(L, sizeof *handle), *next;
    522 	for (next = vis->windows; next && next->file->internal; next = next->next);
    523 	*handle = next;
    524 	lua_pushcclosure(L, windows_iter, 1);
    525 	return 1;
    526 }
    527 
    528 static int windows_iter(lua_State *L) {
    529 	Win **handle = lua_touserdata(L, lua_upvalueindex(1));
    530 	if (!*handle)
    531 		return 0;
    532 	Win *win = obj_ref_new(L, *handle, VIS_LUA_TYPE_WINDOW), *next;
    533 	if (win) {
    534 		for (next = win->next; next && next->file->internal; next = next->next);
    535 		*handle = next;
    536 	}
    537 	return 1;
    538 }
    539 
    540 /***
    541  * Create an iterator over all files.
    542  * @function files
    543  * @return the new iterator
    544  * @usage
    545  * for file in vis:files() do
    546  * 	-- do something with file
    547  * end
    548  */
    549 static int files_iter(lua_State *L);
    550 static int files(lua_State *L) {
    551 	Vis *vis = obj_ref_check(L, 1, "vis");
    552 	File **handle = lua_newuserdata(L, sizeof *handle);
    553 	*handle = vis->files;
    554 	lua_pushcclosure(L, files_iter, 1);
    555 	return 1;
    556 }
    557 
    558 static int files_iter(lua_State *L) {
    559 	File **handle = lua_touserdata(L, lua_upvalueindex(1));
    560 	if (!*handle)
    561 		return 0;
    562 	File *file = obj_ref_new(L, *handle, VIS_LUA_TYPE_FILE);
    563 	if (file)
    564 		*handle = file->next;
    565 	return 1;
    566 }
    567 
    568 /***
    569  * Create an iterator over all mark names.
    570  * @function mark_names
    571  * @return the new iterator
    572  * @usage
    573  * local marks = vis.win.marks
    574  * for name in vis:mark_names() do
    575  * 	local mark = marks[name]
    576  * 	for i = 1, #mark do
    577  * 		-- do something with: name, mark[i].start, mark[i].finish
    578  * 	end
    579  * end
    580  */
    581 static int mark_names_iter(lua_State *L);
    582 static int mark_names(lua_State *L) {
    583 	Vis *vis = obj_ref_check(L, 1, "vis");
    584 	lua_pushlightuserdata(L, vis);
    585 	enum VisMark *handle = lua_newuserdata(L, sizeof *handle);
    586 	*handle = 0;
    587 	lua_pushcclosure(L, mark_names_iter, 2);
    588 	return 1;
    589 }
    590 
    591 static int mark_names_iter(lua_State *L) {
    592 	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
    593 	enum VisMark *handle = lua_touserdata(L, lua_upvalueindex(2));
    594 	char mark = vis_mark_to(vis, *handle);
    595 	if (mark) {
    596 		lua_pushlstring(L, &mark, 1);
    597 		(*handle)++;
    598 		return 1;
    599 	}
    600 	return 0;
    601 }
    602 
    603 /***
    604  * Create an iterator over all register names.
    605  * @function register_names
    606  * @return the new iterator
    607  * @usage
    608  * for name in vis:register_names() do
    609  * 	local reg = vis.registers[name]
    610  * 	for i = 1, #reg do
    611  * 		-- do something with register value reg[i]
    612  * 	end
    613  * end
    614  */
    615 static int register_names_iter(lua_State *L);
    616 static int register_names(lua_State *L) {
    617 	Vis *vis = obj_ref_check(L, 1, "vis");
    618 	lua_pushlightuserdata(L, vis);
    619 	enum VisRegister *handle = lua_newuserdata(L, sizeof *handle);
    620 	*handle = 0;
    621 	lua_pushcclosure(L, register_names_iter, 2);
    622 	return 1;
    623 }
    624 
    625 static int register_names_iter(lua_State *L) {
    626 	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
    627 	enum VisRegister *handle = lua_touserdata(L, lua_upvalueindex(2));
    628 	char reg = vis_register_to(vis, *handle);
    629 	if (reg) {
    630 		lua_pushlstring(L, &reg, 1);
    631 		(*handle)++;
    632 		return 1;
    633 	}
    634 	return 0;
    635 }
    636 
    637 /***
    638  * Execute a `:`-command.
    639  * @function command
    640  * @tparam string command the command to execute
    641  * @treturn bool whether the command succeeded
    642  * @usage
    643  * vis:command("set number")
    644  */
    645 static int command(lua_State *L) {
    646 	Vis *vis = obj_ref_check(L, 1, "vis");
    647 	const char *cmd = luaL_checkstring(L, 2);
    648 	bool ret = vis_cmd(vis, cmd);
    649 	lua_pushboolean(L, ret);
    650 	return 1;
    651 }
    652 
    653 /***
    654  * Display a short message.
    655  *
    656  * The single line message will be displayed at the bottom of
    657  * the screen and automatically hidden once a key is pressed.
    658  *
    659  * @function info
    660  * @tparam string message the message to display
    661  */
    662 static int info(lua_State *L) {
    663 	Vis *vis = obj_ref_check(L, 1, "vis");
    664 	const char *msg = luaL_checkstring(L, 2);
    665 	vis_info_show(vis, "%s", msg);
    666 	return 0;
    667 }
    668 
    669 /***
    670  * Display a multi line message.
    671  *
    672  * Opens a new window and displays an arbitrarily long message.
    673  *
    674  * @function message
    675  * @tparam string message the message to display
    676  */
    677 static int message(lua_State *L) {
    678 	Vis *vis = obj_ref_check(L, 1, "vis");
    679 	const char *msg = luaL_checkstring(L, 2);
    680 	vis_message_show(vis, msg);
    681 	return 0;
    682 }
    683 
    684 /***
    685  * Register a Lua function as key action.
    686  * @function action_register
    687  * @tparam string name the name of the action, can be referred to in key bindings as `<name>` pseudo key
    688  * @tparam Function func the lua function implementing the key action (see @{keyhandler})
    689  * @tparam[opt] string help the single line help text as displayed in `:help`
    690  * @treturn KeyAction action the registered key action
    691  * @see Vis:map
    692  * @see Window:map
    693  */
    694 static int action_register(lua_State *L) {
    695 	Vis *vis = obj_ref_check(L, 1, "vis");
    696 	const char *name = luaL_checkstring(L, 2);
    697 	const void *func = func_ref_new(L, 3);
    698 	const char *help = luaL_optstring(L, 4, NULL);
    699 	KeyAction *action = vis_action_new(vis, name, help, keymapping, (Arg){ .v = func });
    700 	if (!action)
    701 		goto err;
    702 	if (!vis_action_register(vis, action))
    703 		goto err;
    704 	obj_ref_new(L, action, VIS_LUA_TYPE_KEYACTION);
    705 	return 1;
    706 err:
    707 	vis_action_free(vis, action);
    708 	lua_pushnil(L);
    709 	return 1;
    710 }
    711 
    712 static int keymap(lua_State *L, Vis *vis, Win *win) {
    713 	int mode = luaL_checkint(L, 2);
    714 	const char *key = luaL_checkstring(L, 3);
    715 	const char *help = luaL_optstring(L, 5, NULL);
    716 	KeyBinding *binding = vis_binding_new(vis);
    717 	if (!binding)
    718 		goto err;
    719 	if (lua_isstring(L, 4)) {
    720 		const char *alias = luaL_checkstring(L, 4);
    721 		if (!(binding->alias = strdup(alias)))
    722 			goto err;
    723 	} else if (lua_isfunction(L, 4)) {
    724 		const void *func = func_ref_new(L, 4);
    725 		if (!(binding->action = vis_action_new(vis, NULL, help, keymapping, (Arg){ .v = func })))
    726 			goto err;
    727 	} else if (lua_isuserdata(L, 4)) {
    728 		binding->action = obj_ref_check(L, 4, VIS_LUA_TYPE_KEYACTION);
    729 	} else {
    730 		goto err;
    731 	}
    732 
    733 	if (win) {
    734 		if (!vis_window_mode_map(win, mode, true, key, binding))
    735 			goto err;
    736 	} else {
    737 		if (!vis_mode_map(vis, mode, true, key, binding))
    738 			goto err;
    739 	}
    740 
    741 	lua_pushboolean(L, true);
    742 	return 1;
    743 err:
    744 	vis_binding_free(vis, binding);
    745 	lua_pushboolean(L, false);
    746 	return 1;
    747 }
    748 
    749 /***
    750  * Map a key to a Lua function.
    751  *
    752  * Creates a new key mapping in a given mode.
    753  *
    754  * @function map
    755  * @tparam int mode the mode to which the mapping should be added
    756  * @tparam string key the key to map
    757  * @tparam function func the Lua function to handle the key mapping (see @{keyhandler})
    758  * @tparam[opt] string help the single line help text as displayed in `:help`
    759  * @treturn bool whether the mapping was successfully established
    760  * @see Window:map
    761  * @usage
    762  * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
    763  * 	if #keys < 2 then
    764  * 		return -1 -- need more input
    765  * 	end
    766  * 	local digraph = keys:sub(1, 2)
    767  * 	if digraph == "l*" then
    768  * 		vis:feedkeys('λ')
    769  * 		return 2 -- consume 2 bytes of input
    770  * 	end
    771  * end, "Insert digraph")
    772  */
    773 /***
    774  * Setup a key alias.
    775  *
    776  * This is equivalent to `vis:command('map! mode key alias')`.
    777  *
    778  * Mappings are always recursive!
    779  * @function map
    780  * @tparam int mode the mode to which the mapping should be added
    781  * @tparam string key the key to map
    782  * @tparam string alias the key to map to
    783  * @treturn bool whether the mapping was successfully established
    784  * @see Window:map
    785  * @usage
    786  * vis:map(vis.modes.NORMAL, "j", "k")
    787  */
    788 /***
    789  * Map a key to a key action.
    790  *
    791  * @function map
    792  * @tparam int mode the mode to which the mapping should be added
    793  * @tparam string key the key to map
    794  * @param action the action to map
    795  * @treturn bool whether the mapping was successfully established
    796  * @see Window:map
    797  * @usage
    798  * local action = vis:action_register("info", function()
    799  *   vis:info("Mapping works!")
    800  * end, "Info message help text")
    801  * vis:map(vis.modes.NORMAL, "gh", action)
    802  * vis:map(vis.modes.NORMAL, "gl", action)
    803  */
    804 static int map(lua_State *L) {
    805 	Vis *vis = obj_ref_check(L, 1, "vis");
    806 	return keymap(L, vis, NULL);
    807 }
    808 
    809 /***
    810  * Unmap a global key binding.
    811  *
    812  * @function unmap
    813  * @tparam int mode the mode from which the mapping should be removed
    814  * @tparam string key the mapping to remove
    815  * @treturn bool whether the mapping was successfully removed
    816  * @see Window:unmap
    817  */
    818 static int keyunmap(lua_State *L, Vis *vis, Win *win) {
    819 	enum VisMode mode = luaL_checkint(L, 2);
    820 	const char *key = luaL_checkstring(L, 3);
    821 	bool ret;
    822 	if (!win)
    823 		ret = vis_mode_unmap(vis, mode, key);
    824 	else
    825 		ret = vis_window_mode_unmap(win, mode, key);
    826 	lua_pushboolean(L, ret);
    827 	return 1;
    828 }
    829 
    830 static int unmap(lua_State *L) {
    831 	Vis *vis = obj_ref_check(L, 1, "vis");
    832 	return keyunmap(L, vis, NULL);
    833 }
    834 
    835 /***
    836  * Get all currently active mappings of a mode.
    837  *
    838  * @function mappings
    839  * @tparam int mode the mode to query
    840  * @treturn table the active mappings and their associated help texts
    841  * @usage
    842  * local bindings = vis:mappings(vis.modes.NORMAL)
    843  * for key, help in pairs(bindings) do
    844  * 	-- do something
    845  * end
    846  * @see Vis:map
    847  */
    848 static bool binding_collect(const char *key, void *value, void *ctx) {
    849 	lua_State *L = ctx;
    850 	KeyBinding *binding = value;
    851 	lua_getfield(L, -1, key);
    852 	bool new = lua_isnil(L, -1);
    853 	lua_pop(L, 1);
    854 	if (new) {
    855 		const char *help = binding->alias ? binding->alias : VIS_HELP_USE(binding->action->help);
    856 		lua_pushstring(L, help ? help : "");
    857 		lua_setfield(L, -2, key);
    858 	}
    859 	return true;
    860 }
    861 
    862 static int mappings(lua_State *L) {
    863 	Vis *vis = obj_ref_check(L, 1, "vis");
    864 	lua_newtable(L);
    865 	for (Mode *mode = mode_get(vis, luaL_checkint(L, 2)); mode; mode = mode->parent) {
    866 		if (!mode->bindings)
    867 			continue;
    868 		map_iterate(mode->bindings, binding_collect, vis->lua);
    869 	}
    870 	return 1;
    871 }
    872 
    873 /***
    874  * Execute a motion.
    875  *
    876  * @function motion
    877  * @tparam int id the id of the motion to execute
    878  * @treturn bool whether the id was valid
    879  * @local
    880  */
    881 static int motion(lua_State *L) {
    882 	Vis *vis = obj_ref_check(L, 1, "vis");
    883 	enum VisMotion id = luaL_checkunsigned(L, 2);
    884 	// TODO handle var args?
    885 	lua_pushboolean(L, vis && vis_motion(vis, id));
    886 	return 1;
    887 }
    888 
    889 static size_t motion_lua(Vis *vis, Win *win, void *data, size_t pos) {
    890 	lua_State *L = vis->lua;
    891 	if (!L || !func_ref_get(L, data) || !obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW))
    892 		return EPOS;
    893 
    894 	lua_pushunsigned(L, pos);
    895 	if (pcall(vis, L, 2, 1) != 0)
    896 		return EPOS;
    897 	return getpos(L, -1);
    898 }
    899 
    900 /***
    901  * Register a custom motion.
    902  *
    903  * @function motion_register
    904  * @tparam function motion the Lua function implementing the motion
    905  * @treturn int the associated motion id, or `-1` on failure
    906  * @see motion, motion_new
    907  * @local
    908  * @usage
    909  * -- custom motion advancing to the next byte
    910  * local id = vis:motion_register(function(win, pos)
    911  * 	return pos+1
    912  * end)
    913  */
    914 static int motion_register(lua_State *L) {
    915 	Vis *vis = obj_ref_check(L, 1, "vis");
    916 	const void *func = func_ref_new(L, 2);
    917 	int id = vis_motion_register(vis, (void*)func, motion_lua);
    918 	lua_pushinteger(L, id);
    919 	return 1;
    920 }
    921 
    922 /***
    923  * Execute an operator.
    924  *
    925  * @function operator
    926  * @tparam int id the id of the operator to execute
    927  * @treturn bool whether the id was valid
    928  * @local
    929  */
    930 static int operator(lua_State *L) {
    931 	Vis *vis = obj_ref_check(L, 1, "vis");
    932 	enum VisOperator id = luaL_checkunsigned(L, 2);
    933 	// TODO handle var args?
    934 	lua_pushboolean(L, vis && vis_operator(vis, id));
    935 	return 1;
    936 }
    937 
    938 static size_t operator_lua(Vis *vis, Text *text, OperatorContext *c) {
    939 	lua_State *L = vis->lua;
    940 	if (!L || !func_ref_get(L, c->context))
    941 		return EPOS;
    942 	File *file = vis->files;
    943 	while (file && (file->internal || file->text != text))
    944 		file = file->next;
    945 	if (!file || !obj_ref_new(L, file, VIS_LUA_TYPE_FILE))
    946 		return EPOS;
    947 	pushrange(L, &c->range);
    948 	pushpos(L, c->pos);
    949 	if (pcall(vis, L, 3, 1) != 0)
    950 		return EPOS;
    951 	return getpos(L, -1);
    952 }
    953 
    954 /***
    955  * Register a custom operator.
    956  *
    957  * @function operator_register
    958  * @tparam function operator the Lua function implementing the operator
    959  * @treturn int the associated operator id, or `-1` on failure
    960  * @see operator, operator_new
    961  * @local
    962  * @usage
    963  * -- custom operator replacing every 'a' with 'b'
    964  * local id = vis:operator_register(function(file, range, pos)
    965  * 	local data = file:content(range)
    966  * 	data = data:gsub("a", "b")
    967  * 	file:delete(range)
    968  * 	file:insert(range.start, data)
    969  * 	return range.start -- new cursor location
    970  * end)
    971  */
    972 static int operator_register(lua_State *L) {
    973 	Vis *vis = obj_ref_check(L, 1, "vis");
    974 	const void *func = func_ref_new(L, 2);
    975 	int id = vis_operator_register(vis, operator_lua, (void*)func);
    976 	lua_pushinteger(L, id);
    977 	return 1;
    978 }
    979 
    980 /***
    981  * Execute a text object.
    982  *
    983  * @function textobject
    984  * @tparam int id the id of the text object to execute
    985  * @treturn bool whether the id was valid
    986  * @see textobject_register, textobject_new
    987  * @local
    988  */
    989 static int textobject(lua_State *L) {
    990 	Vis *vis = obj_ref_check(L, 1, "vis");
    991 	enum VisTextObject id = luaL_checkunsigned(L, 2);
    992 	lua_pushboolean(L, vis_textobject(vis, id));
    993 	return 1;
    994 }
    995 
    996 static Filerange textobject_lua(Vis *vis, Win *win, void *data, size_t pos) {
    997 	lua_State *L = vis->lua;
    998 	if (!L || !func_ref_get(L, data) || !obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW))
    999 		return text_range_empty();
   1000 	lua_pushunsigned(L, pos);
   1001 	if (pcall(vis, L, 2, 2) != 0 || lua_isnil(L, -1))
   1002 		return text_range_empty();
   1003 	return text_range_new(getpos(L, -2), getpos(L, -1));
   1004 }
   1005 
   1006 /***
   1007  * Register a custom text object.
   1008  *
   1009  * @function textobject_register
   1010  * @tparam function textobject the Lua function implementing the text object
   1011  * @treturn int the associated text object id, or `-1` on failure
   1012  * @see textobject, textobject_new
   1013  * @local
   1014  * @usage
   1015  * -- custom text object covering the next byte
   1016  * local id = vis:textobject_register(function(win, pos)
   1017  * 	return pos, pos+1
   1018  * end)
   1019  */
   1020 static int textobject_register(lua_State *L) {
   1021 	Vis *vis = obj_ref_check(L, 1, "vis");
   1022 	const void *func = func_ref_new(L, 2);
   1023 	int id = vis_textobject_register(vis, 0, (void*)func, textobject_lua);
   1024 	lua_pushinteger(L, id);
   1025 	return 1;
   1026 }
   1027 
   1028 static bool option_lua(Vis *vis, Win *win, void *context, bool toggle,
   1029                        enum VisOption flags, const char *name, Arg *value) {
   1030 	lua_State *L = vis->lua;
   1031 	if (!L || !func_ref_get(L, context))
   1032 		return false;
   1033 	if (flags & VIS_OPTION_TYPE_BOOL)
   1034 		lua_pushboolean(L, value->b);
   1035 	else if (flags & VIS_OPTION_TYPE_STRING)
   1036 		lua_pushstring(L, value->s);
   1037 	else if (flags & VIS_OPTION_TYPE_NUMBER)
   1038 		lua_pushnumber(L, value->i);
   1039 	else
   1040 		return false;
   1041 	lua_pushboolean(L, toggle);
   1042 	return pcall(vis, L, 2, 2) == 0 && (!lua_isboolean(L, -1) || lua_toboolean(L, -1));
   1043 }
   1044 
   1045 /***
   1046  * Register a custom `:set` option.
   1047  *
   1048  * @function option_register
   1049  * @tparam string name the option name
   1050  * @tparam string type the option type (`bool`, `string` or `number`)
   1051  * @tparam function handler the Lua function being called when the option is changed
   1052  * @tparam[opt] string help the single line help text as displayed in `:help`
   1053  * @treturn bool whether the option was successfully registered
   1054  * @usage
   1055  * vis:option_register("foo", "bool", function(value, toggle)
   1056  * 	if not vis.win then return false end
   1057  * 	vis.win.foo = toggle and not vis.win.foo or value
   1058  * 	vis:info("Option foo = " .. tostring(vis.win.foo))
   1059  * 	return true
   1060  * end, "Foo enables superpowers")
   1061  */
   1062 static int option_register(lua_State *L) {
   1063 	Vis *vis = obj_ref_check(L, 1, "vis");
   1064 	const char *name = luaL_checkstring(L, 2);
   1065 	const char *type = luaL_checkstring(L, 3);
   1066 	const void *func = func_ref_new(L, 4);
   1067 	const char *help = luaL_optstring(L, 5, NULL);
   1068 	const char *names[] = { name, NULL };
   1069 	enum VisOption flags = 0;
   1070 	if (strcmp(type, "string") == 0)
   1071 		flags |= VIS_OPTION_TYPE_STRING;
   1072 	else if (strcmp(type, "number") == 0)
   1073 		flags |= VIS_OPTION_TYPE_NUMBER;
   1074 	else
   1075 		flags |= VIS_OPTION_TYPE_BOOL;
   1076 	bool ret = vis_option_register(vis, names, flags, option_lua, (void*)func, help);
   1077 	lua_pushboolean(L, ret);
   1078 	return 1;
   1079 }
   1080 
   1081 /***
   1082  * Unregister a `:set` option.
   1083  *
   1084  * @function option_unregister
   1085  * @tparam string name the option name
   1086  * @treturn bool whether the option was successfully unregistered
   1087  */
   1088 static int option_unregister(lua_State *L) {
   1089 	Vis *vis = obj_ref_check(L, 1, "vis");
   1090 	const char *name = luaL_checkstring(L, 2);
   1091 	bool ret = vis_option_unregister(vis, name);
   1092 	lua_pushboolean(L, ret);
   1093 	return 1;
   1094 }
   1095 
   1096 static bool command_lua(Vis *vis, Win *win, void *data, bool force, const char *argv[], Selection *sel, Filerange *range) {
   1097 	lua_State *L = vis->lua;
   1098 	if (!L || !func_ref_get(L, data))
   1099 		return false;
   1100 	lua_newtable(L);
   1101 	for (size_t i = 0; argv[i]; i++) {
   1102 		lua_pushunsigned(L, i);
   1103 		lua_pushstring(L, argv[i]);
   1104 		lua_settable(L, -3);
   1105 	}
   1106 	lua_pushboolean(L, force);
   1107 	if (!obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW))
   1108 		return false;
   1109 	if (!sel)
   1110 		sel = view_selections_primary_get(&win->view);
   1111 	if (!obj_lightref_new(L, sel, VIS_LUA_TYPE_SELECTION))
   1112 		return false;
   1113 	pushrange(L, range);
   1114 	if (pcall(vis, L, 5, 1) != 0)
   1115 		return false;
   1116 	return lua_toboolean(L, -1);
   1117 }
   1118 
   1119 /***
   1120  * Register a custom `:`-command.
   1121  *
   1122  * @function command_register
   1123  * @tparam string name the command name
   1124  * @tparam function command the Lua function implementing the command
   1125  * @tparam[opt] string help the single line help text as displayed in `:help`
   1126  * @treturn bool whether the command has been successfully registered
   1127  * @usage
   1128  * vis:command_register("foo", function(argv, force, win, selection, range)
   1129  * 	 for i,arg in ipairs(argv) do
   1130  * 		 print(i..": "..arg)
   1131  * 	 end
   1132  * 	 print("was command forced with ! "..(force and "yes" or "no"))
   1133  * 	 print(win.file.name)
   1134  * 	 print(selection.pos)
   1135  * 	 print(range ~= nil and ('['..range.start..', '..range.finish..']') or "invalid range")
   1136  * 	 return true;
   1137  * end)
   1138  */
   1139 static int command_register(lua_State *L) {
   1140 	Vis *vis = obj_ref_check(L, 1, "vis");
   1141 	const char *name = luaL_checkstring(L, 2);
   1142 	const void *func = func_ref_new(L, 3);
   1143 	const char *help = luaL_optstring(L, 4, "");
   1144 	bool ret = vis_cmd_register(vis, name, help, (void*)func, command_lua);
   1145 	lua_pushboolean(L, ret);
   1146 	return 1;
   1147 }
   1148 
   1149 /***
   1150  * Push keys to input queue and interpret them.
   1151  *
   1152  * The keys are processed as if they were read from the keyboard.
   1153  *
   1154  * @function feedkeys
   1155  * @tparam string keys the keys to interpret
   1156  */
   1157 static int feedkeys(lua_State *L) {
   1158 	Vis *vis = obj_ref_check(L, 1, "vis");
   1159 	const char *keys = luaL_checkstring(L, 2);
   1160 	vis_keys_feed(vis, keys);
   1161 	return 0;
   1162 }
   1163 
   1164 /***
   1165  * Insert keys at all cursor positions of active window.
   1166  *
   1167  * This function behaves as if the keys were entered in insert mode,
   1168  * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
   1169  * meaning mappings do not apply and the keys will not be recorded in macros.
   1170  *
   1171  * @function insert
   1172  * @tparam string keys the keys to insert
   1173  * @see Vis:feedkeys
   1174  */
   1175 static int insert(lua_State *L) {
   1176 	Vis *vis = obj_ref_check(L, 1, "vis");
   1177 	size_t len;
   1178 	const char *keys = luaL_checklstring(L, 2, &len);
   1179 	vis_insert_key(vis, keys, len);
   1180 	return 0;
   1181 }
   1182 
   1183 /***
   1184  * Replace keys at all cursor positions of active window.
   1185  *
   1186  * This function behaves as if the keys were entered in replace mode,
   1187  * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
   1188  * meaning mappings do not apply and the keys will not be recorded in macros.
   1189  *
   1190  * @function replace
   1191  * @tparam string keys the keys to insert
   1192  * @see Vis:feedkeys
   1193  */
   1194 static int replace(lua_State *L) {
   1195 	Vis *vis = obj_ref_check(L, 1, "vis");
   1196 	size_t len;
   1197 	const char *keys = luaL_checklstring(L, 2, &len);
   1198 	vis_replace_key(vis, keys, len);
   1199 	return 0;
   1200 }
   1201 
   1202 /***
   1203  * Terminate editor process.
   1204  *
   1205  * Termination happens upon the next iteration of the main event loop.
   1206  * This means the calling Lua code will be executed further until it
   1207  * eventually hands over control to the editor core. The exit status
   1208  * of the most recent call is used.
   1209  *
   1210  * All unsaved changes will be lost!
   1211  *
   1212  * @function exit
   1213  * @tparam int code the exit status returned to the operating system
   1214  */
   1215 static int exit_func(lua_State *L) {
   1216 	Vis *vis = obj_ref_check(L, 1, "vis");
   1217 	int code = luaL_checkint(L, 2);
   1218 	vis_exit(vis, code);
   1219 	return 0;
   1220 }
   1221 
   1222 /***
   1223  * Pipe file range to external process and collect output.
   1224  *
   1225  * The editor core will be blocked while the external process is running.
   1226  * File and Range can be omitted or nil to indicate empty input.
   1227  *
   1228  * @function pipe
   1229  * @tparam[opt] File file the file to which the range applies
   1230  * @tparam[opt] Range range the range to pipe
   1231  * @tparam string command the command to execute
   1232  * @tparam[opt] bool fullscreen whether command is a fullscreen program (e.g. curses based)
   1233  * @treturn int code the exit status of the executed command
   1234  * @treturn string stdout the data written to stdout
   1235  * @treturn string stderr the data written to stderr
   1236  */
   1237 /***
   1238  * Pipe a string to external process and collect output.
   1239  *
   1240  * The editor core will be blocked while the external process is running.
   1241  *
   1242  * @function pipe
   1243  * @tparam string text the text written to the external command
   1244  * @tparam string command the command to execute
   1245  * @tparam[opt] bool fullscreen whether command is a fullscreen program (e.g. curses based)
   1246  * @treturn int code the exit status of the executed command
   1247  * @treturn string stdout the data written to stdout
   1248  * @treturn string stderr the data written to stderr
   1249  */
   1250 static int pipe_func(lua_State *L) {
   1251 	Vis *vis = obj_ref_check(L, 1, "vis");
   1252 	int cmd_idx = 4;
   1253 	char *out = NULL, *err = NULL;
   1254 	const char *text = NULL;
   1255 	File *file = vis->win ? vis->win->file : NULL;
   1256 	Filerange range = text_range_new(0, 0);
   1257 	if (lua_gettop(L) == 2) { // vis:pipe(cmd)
   1258 		cmd_idx = 2;
   1259 	} else if (lua_gettop(L) == 3) {
   1260 		if (lua_isboolean(L, 3)) { // vis:pipe(cmd, fullscreen)
   1261 			cmd_idx = 2;
   1262 		} else { // vis:pipe(text, cmd)
   1263 			text = luaL_checkstring(L, 2);
   1264 			cmd_idx = 3;
   1265 		}
   1266 	} else if (lua_isboolean(L, 4)) { // vis:pipe(text, cmd, fullscreen)
   1267 		text = luaL_checkstring(L, 2);
   1268 		cmd_idx = 3;
   1269 	} else if (!(lua_isnil(L, 2) && lua_isnil(L, 3))) { // vis:pipe(file, range, cmd, [fullscreen])
   1270 		file = obj_ref_check(L, 2, VIS_LUA_TYPE_FILE);
   1271 		range = getrange(L, 3);
   1272 	}
   1273 	const char *cmd = luaL_checkstring(L, cmd_idx);
   1274 	bool fullscreen = lua_isboolean(L, cmd_idx + 1) && lua_toboolean(L, cmd_idx + 1);
   1275 
   1276 	if (!text && !file)
   1277 		return luaL_error(L, "vis:pipe(cmd = '%s'): win not open, file can't be nil", cmd);
   1278 
   1279 	int status;
   1280 	if (text)
   1281 		status = vis_pipe_buf_collect(vis, text, (const char*[]){ cmd, NULL }, &out, &err, fullscreen);
   1282 	else
   1283 		status = vis_pipe_collect(vis, file, &range, (const char*[]){ cmd, NULL }, &out, &err, fullscreen);
   1284 	lua_pushinteger(L, status);
   1285 	if (out)
   1286 		lua_pushstring(L, out);
   1287 	else
   1288 		lua_pushnil(L);
   1289 	free(out);
   1290 	if (err)
   1291 		lua_pushstring(L, err);
   1292 	else
   1293 		lua_pushnil(L);
   1294 	free(err);
   1295 	vis_draw(vis);
   1296 	return 3;
   1297 }
   1298 
   1299 /***
   1300  * Redraw complete user interface.
   1301  *
   1302  * Will trigger redraw events, make sure to avoid recursive events.
   1303  *
   1304  * @function redraw
   1305  */
   1306 static int redraw(lua_State *L) {
   1307 	Vis *vis = obj_ref_check(L, 1, "vis");
   1308 	vis_redraw(vis);
   1309 	return 0;
   1310 }
   1311 /***
   1312  * Closes a stream returned by @{Vis:communicate}.
   1313  *
   1314  * @function close
   1315  * @tparam io.file inputfd the stream to be closed
   1316  * @treturn bool identical to @{io.close}
   1317  */
   1318 static int close_subprocess(lua_State *L) {
   1319 	luaL_Stream *file = luaL_checkudata(L, -1, "FILE*");
   1320 	int result = fclose(file->f);
   1321 	if (result == 0) {
   1322 		file->f = NULL;
   1323 		file->closef = NULL;
   1324 	}
   1325 	return luaL_fileresult(L, result == 0, NULL);
   1326 }
   1327 /***
   1328  * Open new process and return its input stream (stdin).
   1329  * If the stream is closed (by calling the close method or by being removed by a garbage collector)
   1330  * the spawned process will be killed by SIGTERM.
   1331  * When the process will quit or will output anything to stdout or stderr,
   1332  * the @{process_response} event will be fired.
   1333  *
   1334  * The editor core won't be blocked while the external process is running.
   1335  *
   1336  * @function communicate
   1337  * @tparam string name the name of subprocess (to distinguish processes in the @{process_response} event)
   1338  * @tparam string command the command to execute
   1339  * @return the file handle to write data to the process, in case of error the return values are equivalent to @{io.open} error values.
   1340  */
   1341 static int communicate_func(lua_State *L) {
   1342 
   1343 	typedef struct {
   1344 		/* Lua stream structure for the process input stream */
   1345 		luaL_Stream stream;
   1346 		Process *handler;
   1347 	} ProcessStream;
   1348 
   1349 	Vis *vis = obj_ref_check(L, 1, "vis");
   1350 	const char *name = luaL_checkstring(L, 2);
   1351 	const char *cmd = luaL_checkstring(L, 3);
   1352 	ProcessStream *inputfd = (ProcessStream *)lua_newuserdata(L, sizeof(ProcessStream));
   1353 	luaL_setmetatable(L, LUA_FILEHANDLE);
   1354 	inputfd->handler = vis_process_communicate(vis, name, cmd, &(inputfd->stream.closef));
   1355 	if (inputfd->handler) {
   1356 		inputfd->stream.f = fdopen(inputfd->handler->inpfd, "w");
   1357 		inputfd->stream.closef = &close_subprocess;
   1358 	}
   1359 	return inputfd->stream.f ? 1 : luaL_fileresult(L, 0, name);
   1360 }
   1361 /***
   1362  * Currently active window.
   1363  * @tfield Window win
   1364  * @see windows
   1365  */
   1366 /***
   1367  * Currently active mode.
   1368  * @tfield modes mode
   1369  */
   1370 /***
   1371  * Whether a macro is being recorded.
   1372  * @tfield bool recording
   1373  */
   1374 /***
   1375  * Currently unconsumed keys in the input queue.
   1376  * @tfield string input_queue
   1377  */
   1378 /***
   1379  * Register name in use.
   1380  * @tfield string register
   1381  */
   1382 /***
   1383  * Mark name in use.
   1384  * @tfield string mark
   1385  */
   1386 static int vis_index(lua_State *L) {
   1387 	Vis *vis = obj_ref_check(L, 1, "vis");
   1388 
   1389 	if (lua_isstring(L, 2)) {
   1390 		const char *key = lua_tostring(L, 2);
   1391 		if (strcmp(key, "win") == 0) {
   1392 			if (vis->win)
   1393 				obj_ref_new(L, vis->win, VIS_LUA_TYPE_WINDOW);
   1394 			else
   1395 				lua_pushnil(L);
   1396 			return 1;
   1397 		}
   1398 
   1399 		if (strcmp(key, "mode") == 0) {
   1400 			lua_pushunsigned(L, vis->mode->id);
   1401 			return 1;
   1402 		}
   1403 
   1404 		if (strcmp(key, "input_queue") == 0) {
   1405 			lua_pushstring(L, buffer_content0(&vis->input_queue));
   1406 			return 1;
   1407 		}
   1408 
   1409 		if (strcmp(key, "recording") == 0) {
   1410 			lua_pushboolean(L, vis_macro_recording(vis));
   1411 			return 1;
   1412 		}
   1413 
   1414 		if (strcmp(key, "count") == 0) {
   1415 			int count = vis->action.count;
   1416 			if (count == VIS_COUNT_UNKNOWN)
   1417 				lua_pushnil(L);
   1418 			else
   1419 				lua_pushunsigned(L, count);
   1420 			return 1;
   1421 		}
   1422 
   1423 		if (strcmp(key, "register") == 0) {
   1424 			char name = vis_register_to(vis, vis_register_used(vis));
   1425 			lua_pushlstring(L, &name, 1);
   1426 			return 1;
   1427 		}
   1428 
   1429 		if (strcmp(key, "registers") == 0) {
   1430 			obj_ref_new(L, &vis->ui, VIS_LUA_TYPE_REGISTERS);
   1431 			return 1;
   1432 		}
   1433 
   1434 		if (strcmp(key, "mark") == 0) {
   1435 			char name = vis_mark_to(vis, vis_mark_used(vis));
   1436 			lua_pushlstring(L, &name, 1);
   1437 			return 1;
   1438 		}
   1439 
   1440 		if (strcmp(key, "options") == 0) {
   1441 			obj_ref_new(L, &vis->options, VIS_LUA_TYPE_VIS_OPTS);
   1442 			return 1;
   1443 		}
   1444 
   1445 		if (strcmp(key, "ui") == 0) {
   1446 			obj_ref_new(L, &vis->ui, VIS_LUA_TYPE_UI);
   1447 			return 1;
   1448 		}
   1449 	}
   1450 
   1451 	return index_common(L);
   1452 }
   1453 
   1454 static int vis_options_assign(Vis *vis, lua_State *L, const char *key, int next) {
   1455 	if (strcmp(key, "autoindent") == 0 || strcmp(key, "ai") == 0) {
   1456 		vis->autoindent = lua_toboolean(L, next);
   1457 	} else if (strcmp(key, "changecolors") == 0) {
   1458 		vis->change_colors = lua_toboolean(L, next);
   1459 	} else if (strcmp(key, "escdelay") == 0) {
   1460 		termkey_set_waittime(vis->ui.termkey, luaL_checkint(L, next));
   1461 	} else if (strcmp(key, "ignorecase") == 0 || strcmp(key, "ic") == 0) {
   1462 		vis->ignorecase = lua_toboolean(L, next);
   1463 	} else if (strcmp(key, "loadmethod") == 0) {
   1464 		if (!lua_isstring(L, next))
   1465 			return newindex_common(L);
   1466 		const char *lm = lua_tostring(L, next);
   1467 		if (strcmp(lm, "auto") == 0)
   1468 			vis->load_method = TEXT_LOAD_AUTO;
   1469 		else if (strcmp(lm, "read") == 0)
   1470 			vis->load_method = TEXT_LOAD_READ;
   1471 		else if (strcmp(lm, "mmap") == 0)
   1472 			vis->load_method = TEXT_LOAD_MMAP;
   1473 	} else if (strcmp(key, "shell") == 0) {
   1474 		if (!lua_isstring(L, next))
   1475 			return newindex_common(L);
   1476 		vis_shell_set(vis, lua_tostring(L, next));
   1477 	}
   1478 	return 0;
   1479 }
   1480 
   1481 static int vis_newindex(lua_State *L) {
   1482 	Vis *vis = obj_ref_check(L, 1, "vis");
   1483 	if (lua_isstring(L, 2)) {
   1484 		const char *key = lua_tostring(L, 2);
   1485 		if (strcmp(key, "mode") == 0) {
   1486 			enum VisMode mode = luaL_checkunsigned(L, 3);
   1487 			vis_mode_switch(vis, mode);
   1488 			return 0;
   1489 		}
   1490 
   1491 		if (strcmp(key, "count") == 0) {
   1492 			int count;
   1493 			if (lua_isnil(L, 3))
   1494 				count = VIS_COUNT_UNKNOWN;
   1495 			else
   1496 				count = luaL_checkunsigned(L, 3);
   1497 			vis->action.count = count;
   1498 			return 0;
   1499 		}
   1500 
   1501 		if (strcmp(key, "win") == 0) {
   1502 			vis_window_focus(obj_ref_check(L, 3, VIS_LUA_TYPE_WINDOW));
   1503 			return 0;
   1504 		}
   1505 
   1506 		if (strcmp(key, "register") == 0) {
   1507 			const char *name = luaL_checkstring(L, 3);
   1508 			if (strlen(name) == 1)
   1509 				vis_register(vis, vis_register_from(vis, name[0]));
   1510 			return 0;
   1511 		}
   1512 
   1513 		if (strcmp(key, "mark") == 0) {
   1514 			const char *name = luaL_checkstring(L, 3);
   1515 			if (strlen(name) == 1)
   1516 				vis_mark(vis, vis_mark_from(vis, name[0]));
   1517 			return 0;
   1518 		}
   1519 
   1520 		if (strcmp(key, "options") == 0 && lua_istable(L, 3)) {
   1521 			int ret = 0;
   1522 			/* since we don't know which keys are in the table we push
   1523 			 * a nil then use lua_next() to remove it and push the
   1524 			 * table's key-value pairs to the stack. these can then be
   1525 			 * used to assign options
   1526 			 */
   1527 			lua_pushnil(L);
   1528 			while (lua_next(L, 3)) {
   1529 				if (lua_isstring(L, 4))
   1530 					ret += vis_options_assign(vis, L, lua_tostring(L, 4), 5);
   1531 				else
   1532 					ret += newindex_common(L);
   1533 				lua_pop(L, 1);
   1534 			}
   1535 			lua_pop(L, 1);
   1536 			return ret;
   1537 		}
   1538 	}
   1539 	return newindex_common(L);
   1540 }
   1541 
   1542 static const struct luaL_Reg vis_lua[] = {
   1543 	{ "files", files },
   1544 	{ "windows", windows },
   1545 	{ "mark_names", mark_names },
   1546 	{ "register_names", register_names },
   1547 	{ "command", command },
   1548 	{ "info", info },
   1549 	{ "message", message },
   1550 	{ "map", map },
   1551 	{ "unmap", unmap },
   1552 	{ "mappings", mappings },
   1553 	{ "operator", operator },
   1554 	{ "operator_register", operator_register },
   1555 	{ "motion", motion },
   1556 	{ "motion_register", motion_register },
   1557 	{ "textobject", textobject },
   1558 	{ "textobject_register", textobject_register },
   1559 	{ "option_register", option_register },
   1560 	{ "option_unregister", option_unregister },
   1561 	{ "command_register", command_register },
   1562 	{ "feedkeys", feedkeys },
   1563 	{ "insert", insert },
   1564 	{ "replace", replace },
   1565 	{ "action_register", action_register },
   1566 	{ "exit", exit_func },
   1567 	{ "pipe", pipe_func },
   1568 	{ "redraw", redraw },
   1569 	{ "communicate", communicate_func },
   1570 	{ "__index", vis_index },
   1571 	{ "__newindex", vis_newindex },
   1572 	{ NULL, NULL },
   1573 };
   1574 
   1575 /***
   1576  * Vis Options
   1577  * @table options
   1578  * @tfield[opt=false] boolean autoindent {ai}
   1579  * @tfield[opt=false] boolean changecolors
   1580  * @tfield[opt=50] int escdelay
   1581  * @tfield[opt=false] boolean ignorecase {ic}
   1582  * @tfield[opt="auto"] string loadmethod `"auto"`, `"read"`, or `"mmap"`.
   1583  * @tfield[opt="/bin/sh"] string shell
   1584  * @see Window.options
   1585  */
   1586 
   1587 static int vis_options_index(lua_State *L) {
   1588 	Vis *vis = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_VIS_OPTS, offsetof(Vis, options));
   1589 	if (!vis)
   1590 		return -1;
   1591 	if (lua_isstring(L, 2)) {
   1592 		const char *key = lua_tostring(L, 2);
   1593 		if (strcmp(key, "autoindent") == 0 || strcmp(key, "ai") == 0) {
   1594 			lua_pushboolean(L, vis->autoindent);
   1595 			return 1;
   1596 		} else if (strcmp(key, "changecolors") == 0) {
   1597 			lua_pushboolean(L, vis->change_colors);
   1598 			return 1;
   1599 		} else if (strcmp(key, "escdelay") == 0) {
   1600 			lua_pushunsigned(L, termkey_get_waittime(vis->ui.termkey));
   1601 			return 1;
   1602 		} else if (strcmp(key, "ignorecase") == 0 || strcmp(key, "ic") == 0) {
   1603 			lua_pushboolean(L, vis->ignorecase);
   1604 			return 1;
   1605 		} else if (strcmp(key, "loadmethod") == 0) {
   1606 			switch (vis->load_method) {
   1607 			case TEXT_LOAD_AUTO:
   1608 				lua_pushstring(L, "auto");
   1609 				break;
   1610 			case TEXT_LOAD_READ:
   1611 				lua_pushstring(L, "read");
   1612 				break;
   1613 			case TEXT_LOAD_MMAP:
   1614 				lua_pushstring(L, "mmap");
   1615 				break;
   1616 			}
   1617 			return 1;
   1618 		} else if (strcmp(key, "shell") == 0) {
   1619 			lua_pushstring(L, vis->shell);
   1620 			return 1;
   1621 		}
   1622 	}
   1623 	return index_common(L);
   1624 }
   1625 
   1626 static int vis_options_newindex(lua_State *L) {
   1627 	Vis *vis = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_VIS_OPTS, offsetof(Vis, options));
   1628 	if (!vis)
   1629 		return 0;
   1630 	if (lua_isstring(L, 2))
   1631 		return vis_options_assign(vis, L, lua_tostring(L, 2), 3);
   1632 	return newindex_common(L);
   1633 }
   1634 
   1635 static const struct luaL_Reg vis_option_funcs[] = {
   1636 	{ "__index", vis_options_index },
   1637 	{ "__newindex", vis_options_newindex},
   1638 	{ NULL, NULL },
   1639 };
   1640 
   1641 /***
   1642  * The user interface.
   1643  *
   1644  * @type Ui
   1645  */
   1646 /***
   1647  * Number of available colors.
   1648  * @tfield int colors
   1649  */
   1650 /***
   1651  * Current layout.
   1652  * @tfield layouts layout current window layout.
   1653  */
   1654 
   1655 static int ui_index(lua_State *L) {
   1656 	Ui *ui = obj_ref_check(L, 1,  VIS_LUA_TYPE_UI);
   1657 
   1658 	if (lua_isstring(L, 2)) {
   1659 		const char *key  = lua_tostring(L, 2);
   1660 
   1661 		if (strcmp(key, "layout") == 0) {
   1662 			lua_pushunsigned(L, ui->layout);
   1663 			return 1;
   1664 		}
   1665 	}
   1666 
   1667 	return index_common(L);
   1668 }
   1669 
   1670 static int ui_newindex(lua_State *L) {
   1671 	Ui *ui = obj_ref_check(L, 1,  VIS_LUA_TYPE_UI);
   1672 
   1673 	if (lua_isstring(L, 2)) {
   1674 		const char *key  = lua_tostring(L, 2);
   1675 
   1676 		if (strcmp(key, "layout") == 0) {
   1677 			ui_arrange(ui, luaL_checkint(L, 3));
   1678 			return 0;
   1679 		}
   1680 	}
   1681 	return newindex_common(L);
   1682 }
   1683 
   1684 static int ui_lua_showcursor(lua_State *L) {
   1685 	obj_ref_check(L, 1, VIS_LUA_TYPE_UI);
   1686 	bool show = lua_toboolean(L, 2);
   1687 	ui_showcursor(show);
   1688 	return 0;
   1689 }
   1690 
   1691 static const struct luaL_Reg ui_funcs[] = {
   1692 	{ "__index", ui_index },
   1693 	{ "__newindex", ui_newindex },
   1694 	{ "showcursor", ui_lua_showcursor },
   1695 	{ NULL, NULL },
   1696 };
   1697 
   1698 static int registers_index(lua_State *L) {
   1699 	lua_newtable(L);
   1700 	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
   1701 	const char *symbol = luaL_checkstring(L, 2);
   1702 	if (strlen(symbol) != 1)
   1703 		return 1;
   1704 	enum VisRegister reg = vis_register_from(vis, symbol[0]);
   1705 	if (reg >= VIS_REG_INVALID)
   1706 		return 1;
   1707 	Array data = vis_register_get(vis, reg);
   1708 	for (size_t i = 0, len = data.len; i < len; i++) {
   1709 		TextString *string = array_get(&data, i);
   1710 		lua_pushunsigned(L, i+1);
   1711 		lua_pushlstring(L, string->data, string->len);
   1712 		lua_settable(L, -3);
   1713 	}
   1714 	array_release(&data);
   1715 	return 1;
   1716 }
   1717 
   1718 static int registers_newindex(lua_State *L) {
   1719 	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
   1720 	const char *symbol = luaL_checkstring(L, 2);
   1721 	if (strlen(symbol) != 1)
   1722 		return 0;
   1723 	enum VisRegister reg = vis_register_from(vis, symbol[0]);
   1724 	Array data;
   1725 	array_init_sized(&data, sizeof(TextString));
   1726 
   1727 	if (lua_istable(L, 3)) {
   1728 		lua_pushnil(L);
   1729 		while (lua_next(L, 3)) {
   1730 			TextString string;
   1731 			string.data = luaL_checklstring(L, -1, &string.len);
   1732 			array_add(&data, &string);
   1733 			lua_pop(L, 1);
   1734 		}
   1735 	}
   1736 
   1737 	vis_register_set(vis, reg, &data);
   1738 	array_release(&data);
   1739 	return 0;
   1740 }
   1741 
   1742 static int registers_len(lua_State *L) {
   1743 	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
   1744 	lua_pushunsigned(L, LENGTH(vis->registers));
   1745 	return 1;
   1746 }
   1747 
   1748 static const struct luaL_Reg registers_funcs[] = {
   1749 	{ "__index", registers_index },
   1750 	{ "__newindex", registers_newindex },
   1751 	{ "__len", registers_len },
   1752 	{ NULL, NULL },
   1753 };
   1754 
   1755 /***
   1756  * A window object.
   1757  * @type Window
   1758  */
   1759 
   1760 /***
   1761  * Viewport currently being displayed.
   1762  * Changing these values will not move the viewport.
   1763  * @table viewport
   1764  * @tfield Range bytes file bytes, from 0, at the start and end of the viewport
   1765  * @tfield Range lines file lines, from 1, at the top and bottom of the viewport
   1766  * @tfield int height lines in viewport, accounting for window decoration
   1767  * @tfield int width columns in viewport, accounting for window decoration
   1768  */
   1769 /***
   1770  * The window width.
   1771  * @tfield int width
   1772  */
   1773 /***
   1774  * The window height.
   1775  * @tfield int height
   1776  */
   1777 /***
   1778  * The file being displayed in this window.
   1779  * Changing the value to a file path will replace the current file with a new
   1780  * one for the specified path.
   1781  * @tfield File file
   1782  */
   1783 /***
   1784  * The primary selection of this window.
   1785  * @tfield Selection selection
   1786  */
   1787 /***
   1788  * The selections of this window.
   1789  * @tfield Array(Selection) selections
   1790  */
   1791 /***
   1792  * Window marks.
   1793  * Most of these marks are stored in the associated File object, meaning they
   1794  * are the same in all windows displaying the same file.
   1795  * @field marks array to access the marks of this window by single letter name
   1796  * @see Vis:mark_names
   1797  */
   1798 static int window_index(lua_State *L) {
   1799 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   1800 
   1801 	if (lua_isstring(L, 2)) {
   1802 		const char *key = lua_tostring(L, 2);
   1803 
   1804 		if (strcmp(key, "viewport") == 0) {
   1805 			Filerange b = VIEW_VIEWPORT_GET(win->view);
   1806 			Filerange l;
   1807 			l.start = win->view.topline->lineno;
   1808 			l.end   = win->view.lastline->lineno;
   1809 
   1810 			lua_createtable(L, 0, 4);
   1811 			lua_pushstring(L, "bytes");
   1812 			pushrange(L, &b);
   1813 			lua_settable(L, -3);
   1814 			lua_pushstring(L, "lines");
   1815 			pushrange(L, &l);
   1816 			lua_settable(L, -3);
   1817 			lua_pushstring(L, "width");
   1818 			lua_pushunsigned(L, win->view.width);
   1819 			lua_settable(L, -3);
   1820 			lua_pushstring(L, "height");
   1821 			lua_pushunsigned(L, win->view.height);
   1822 			lua_settable(L, -3);
   1823 			return 1;
   1824 		}
   1825 
   1826 		if (strcmp(key, "width") == 0) {
   1827 			lua_pushunsigned(L, win->width);
   1828 			return 1;
   1829 		}
   1830 
   1831 		if (strcmp(key, "height") == 0) {
   1832 			lua_pushunsigned(L, win->height);
   1833 			return 1;
   1834 		}
   1835 
   1836 		if (strcmp(key, "file") == 0) {
   1837 			obj_ref_new(L, win->file, VIS_LUA_TYPE_FILE);
   1838 			return 1;
   1839 		}
   1840 
   1841 		if (strcmp(key, "selection") == 0) {
   1842 			Selection *sel = view_selections_primary_get(&win->view);
   1843 			obj_lightref_new(L, sel, VIS_LUA_TYPE_SELECTION);
   1844 			return 1;
   1845 		}
   1846 
   1847 		if (strcmp(key, "selections") == 0) {
   1848 			obj_ref_new(L, &win->view, VIS_LUA_TYPE_SELECTIONS);
   1849 			return 1;
   1850 		}
   1851 
   1852 		if (strcmp(key, "marks") == 0) {
   1853 			obj_ref_new(L, &win->saved_selections, VIS_LUA_TYPE_MARKS);
   1854 			return 1;
   1855 		}
   1856 		if (strcmp(key, "options") == 0) {
   1857 			obj_ref_new(L, &win->view, VIS_LUA_TYPE_WIN_OPTS);
   1858 			return 1;
   1859 		}
   1860 	}
   1861 
   1862 	return index_common(L);
   1863 }
   1864 
   1865 static int window_options_assign(Win *win, lua_State *L, const char *key, int next) {
   1866 	enum UiOption flags = win->options;
   1867 	if (strcmp(key, "breakat") == 0 || strcmp(key, "brk") == 0) {
   1868 		if (lua_isstring(L, next))
   1869 			view_breakat_set(&win->view, lua_tostring(L, next));
   1870 	} else if (strcmp(key, "colorcolumn") == 0 || strcmp(key, "cc") == 0) {
   1871 		win->view.colorcolumn = luaL_checkunsigned(L, next);
   1872 	} else if (strcmp(key, "cursorline") == 0 || strcmp(key, "cul") == 0) {
   1873 		if (lua_toboolean(L, next))
   1874 			flags |= UI_OPTION_CURSOR_LINE;
   1875 		else
   1876 			flags &= ~UI_OPTION_CURSOR_LINE;
   1877 		win_options_set(win, flags);
   1878 	} else if (strcmp(key, "numbers") == 0 || strcmp(key, "nu") == 0) {
   1879 		if (lua_toboolean(L, next))
   1880 			flags |= UI_OPTION_LINE_NUMBERS_ABSOLUTE;
   1881 		else
   1882 			flags &= ~UI_OPTION_LINE_NUMBERS_ABSOLUTE;
   1883 		win_options_set(win, flags);
   1884 	} else if (strcmp(key, "relativenumbers") == 0 || strcmp(key, "rnu") == 0) {
   1885 		if (lua_toboolean(L, next))
   1886 			flags |= UI_OPTION_LINE_NUMBERS_RELATIVE;
   1887 		else
   1888 			flags &= ~UI_OPTION_LINE_NUMBERS_RELATIVE;
   1889 		win_options_set(win, flags);
   1890 	} else if (strcmp(key, "showeof") == 0) {
   1891 		if (lua_toboolean(L, next))
   1892 			flags |= UI_OPTION_SYMBOL_EOF;
   1893 		else
   1894 			flags &= ~UI_OPTION_SYMBOL_EOF;
   1895 		win_options_set(win, flags);
   1896 	} else if (strcmp(key, "shownewlines") == 0) {
   1897 		if (lua_toboolean(L, next))
   1898 			flags |= UI_OPTION_SYMBOL_EOL;
   1899 		else
   1900 			flags &= ~UI_OPTION_SYMBOL_EOL;
   1901 		win_options_set(win, flags);
   1902 	} else if (strcmp(key, "showspaces") == 0) {
   1903 		if (lua_toboolean(L, next))
   1904 			flags |= UI_OPTION_SYMBOL_SPACE;
   1905 		else
   1906 			flags &= ~UI_OPTION_SYMBOL_SPACE;
   1907 		win_options_set(win, flags);
   1908 	} else if (strcmp(key, "showtabs") == 0) {
   1909 		if (lua_toboolean(L, next))
   1910 			flags |= UI_OPTION_SYMBOL_TAB;
   1911 		else
   1912 			flags &= ~UI_OPTION_SYMBOL_TAB;
   1913 		win_options_set(win, flags);
   1914 	} else if (strcmp(key, "statusbar") == 0) {
   1915 		if (lua_toboolean(L, next))
   1916 			flags |= UI_OPTION_STATUSBAR;
   1917 		else
   1918 			flags &= ~UI_OPTION_STATUSBAR;
   1919 		win_options_set(win, flags);
   1920 	} else if (strcmp(key, "wrapcolumn") == 0 || strcmp(key, "wc") == 0) {
   1921 		win->view.wrapcolumn = luaL_checkunsigned(L, next);
   1922 	} else if (strcmp(key, "tabwidth") == 0 || strcmp(key, "tw") == 0) {
   1923 		view_tabwidth_set(&win->view, luaL_checkint(L, next));
   1924 	} else if (strcmp(key, "expandtab") == 0 || strcmp(key, "et") == 0) {
   1925 		win->expandtab = lua_toboolean(L, next);
   1926 	}
   1927 	return 0;
   1928 }
   1929 
   1930 static int window_newindex(lua_State *L) {
   1931 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   1932 
   1933 	if (lua_isstring(L, 2)) {
   1934 		const char *key = lua_tostring(L, 2);
   1935 		if (strcmp(key, "options") == 0 && lua_istable(L, 3)) {
   1936 			int ret = 0;
   1937 			/* since we don't know which keys are in the table we push
   1938 			 * a nil then use lua_next() to remove it and push the
   1939 			 * table's key-value pairs to the stack. these can then be
   1940 			 * used to assign options
   1941 			 */
   1942 			lua_pushnil(L);
   1943 			while (lua_next(L, 3)) {
   1944 				if (lua_isstring(L, 4))
   1945 					ret += window_options_assign(win, L, lua_tostring(L, 4), 5);
   1946 				else
   1947 					ret += newindex_common(L);
   1948 				lua_pop(L, 1);
   1949 			}
   1950 			lua_pop(L, 1);
   1951 			return ret;
   1952 		} else if (strcmp(key, "file") == 0 && lua_isstring(L, 3)) {
   1953 			const char* filename = lua_tostring(L, 3);
   1954 			if (!vis_window_change_file(win, filename)) {
   1955 				return luaL_argerror(L, 3, "failed to open");
   1956 			}
   1957 			return 0;
   1958 		}
   1959 	}
   1960 
   1961 	return newindex_common(L);
   1962 }
   1963 
   1964 static int window_selections_iterator_next(lua_State *L) {
   1965 	Selection **handle = lua_touserdata(L, lua_upvalueindex(1));
   1966 	if (!*handle)
   1967 		return 0;
   1968 	Selection *sel = obj_lightref_new(L, *handle, VIS_LUA_TYPE_SELECTION);
   1969 	if (!sel)
   1970 		return 0;
   1971 	*handle = view_selections_next(sel);
   1972 	return 1;
   1973 }
   1974 
   1975 /***
   1976  * Create an iterator over all selections of this window.
   1977  * @function selections_iterator
   1978  * @return the new iterator
   1979  */
   1980 static int window_selections_iterator(lua_State *L) {
   1981 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   1982 	Selection **handle = lua_newuserdata(L, sizeof *handle);
   1983 	*handle = view_selections(&win->view);
   1984 	lua_pushcclosure(L, window_selections_iterator_next, 1);
   1985 	return 1;
   1986 }
   1987 
   1988 /***
   1989  * Set up a window local key mapping.
   1990  * The function signatures are the same as for @{Vis:map}.
   1991  * @function map
   1992  * @param ...
   1993  * @see Vis:map
   1994  */
   1995 static int window_map(lua_State *L) {
   1996 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   1997 	return keymap(L, win->vis, win);
   1998 }
   1999 
   2000 /***
   2001  * Remove a window local key mapping.
   2002  * The function signature is the same as for @{Vis:unmap}.
   2003  * @function unmap
   2004  * @param ...
   2005  * @see Vis:unmap
   2006  */
   2007 static int window_unmap(lua_State *L) {
   2008 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   2009 	return keyunmap(L, win->vis, win);
   2010 }
   2011 
   2012 /***
   2013  * Define a display style.
   2014  * @function style_define
   2015  * @tparam int id the style id to use
   2016  * @tparam string style the style definition
   2017  * @treturn bool whether the style definition has been successfully
   2018  *  associated with the given id
   2019  * @see style
   2020  * @usage
   2021  * win:style_define(win.STYLE_DEFAULT, "fore:red")
   2022  */
   2023 static int window_style_define(lua_State *L) {
   2024 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   2025 	enum UiStyle id = luaL_checkunsigned(L, 2);
   2026 	const char *style = luaL_checkstring(L, 3);
   2027 	bool ret = ui_style_define(win, id, style);
   2028 	lua_pushboolean(L, ret);
   2029 	return 1;
   2030 }
   2031 
   2032 /***
   2033  * Style a window range.
   2034  *
   2035  * The style will be cleared after every window redraw.
   2036  * @function style
   2037  * @tparam      int  id the display style as registered with @{style_define}
   2038  * @tparam      int  start the absolute file position in bytes
   2039  * @tparam      int  finish the end position
   2040  * @tparam[opt] bool keep_non_default whether non-default style values should be kept
   2041  * @see style_define
   2042  * @usage
   2043  * win:style(win.STYLE_DEFAULT, 0, 10)
   2044  */
   2045 static int window_style(lua_State *L) {
   2046 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   2047 	enum UiStyle style = luaL_checkunsigned(L, 2);
   2048 	size_t start = checkpos(L, 3);
   2049 	size_t end = checkpos(L, 4);
   2050 	bool keep_non_default = lua_isboolean(L, 5) && lua_toboolean(L, 5);
   2051 	win_style(win, style, start, end, keep_non_default);
   2052 	return 0;
   2053 }
   2054 
   2055 /***
   2056  * Style the single terminal cell at the given coordinates, relative to this window.
   2057  *
   2058  * Completely independent of the file buffer, and can be used to style UI elements,
   2059  * such as the status bar.
   2060  * The style will be cleared after every window redraw.
   2061  * @function style_pos
   2062  * @tparam      int  id display style registered with @{style_define}
   2063  * @tparam      int  x 0-based x coordinate within Win, where (0,0) is the top left corner
   2064  * @tparam      int  y See above
   2065  * @tparam[opt] bool keep_non_default whether non-default style values should be kept
   2066  * @treturn bool false if the coordinates would be outside the window's dimensions
   2067  * @see style_define
   2068  * @usage
   2069  * win:style_pos(win.STYLE_COLOR_COLUMN, 0, win.height - 1)
   2070  * -- Styles the first character of the status bar (or the last line, if disabled)
   2071  */
   2072 static int window_style_pos(lua_State *L) {
   2073 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   2074 	enum UiStyle style = luaL_checkunsigned(L, 2);
   2075 	size_t x = checkpos(L, 3);
   2076 	size_t y = checkpos(L, 4);
   2077 	bool keep_non_default = lua_isboolean(L, 5) && lua_toboolean(L, 5);
   2078 	bool ret = ui_window_style_set_pos(win, (int)x, (int)y, style, keep_non_default);
   2079 	lua_pushboolean(L, ret);
   2080 	return 1;
   2081 }
   2082 
   2083 /***
   2084  * Set window status line.
   2085  *
   2086  * @function status
   2087  * @tparam string left the left aligned part of the status line
   2088  * @tparam[opt] string right the right aligned part of the status line
   2089  */
   2090 static int window_status(lua_State *L) {
   2091 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   2092 	char status[1024] = "";
   2093 	int width = win->width;
   2094 	const char *left = luaL_checkstring(L, 2);
   2095 	const char *right = luaL_optstring(L, 3, "");
   2096 	int left_width = text_string_width(left, strlen(left));
   2097 	int right_width = text_string_width(right, strlen(right));
   2098 	int spaces = width - left_width - right_width;
   2099 	if (spaces < 1)
   2100 		spaces = 1;
   2101 	snprintf(status, sizeof(status)-1, "%s%*s%s", left, spaces, " ", right);
   2102 	ui_window_status(win, status);
   2103 	return 0;
   2104 }
   2105 
   2106 /***
   2107  * Redraw window content.
   2108  *
   2109  * @function draw
   2110  */
   2111 static int window_draw(lua_State *L) {
   2112 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   2113 	view_draw(&win->view);
   2114 	return 0;
   2115 }
   2116 
   2117 /***
   2118  * Close window.
   2119  *
   2120  * After a successful call the Window reference becomes invalid and
   2121  * must no longer be used. Attempting to close the last window will
   2122  * always fail.
   2123  *
   2124  * @function close
   2125  * @see exit
   2126  * @tparam bool force whether unsaved changes should be discarded
   2127  * @treturn bool whether the window was closed
   2128  */
   2129 static int window_close(lua_State *L) {
   2130 	Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
   2131 	int count = 0;
   2132 	for (Win *w = win->vis->windows; w; w = w->next) {
   2133 		if (!w->file->internal)
   2134 			count++;
   2135 	}
   2136 	bool force = lua_isboolean(L, 2) && lua_toboolean(L, 2);
   2137 	bool close = count > 1 && (force || vis_window_closable(win));
   2138 	if (close)
   2139 		vis_window_close(win);
   2140 	lua_pushboolean(L, close);
   2141 	return 1;
   2142 }
   2143 
   2144 static const struct luaL_Reg window_funcs[] = {
   2145 	{ "__index", window_index },
   2146 	{ "__newindex", window_newindex },
   2147 	{ "selections_iterator", window_selections_iterator },
   2148 	{ "map", window_map },
   2149 	{ "unmap", window_unmap },
   2150 	{ "style_define", window_style_define },
   2151 	{ "style", window_style },
   2152 	{ "style_pos", window_style_pos },
   2153 	{ "status", window_status },
   2154 	{ "draw", window_draw },
   2155 	{ "close", window_close },
   2156 	{ NULL, NULL },
   2157 };
   2158 
   2159 /***
   2160  * Window Options
   2161  * @table options
   2162  * @tfield[opt=""] string breakat {brk}
   2163  * @tfield[opt=0] int colorcolumn {cc}
   2164  * @tfield[opt=false] boolean cursorline {cul}
   2165  * @tfield[opt=false] boolean expandtab {et}
   2166  * @tfield[opt=false] boolean numbers {nu}
   2167  * @tfield[opt=false] boolean relativenumbers {rnu}
   2168  * @tfield[opt=true] boolean showeof
   2169  * @tfield[opt=false] boolean shownewlines
   2170  * @tfield[opt=false] boolean showspaces
   2171  * @tfield[opt=false] boolean showtabs
   2172  * @tfield[opt=true] boolean statusbar
   2173  * @tfield[opt=8] int tabwidth {tw}
   2174  * @tfield[opt=0] int wrapcolumn {wc}
   2175  * @see Vis.options
   2176  */
   2177 
   2178 static int window_options_index(lua_State *L) {
   2179 	Win *win = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_WIN_OPTS, offsetof(Win, view));
   2180 	if (!win)
   2181 		return -1;
   2182 	if (lua_isstring(L, 2)) {
   2183 		const char *key = lua_tostring(L, 2);
   2184 		if (strcmp(key, "breakat") == 0 || strcmp(key, "brk") == 0) {
   2185 			lua_pushstring(L, win->view.breakat);
   2186 			return 1;
   2187 		} else if (strcmp(key, "colorcolumn") == 0 || strcmp(key, "cc") == 0) {
   2188 			lua_pushunsigned(L, win->view.colorcolumn);
   2189 			return 1;
   2190 		} else if (strcmp(key, "cursorline") == 0 || strcmp(key, "cul") == 0) {
   2191 			lua_pushboolean(L, win->options & UI_OPTION_CURSOR_LINE);
   2192 			return 1;
   2193 		} else if (strcmp(key, "expandtab") == 0 || strcmp(key, "et") == 0) {
   2194 			lua_pushboolean(L, win->expandtab);
   2195 			return 1;
   2196 		} else if (strcmp(key, "numbers") == 0 || strcmp(key, "nu") == 0) {
   2197 			lua_pushboolean(L, win->options & UI_OPTION_LINE_NUMBERS_ABSOLUTE);
   2198 			return 1;
   2199 		} else if (strcmp(key, "relativenumbers") == 0 || strcmp(key, "rnu") == 0) {
   2200 			lua_pushboolean(L, win->options & UI_OPTION_LINE_NUMBERS_RELATIVE);
   2201 			return 1;
   2202 		} else if (strcmp(key, "showeof") == 0) {
   2203 			lua_pushboolean(L, win->options & UI_OPTION_SYMBOL_EOF);
   2204 			return 1;
   2205 		} else if (strcmp(key, "shownewlines") == 0) {
   2206 			lua_pushboolean(L, win->options & UI_OPTION_SYMBOL_EOL);
   2207 			return 1;
   2208 		} else if (strcmp(key, "showspaces") == 0) {
   2209 			lua_pushboolean(L, win->options & UI_OPTION_SYMBOL_SPACE);
   2210 			return 1;
   2211 		} else if (strcmp(key, "showtabs") == 0) {
   2212 			lua_pushboolean(L, win->options & UI_OPTION_SYMBOL_TAB);
   2213 			return 1;
   2214 		} else if (strcmp(key, "statusbar") == 0) {
   2215 			lua_pushboolean(L, win->options & UI_OPTION_STATUSBAR);
   2216 			return 1;
   2217 		} else if (strcmp(key, "tabwidth") == 0 || strcmp(key, "tw") == 0) {
   2218 			lua_pushinteger(L, win->view.tabwidth);
   2219 			return 1;
   2220 		} else if (strcmp(key, "wrapcolumn") == 0 || strcmp(key, "wc") == 0) {
   2221 			lua_pushunsigned(L, win->view.wrapcolumn);
   2222 			return 1;
   2223 		}
   2224 	}
   2225 	return index_common(L);
   2226 }
   2227 
   2228 static int window_options_newindex(lua_State *L) {
   2229 	Win *win = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_WIN_OPTS, offsetof(Win, view));
   2230 	if (!win)
   2231 		return 0;
   2232 	if (lua_isstring(L, 2))
   2233 		return window_options_assign(win, L, lua_tostring(L, 2), 3);
   2234 	return newindex_common(L);
   2235 }
   2236 
   2237 static const struct luaL_Reg window_option_funcs[] = {
   2238 	{ "__index", window_options_index },
   2239 	{ "__newindex", window_options_newindex},
   2240 	{ NULL, NULL },
   2241 };
   2242 
   2243 static int window_selections_index(lua_State *L) {
   2244 	View *view = obj_ref_check(L, 1, VIS_LUA_TYPE_SELECTIONS);
   2245 	size_t index = luaL_checkunsigned(L, 2);
   2246 	size_t count = view->selection_count;
   2247 	if (index == 0 || index > count)
   2248 		goto err;
   2249 	for (Selection *s = view_selections(view); s; s = view_selections_next(s)) {
   2250 		if (!--index) {
   2251 			obj_lightref_new(L, s, VIS_LUA_TYPE_SELECTION);
   2252 			return 1;
   2253 		}
   2254 	}
   2255 err:
   2256 	lua_pushnil(L);
   2257 	return 1;
   2258 }
   2259 
   2260 static int window_selections_len(lua_State *L) {
   2261 	View *view = obj_ref_check(L, 1, VIS_LUA_TYPE_SELECTIONS);
   2262 	lua_pushunsigned(L, view->selection_count);
   2263 	return 1;
   2264 }
   2265 
   2266 static const struct luaL_Reg window_selections_funcs[] = {
   2267 	{ "__index", window_selections_index },
   2268 	{ "__len", window_selections_len },
   2269 	{ NULL, NULL },
   2270 };
   2271 
   2272 /***
   2273  * A selection object.
   2274  *
   2275  * A selection is a non-empty, directed range with two endpoints called
   2276  * *cursor* and *anchor*. A selection can be anchored in which case
   2277  * the anchor remains fixed while only the position of the cursor is
   2278  * adjusted. For non-anchored selections both endpoints are updated. A
   2279  * singleton selection covers one character on which both cursor and
   2280  * anchor reside. There always exists a primary selection which remains
   2281  * visible (i.e. changes to its position will adjust the viewport).
   2282  *
   2283  * The range covered by a selection is represented as an interval whose
   2284  * endpoints are absolute byte offsets from the start of the file.
   2285  * Valid addresses are within the closed interval `[0, file.size]`.
   2286  *
   2287  * Selections are currently implemented using character marks into
   2288  * the underlying persistent
   2289  * [text management data structure](https://github.com/martanne/vis/wiki/Text-management-using-a-piece-chain).
   2290  *
   2291  * This has a few consequences you should be aware of:
   2292  *
   2293  *  - A selection becomes invalid when the delimiting boundaries of the underlying
   2294  *    text it is referencing is deleted:
   2295  *
   2296  *        -- leaves selection in an invalid state
   2297  *        win.file:delete(win.selection.pos, 1)
   2298  *        assert(win.selection.pos == nil)
   2299  *
   2300  *    Like a regular mark it will become valid again when the text is reverted
   2301  *    to the state before the deletion.
   2302  *
   2303  *  - Inserts after the selection position (`> selection.pos`) will not affect the
   2304  *    selection position.
   2305  *
   2306  *        local pos = win.selection.pos
   2307  *        win.file:insert(pos+1, "-")
   2308  *        assert(win.selection.pos == pos)
   2309  *
   2310  *  - Non-cached inserts before the selection position (`<= selection.pos`) will
   2311  *    affect the mark and adjust the selection position by the number of bytes
   2312  *    which were inserted.
   2313  *
   2314  *        local pos = win.selection.pos
   2315  *        win.file:insert(pos, "-")
   2316  *        assert(win.selection.pos == pos+1)
   2317  *
   2318  *  - Cached inserts before the selection position (`<= selection.pos`) will
   2319  *    not affect the selection position because the underlying text is replaced
   2320  *    inplace.
   2321  *
   2322  * For these reasons it is generally recommended to update the selection position
   2323  * after a modification. The general procedure amounts to:
   2324  *
   2325  * 1. Read out the current selection position
   2326  * 2. Perform text modifications
   2327  * 3. Update the selection position
   2328  *
   2329  * This is what @{Vis:insert} and @{Vis:replace} do internally.
   2330  *
   2331  * @type Selection
   2332  * @usage
   2333  * local data = "new text"
   2334  * local pos = win.selection.pos
   2335  * win.file:insert(pos, data)
   2336  * win.selection.pos = pos + #data
   2337  */
   2338 
   2339 /***
   2340  * The zero based byte position in the file.
   2341  *
   2342  * Might be `nil` if the selection is in an invalid state.
   2343  * Setting this field will move the cursor endpoint of the
   2344  * selection to the given position.
   2345  * @tfield int pos
   2346  */
   2347 /***
   2348  * The 1-based line the cursor of this selection resides on.
   2349  *
   2350  * @tfield int line
   2351  * @see to
   2352  */
   2353 /***
   2354  * The 1-based column position the cursor of this selection resides on.
   2355  * @tfield int col
   2356  * @see to
   2357  */
   2358 /***
   2359  * The 1-based selection index.
   2360  * @tfield int number
   2361  */
   2362 /***
   2363  * The range covered by this selection.
   2364  * @tfield Range range
   2365  */
   2366 /***
   2367  * Whether this selection is anchored.
   2368  * @tfield bool anchored
   2369  */
   2370 static int window_selection_index(lua_State *L) {
   2371 	Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
   2372 	if (!sel) {
   2373 		lua_pushnil(L);
   2374 		return 1;
   2375 	}
   2376 
   2377 	if (lua_isstring(L, 2)) {
   2378 		const char *key = lua_tostring(L, 2);
   2379 		if (strcmp(key, "pos") == 0) {
   2380 			pushpos(L, view_cursors_pos(sel));
   2381 			return 1;
   2382 		}
   2383 
   2384 		if (strcmp(key, "line") == 0) {
   2385 			lua_pushunsigned(L, view_cursors_line(sel));
   2386 			return 1;
   2387 		}
   2388 
   2389 		if (strcmp(key, "col") == 0) {
   2390 			lua_pushunsigned(L, view_cursors_col(sel));
   2391 			return 1;
   2392 		}
   2393 
   2394 		if (strcmp(key, "number") == 0) {
   2395 			lua_pushunsigned(L, view_selections_number(sel)+1);
   2396 			return 1;
   2397 		}
   2398 
   2399 		if (strcmp(key, "range") == 0) {
   2400 			Filerange range = view_selections_get(sel);
   2401 			pushrange(L, &range);
   2402 			return 1;
   2403 		}
   2404 
   2405 		if (strcmp(key, "anchored") == 0) {
   2406 			lua_pushboolean(L, sel->anchored);
   2407 			return 1;
   2408 		}
   2409 
   2410 	}
   2411 
   2412 	return index_common(L);
   2413 }
   2414 
   2415 static int window_selection_newindex(lua_State *L) {
   2416 	Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
   2417 	if (!sel)
   2418 		return 0;
   2419 	if (lua_isstring(L, 2)) {
   2420 		const char *key = lua_tostring(L, 2);
   2421 		if (strcmp(key, "pos") == 0) {
   2422 			size_t pos = checkpos(L, 3);
   2423 			view_cursors_to(sel, pos);
   2424 			return 0;
   2425 		}
   2426 
   2427 		if (strcmp(key, "range") == 0) {
   2428 			Filerange range = getrange(L, 3);
   2429 			if (text_range_valid(&range)) {
   2430 				view_selections_set(sel, &range);
   2431 				sel->anchored = true;
   2432 			} else {
   2433 				view_selection_clear(sel);
   2434 			}
   2435 			return 0;
   2436 		}
   2437 
   2438 		if (strcmp(key, "anchored") == 0) {
   2439 			sel->anchored = lua_toboolean(L, 3);
   2440 			return 0;
   2441 		}
   2442 	}
   2443 	return newindex_common(L);
   2444 }
   2445 
   2446 /***
   2447  * Move cursor of selection.
   2448  * @function to
   2449  * @tparam int line the 1-based line number
   2450  * @tparam int col the 1-based column number
   2451  */
   2452 static int window_selection_to(lua_State *L) {
   2453 	Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
   2454 	if (sel) {
   2455 		size_t line = checkpos(L, 2);
   2456 		size_t col = checkpos(L, 3);
   2457 		view_cursors_place(sel, line, col);
   2458 	}
   2459 	return 0;
   2460 }
   2461 
   2462 /***
   2463  * Remove selection.
   2464  * @function remove
   2465  */
   2466 static int window_selection_remove(lua_State *L) {
   2467 	Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
   2468 	if (sel) {
   2469 		view_selections_dispose(sel);
   2470 	}
   2471 	return 0;
   2472 }
   2473 
   2474 static const struct luaL_Reg window_selection_funcs[] = {
   2475 	{ "__index", window_selection_index },
   2476 	{ "__newindex", window_selection_newindex },
   2477 	{ "to", window_selection_to },
   2478 	{ "remove", window_selection_remove },
   2479 	{ NULL, NULL },
   2480 };
   2481 
   2482 /***
   2483  * A file object.
   2484  * @type File
   2485  */
   2486 /***
   2487  * File name.
   2488  * @tfield string name the file name relative to current working directory or `nil` if not yet named
   2489  */
   2490 /***
   2491  * File path.
   2492  * @tfield string path the absolute file path or `nil` if not yet named
   2493  */
   2494 /***
   2495  * File content by logical lines.
   2496  *
   2497  * Assigning to array element `0` (`#lines+1`) will insert a new line at
   2498  * the beginning (end) of the file.
   2499  * @tfield Array(string) lines the file content accessible as 1-based array
   2500  * @see content
   2501  * @usage
   2502  * local lines = vis.win.file.lines
   2503  * for i=1, #lines do
   2504  * 	lines[i] = i .. ": " .. lines[i]
   2505  * end
   2506  */
   2507 /***
   2508  * File save method
   2509  * @tfield[opt="auto"] string savemethod `"auto"`, `"atomic"`, or `"inplace"`.
   2510  */
   2511 /***
   2512  * File size in bytes.
   2513  * @tfield int size the current file size in bytes
   2514  */
   2515 /***
   2516  * File state.
   2517  * @tfield bool modified whether the file contains unsaved changes
   2518  */
   2519 /***
   2520  * File permission.
   2521  * @tfield int permission the file permission bits as of the most recent load/save
   2522  */
   2523 static int file_index(lua_State *L) {
   2524 	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
   2525 
   2526 	if (lua_isstring(L, 2)) {
   2527 		const char *key = lua_tostring(L, 2);
   2528 		if (strcmp(key, "name") == 0) {
   2529 			lua_pushstring(L, file_name_get(file));
   2530 			return 1;
   2531 		}
   2532 
   2533 		if (strcmp(key, "path") == 0) {
   2534 			lua_pushstring(L, file->name);
   2535 			return 1;
   2536 		}
   2537 
   2538 		if (strcmp(key, "lines") == 0) {
   2539 			obj_ref_new(L, file->text, VIS_LUA_TYPE_TEXT);
   2540 			return 1;
   2541 		}
   2542 
   2543 		if (strcmp(key, "size") == 0) {
   2544 			lua_pushunsigned(L, text_size(file->text));
   2545 			return 1;
   2546 		}
   2547 
   2548 		if (strcmp(key, "modified") == 0) {
   2549 			lua_pushboolean(L, text_modified(file->text));
   2550 			return 1;
   2551 		}
   2552 
   2553 		if (strcmp(key, "permission") == 0) {
   2554 			struct stat stat = text_stat(file->text);
   2555 			lua_pushunsigned(L, stat.st_mode & 0777);
   2556 			return 1;
   2557 		}
   2558 
   2559 		if (strcmp(key, "savemethod") == 0) {
   2560 			switch (file->save_method) {
   2561 			case TEXT_SAVE_AUTO:
   2562 				lua_pushstring(L, "auto");
   2563 				break;
   2564 			case TEXT_SAVE_ATOMIC:
   2565 				lua_pushstring(L, "atomic");
   2566 				break;
   2567 			case TEXT_SAVE_INPLACE:
   2568 				lua_pushstring(L, "inplace");
   2569 				break;
   2570 			}
   2571 			return 1;
   2572 		}
   2573 	}
   2574 
   2575 	return index_common(L);
   2576 }
   2577 
   2578 static int file_newindex(lua_State *L) {
   2579 	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
   2580 
   2581 	if (lua_isstring(L, 2)) {
   2582 		const char *key = lua_tostring(L, 2);
   2583 
   2584 		if (strcmp(key, "modified") == 0) {
   2585 			bool modified = lua_isboolean(L, 3) && lua_toboolean(L, 3);
   2586 			if (modified) {
   2587 				text_insert(file->text, 0, " ", 1);
   2588 				text_delete(file->text, 0, 1);
   2589 			} else {
   2590 				text_save(file->text, NULL);
   2591 			}
   2592 			return 0;
   2593 		}
   2594 
   2595 		if (strcmp(key, "savemethod") == 0) {
   2596 			if (!lua_isstring(L, 3))
   2597 				return newindex_common(L);
   2598 			const char *sm = lua_tostring(L, 3);
   2599 			if (strcmp(sm, "auto") == 0)
   2600 				file->save_method = TEXT_SAVE_AUTO;
   2601 			else if (strcmp(sm, "atomic") == 0)
   2602 				file->save_method = TEXT_SAVE_ATOMIC;
   2603 			else if (strcmp(sm, "inplace") == 0)
   2604 				file->save_method = TEXT_SAVE_INPLACE;
   2605 			return 0;
   2606 		}
   2607 	}
   2608 
   2609 	return newindex_common(L);
   2610 }
   2611 
   2612 /***
   2613  * Insert data at position.
   2614  * @function insert
   2615  * @tparam int pos the 0-based file position in bytes
   2616  * @tparam string data the data to insert
   2617  * @treturn bool whether the file content was successfully changed
   2618  */
   2619 static int file_insert(lua_State *L) {
   2620 	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
   2621 	size_t pos = checkpos(L, 2);
   2622 	size_t len;
   2623 	luaL_checkstring(L, 3);
   2624 	const char *data = lua_tolstring(L, 3, &len);
   2625 	lua_pushboolean(L, text_insert(file->text, pos, data, len));
   2626 	return 1;
   2627 }
   2628 
   2629 /***
   2630  * Delete data at position.
   2631  *
   2632  * @function delete
   2633  * @tparam int pos the 0-based file position in bytes
   2634  * @tparam int len the length in bytes to delete
   2635  * @treturn bool whether the file content was successfully changed
   2636  */
   2637 /***
   2638  * Delete file range.
   2639  *
   2640  * @function delete
   2641  * @tparam Range range the range to delete
   2642  * @treturn bool whether the file content was successfully changed
   2643  */
   2644 static int file_delete(lua_State *L) {
   2645 	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
   2646 	Filerange range = getrange(L, 2);
   2647 	lua_pushboolean(L, text_delete_range(file->text, &range));
   2648 	return 1;
   2649 }
   2650 
   2651 /***
   2652  * Create an iterator over all lines of the file.
   2653  *
   2654  * For large files this is probably faster than @{lines}.
   2655  * @function lines_iterator
   2656  * @return the new iterator
   2657  * @see lines
   2658  * @usage
   2659  * for line in file:lines_iterator() do
   2660  * 	-- do something with line
   2661  * end
   2662  */
   2663 static int file_lines_iterator_it(lua_State *L);
   2664 static int file_lines_iterator(lua_State *L) {
   2665 	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
   2666 	size_t line = luaL_optunsigned(L, 2, 1);
   2667 	size_t *pos = lua_newuserdata(L, sizeof *pos);
   2668 	*pos = text_pos_by_lineno(file->text, line);
   2669 	lua_pushcclosure(L, file_lines_iterator_it, 2);
   2670 	return 1;
   2671 }
   2672 
   2673 static int file_lines_iterator_it(lua_State *L) {
   2674 	File *file = *(File**)lua_touserdata(L, lua_upvalueindex(1));
   2675 	size_t *start = lua_touserdata(L, lua_upvalueindex(2));
   2676 	if (*start == text_size(file->text))
   2677 		return 0;
   2678 	size_t end = text_line_end(file->text, *start);
   2679 	size_t len = end - *start;
   2680 	char *buf = lua_newuserdata(L, len);
   2681 	if (!buf && len)
   2682 		return 0;
   2683 	len = text_bytes_get(file->text, *start, len, buf);
   2684 	lua_pushlstring(L, buf, len);
   2685 	*start = text_line_next(file->text, end);
   2686 	return 1;
   2687 }
   2688 
   2689 /***
   2690  * Get file content of position and length.
   2691  *
   2692  * @function content
   2693  * @tparam int pos the 0-based file position in bytes
   2694  * @tparam int len the length in bytes to read
   2695  * @treturn string the file content corresponding to the range
   2696  * @see lines
   2697  * @usage
   2698  * local file = vis.win.file
   2699  * local text = file:content(0, file.size)
   2700  */
   2701 /***
   2702  * Get file content of range.
   2703  *
   2704  * @function content
   2705  * @tparam Range range the range to read
   2706  * @treturn string the file content corresponding to the range
   2707  */
   2708 static int file_content(lua_State *L) {
   2709 	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
   2710 	Filerange range = getrange(L, 2);
   2711 	if (!text_range_valid(&range))
   2712 		goto err;
   2713 	size_t len = text_range_size(&range);
   2714 	char *data = lua_newuserdata(L, len);
   2715 	if (!data)
   2716 		goto err;
   2717 	len = text_bytes_get(file->text, range.start, len, data);
   2718 	lua_pushlstring(L, data, len);
   2719 	return 1;
   2720 err:
   2721 	lua_pushnil(L);
   2722 	return 1;
   2723 }
   2724 
   2725 /***
   2726  * Set mark.
   2727  * @function mark_set
   2728  * @tparam int pos the position to set the mark to, must be in [0, file.size]
   2729  * @treturn Mark mark the mark which can be looked up later
   2730  */
   2731 static int file_mark_set(lua_State *L) {
   2732 	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
   2733 	size_t pos = checkpos(L, 2);
   2734 	Mark mark = text_mark_set(file->text, pos);
   2735 	if (mark)
   2736 		obj_lightref_new(L, (void*)mark, VIS_LUA_TYPE_MARK);
   2737 	else
   2738 		lua_pushnil(L);
   2739 	return 1;
   2740 }
   2741 
   2742 /***
   2743  * Get position of mark.
   2744  * @function mark_get
   2745  * @tparam Mark mark the mark to look up
   2746  * @treturn int pos the position of the mark, or `nil` if invalid
   2747  */
   2748 static int file_mark_get(lua_State *L) {
   2749 	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
   2750 	Mark mark = (Mark)obj_lightref_check(L, 2, VIS_LUA_TYPE_MARK);
   2751 	size_t pos = text_mark_get(file->text, mark);
   2752 	if (pos == EPOS)
   2753 		lua_pushnil(L);
   2754 	else
   2755 		lua_pushunsigned(L, pos);
   2756 	return 1;
   2757 }
   2758 
   2759 /***
   2760  * Word text object.
   2761  *
   2762  * @function text_object_word
   2763  * @tparam int pos the position which must be part of the word
   2764  * @treturn Range range the range
   2765  */
   2766 
   2767 /***
   2768  * WORD text object.
   2769  *
   2770  * @function text_object_longword
   2771  * @tparam int pos the position which must be part of the word
   2772  * @treturn Range range the range
   2773  */
   2774 
   2775 static int file_text_object(lua_State *L) {
   2776 	Filerange range = text_range_empty();
   2777 	File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
   2778 	size_t pos = checkpos(L, 2);
   2779 	size_t idx = lua_tointeger(L, lua_upvalueindex(1));
   2780 	if (idx < LENGTH(vis_textobjects)) {
   2781 		const TextObject *txtobj = &vis_textobjects[idx];
   2782 		if (txtobj->txt)
   2783 			range = txtobj->txt(file->text, pos);
   2784 	}
   2785 	pushrange(L, &range);
   2786 	return 1;
   2787 }
   2788 
   2789 static const struct luaL_Reg file_funcs[] = {
   2790 	{ "__index", file_index },
   2791 	{ "__newindex", file_newindex },
   2792 	{ "insert", file_insert },
   2793 	{ "delete", file_delete },
   2794 	{ "lines_iterator", file_lines_iterator },
   2795 	{ "content", file_content },
   2796 	{ "mark_set", file_mark_set },
   2797 	{ "mark_get", file_mark_get },
   2798 	{ NULL, NULL },
   2799 };
   2800 
   2801 static int file_lines_index(lua_State *L) {
   2802 	Text *txt = obj_ref_check(L, 1, VIS_LUA_TYPE_TEXT);
   2803 	size_t line = luaL_checkunsigned(L, 2);
   2804 	size_t start = text_pos_by_lineno(txt, line);
   2805 	size_t end = text_line_end(txt, start);
   2806 	if (start != EPOS && end != EPOS) {
   2807 		size_t size = end - start;
   2808 		char *data = lua_newuserdata(L, size);
   2809 		if (!data && size)
   2810 			goto err;
   2811 		size = text_bytes_get(txt, start, size, data);
   2812 		lua_pushlstring(L, data, size);
   2813 		return 1;
   2814 	}
   2815 err:
   2816 	lua_pushnil(L);
   2817 	return 1;
   2818 }
   2819 
   2820 static int file_lines_newindex(lua_State *L) {
   2821 	Text *txt = obj_ref_check(L, 1, VIS_LUA_TYPE_TEXT);
   2822 	size_t line = luaL_checkunsigned(L, 2);
   2823 	size_t size;
   2824 	const char *data = luaL_checklstring(L, 3, &size);
   2825 	if (line == 0) {
   2826 		text_insert(txt, 0, data, size);
   2827 		text_insert(txt, size, "\n", 1);
   2828 		return 0;
   2829 	}
   2830 	size_t start = text_pos_by_lineno(txt, line);
   2831 	size_t end = text_line_end(txt, start);
   2832 	if (start != EPOS && end != EPOS) {
   2833 		text_delete(txt, start, end - start);
   2834 		text_insert(txt, start, data, size);
   2835 		if (text_size(txt) == start + size)
   2836 			text_insert(txt, text_size(txt), "\n", 1);
   2837 	}
   2838 	return 0;
   2839 }
   2840 
   2841 static int file_lines_len(lua_State *L) {
   2842 	Text *txt = obj_ref_check(L, 1, VIS_LUA_TYPE_TEXT);
   2843 	size_t lines = 0;
   2844 	char lastchar;
   2845 	size_t size = text_size(txt);
   2846 	if (size > 0)
   2847 		lines = text_lineno_by_pos(txt, size);
   2848 	if (lines > 1 && text_byte_get(txt, size-1, &lastchar) && lastchar == '\n')
   2849 		lines--;
   2850 	lua_pushunsigned(L, lines);
   2851 	return 1;
   2852 }
   2853 
   2854 static const struct luaL_Reg file_lines_funcs[] = {
   2855 	{ "__index", file_lines_index },
   2856 	{ "__newindex", file_lines_newindex },
   2857 	{ "__len", file_lines_len },
   2858 	{ NULL, NULL },
   2859 };
   2860 
   2861 static int window_marks_index(lua_State *L) {
   2862 	lua_newtable(L);
   2863 	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
   2864 	Win *win = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_MARKS, offsetof(Win, saved_selections));
   2865 	if (!win)
   2866 		return 1;
   2867 	const char *symbol = luaL_checkstring(L, 2);
   2868 	if (strlen(symbol) != 1)
   2869 		return 1;
   2870 	enum VisMark mark = vis_mark_from(vis, symbol[0]);
   2871 	if (mark == VIS_MARK_INVALID)
   2872 		return 1;
   2873 
   2874 	Array arr = vis_mark_get(win, mark);
   2875 	for (size_t i = 0, len = arr.len; i < len; i++) {
   2876 		Filerange *range = array_get(&arr, i);
   2877 		lua_pushunsigned(L, i+1);
   2878 		pushrange(L, range);
   2879 		lua_settable(L, -3);
   2880 	}
   2881 	array_release(&arr);
   2882 	return 1;
   2883 }
   2884 
   2885 static int window_marks_newindex(lua_State *L) {
   2886 	Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
   2887 	Win *win = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_MARKS, offsetof(Win, saved_selections));
   2888 	if (!win)
   2889 		return 0;
   2890 	const char *symbol = luaL_checkstring(L, 2);
   2891 	if (strlen(symbol) != 1)
   2892 		return 0;
   2893 	enum VisMark mark = vis_mark_from(vis, symbol[0]);
   2894 	if (mark == VIS_MARK_INVALID)
   2895 		return 0;
   2896 
   2897 	Array ranges;
   2898 	array_init_sized(&ranges, sizeof(Filerange));
   2899 
   2900 	if (lua_istable(L, 3)) {
   2901 		lua_pushnil(L);
   2902 		while (lua_next(L, 3)) {
   2903 			Filerange range = getrange(L, -1);
   2904 			if (text_range_valid(&range))
   2905 				array_add(&ranges, &range);
   2906 			lua_pop(L, 1);
   2907 		}
   2908 	}
   2909 
   2910 	vis_mark_set(win, mark, &ranges);
   2911 	array_release(&ranges);
   2912 	return 0;
   2913 }
   2914 
   2915 static int window_marks_len(lua_State *L) {
   2916 	lua_pushunsigned(L, VIS_MARK_INVALID);
   2917 	return 1;
   2918 }
   2919 
   2920 static const struct luaL_Reg window_marks_funcs[] = {
   2921 	{ "__index", window_marks_index },
   2922 	{ "__newindex", window_marks_newindex },
   2923 	{ "__len", window_marks_len },
   2924 	{ NULL, NULL },
   2925 };
   2926 
   2927 /***
   2928  * A file range.
   2929  *
   2930  * For a valid range `start <= finish` holds.
   2931  * An invalid range is represented as `nil`.
   2932  * @type Range
   2933  */
   2934 /***
   2935  * The beginning of the range.
   2936  * @tfield int start
   2937  */
   2938 /***
   2939  * The end of the range.
   2940  * @tfield int finish
   2941  */
   2942 
   2943 /***
   2944  * Layouts.
   2945  * @section Layouts
   2946  */
   2947 
   2948 /***
   2949  * Layout Constants.
   2950  * @table layouts
   2951  * @tfield int HORIZONTAL
   2952  * @tfield int VERTICAL
   2953  */
   2954 
   2955 /***
   2956  * Modes.
   2957  * @section Modes
   2958  */
   2959 
   2960 /***
   2961  * Mode constants.
   2962  * @table modes
   2963  * @tfield int NORMAL
   2964  * @tfield int OPERATOR_PENDING
   2965  * @tfield int INSERT
   2966  * @tfield int REPLACE
   2967  * @tfield int VISUAL
   2968  * @tfield int VISUAL_LINE
   2969  * @see Vis:map
   2970  * @see Window:map
   2971  */
   2972 
   2973 /***
   2974  * Key Handling.
   2975  *
   2976  * This section describes the contract between the editor core and Lua
   2977  * key handling functions mapped to symbolic keys using either @{Vis:map}
   2978  * or @{Window:map}.
   2979  *
   2980  * @section Key_Handling
   2981  */
   2982 
   2983 /***
   2984  * Example of a key handling function.
   2985  *
   2986  * The keyhandler is invoked with the pending content of the input queue
   2987  * given as argument. This might be the empty string if no further input
   2988  * is available.
   2989  *
   2990  * The function is expected to return the number of *bytes* it has
   2991  * consumed from the passed input keys. A negative return value is
   2992  * interpreted as an indication that not enough input was available. The
   2993  * function will be called again once the user has provided more input. A
   2994  * missing return value (i.e. `nil`) is interpreted as zero, meaning
   2995  * no further input was consumed but the function completed successfully.
   2996  *
   2997  * @function keyhandler
   2998  * @tparam string keys the keys following the mapping
   2999  * @treturn int the number of *bytes* being consumed by the function (see above)
   3000  * @see Vis:action_register
   3001  * @see Vis:map
   3002  * @see Window:map
   3003  * @usage
   3004  * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
   3005  * 	if #keys < 2 then
   3006  * 		return -1 -- need more input
   3007  * 	end
   3008  * 	local digraph = keys:sub(1, 2)
   3009  * 	if digraph == "l*" then
   3010  * 		vis:feedkeys('λ')
   3011  * 		return 2 -- consume 2 bytes of input
   3012  * 	end
   3013  * end, "Insert digraph")
   3014  */
   3015 
   3016 /***
   3017  * Core Events.
   3018  *
   3019  * These events are invoked from the editor core.
   3020  * The following functions are invoked if they are registered in the
   3021  * `vis.events` table. Users scripts should generally use the [Events](#events)
   3022  * mechanism instead which multiplexes these core events.
   3023  *
   3024  * @section Core_Events
   3025  */
   3026 
   3027 static void vis_lua_event_get(lua_State *L, const char *name) {
   3028 	lua_getglobal(L, "vis");
   3029 	lua_getfield(L, -1, "events");
   3030 	if (lua_istable(L, -1)) {
   3031 		lua_getfield(L, -1, name);
   3032 	}
   3033 	lua_remove(L, -2);
   3034 }
   3035 
   3036 static void vis_lua_event_call(Vis *vis, const char *name) {
   3037 	lua_State *L = vis->lua;
   3038 	vis_lua_event_get(L, name);
   3039 	if (lua_isfunction(L, -1))
   3040 		pcall(vis, L, 0, 0);
   3041 	lua_pop(L, 1);
   3042 }
   3043 
   3044 static bool vis_lua_path_strip(Vis *vis) {
   3045 	lua_State *L = vis->lua;
   3046 	lua_getglobal(L, "package");
   3047 
   3048 	for (const char **var = (const char*[]){ "path", "cpath", NULL }; *var; var++) {
   3049 
   3050 		lua_getfield(L, -1, *var);
   3051 		const char *path = lua_tostring(L, -1);
   3052 		lua_pop(L, 1);
   3053 		if (!path)
   3054 			return false;
   3055 
   3056 		char *copy = strdup(path), *stripped = calloc(1, strlen(path)+2);
   3057 		if (!copy || !stripped) {
   3058 			free(copy);
   3059 			free(stripped);
   3060 			return false;
   3061 		}
   3062 
   3063 		for (char *elem = copy, *stripped_elem = stripped, *next; elem; elem = next) {
   3064 			if ((next = strstr(elem, ";")))
   3065 				*next++ = '\0';
   3066 			if (strstr(elem, "./"))
   3067 				continue; /* skip relative path entries */
   3068 			stripped_elem += sprintf(stripped_elem, "%s;", elem);
   3069 		}
   3070 
   3071 		lua_pushstring(L, stripped);
   3072 		lua_setfield(L, -2, *var);
   3073 
   3074 		free(copy);
   3075 		free(stripped);
   3076 	}
   3077 
   3078 	lua_pop(L, 1); /* package */
   3079 	return true;
   3080 }
   3081 
   3082 bool vis_lua_path_add(Vis *vis, const char *path) {
   3083 	lua_State *L = vis->lua;
   3084 	if (!L || !path)
   3085 		return false;
   3086 	lua_getglobal(L, "package");
   3087 	lua_pushstring(L, path);
   3088 	lua_pushstring(L, "/?.lua;");
   3089 	lua_pushstring(L, path);
   3090 	lua_pushstring(L, "/?/init.lua;");
   3091 	lua_getfield(L, -5, "path");
   3092 	lua_concat(L, 5);
   3093 	lua_setfield(L, -2, "path");
   3094 	lua_pop(L, 1); /* package */
   3095 	return true;
   3096 }
   3097 
   3098 bool vis_lua_paths_get(Vis *vis, char **lpath, char **cpath) {
   3099 	lua_State *L = vis->lua;
   3100 	if (!L)
   3101 		return false;
   3102 	const char *s;
   3103 	lua_getglobal(L, "package");
   3104 	lua_getfield(L, -1, "path");
   3105 	s = lua_tostring(L, -1);
   3106 	*lpath = s ? strdup(s) : NULL;
   3107 	lua_getfield(L, -2, "cpath");
   3108 	s = lua_tostring(L, -1);
   3109 	*cpath = s ? strdup(s) : NULL;
   3110 	return true;
   3111 }
   3112 
   3113 static bool package_exist(Vis *vis, lua_State *L, const char *name) {
   3114 	const char lua[] =
   3115 		"local name = ...\n"
   3116 		"for _, searcher in ipairs(package.searchers or package.loaders) do\n"
   3117 			"local loader = searcher(name)\n"
   3118 			"if type(loader) == 'function' then\n"
   3119 				"return true\n"
   3120 			"end\n"
   3121 		"end\n"
   3122 		"return false\n";
   3123 	if (luaL_loadstring(L, lua) != LUA_OK)
   3124 		return false;
   3125 	lua_pushstring(L, name);
   3126 	/* an error indicates package exists */
   3127 	bool ret = lua_pcall(L, 1, 1, 0) != LUA_OK || lua_toboolean(L, -1);
   3128 	lua_pop(L, 1);
   3129 	return ret;
   3130 }
   3131 
   3132 static void *alloc_lua(void *ud, void *ptr, size_t osize, size_t nsize) {
   3133 	if (nsize == 0) {
   3134 		free(ptr);
   3135 		return NULL;
   3136 	} else {
   3137 		return realloc(ptr, nsize);
   3138 	}
   3139 }
   3140 
   3141 /***
   3142  * Editor initialization completed.
   3143  * This event is emitted immediately after `visrc.lua` has been sourced, but
   3144  * before any other events have occurred, in particular the command line arguments
   3145  * have not yet been processed.
   3146  *
   3147  * Can be used to set *global* configuration options.
   3148  * @function init
   3149  */
   3150 static void vis_lua_init(Vis *vis) {
   3151 	lua_State *L = lua_newstate(alloc_lua, vis);
   3152 	if (!L)
   3153 		return;
   3154 	vis->lua = L;
   3155 	lua_atpanic(L, &panic_handler);
   3156 
   3157 	luaL_openlibs(L);
   3158 
   3159 #if CONFIG_LPEG
   3160 	extern int luaopen_lpeg(lua_State *L);
   3161 	lua_getglobal(L, "package");
   3162 	lua_getfield(L, -1, "preload");
   3163 	lua_pushcfunction(L, luaopen_lpeg);
   3164 	lua_setfield(L, -2, "lpeg");
   3165 	lua_pop(L, 2);
   3166 #endif
   3167 
   3168 	/* remove any relative paths from lua's default package.path */
   3169 	vis_lua_path_strip(vis);
   3170 
   3171 	/* extends lua's package.path with:
   3172 	 * - $VIS_PATH
   3173 	 * - ./lua (relative path to the binary location)
   3174 	 * - $XDG_CONFIG_HOME/vis (defaulting to $HOME/.config/vis)
   3175 	 * - /etc/vis (for system-wide configuration provided by administrator)
   3176 	 * - /usr/(local/)?share/vis (or whatever is specified during ./configure)
   3177 	 * - package.path (standard lua search path)
   3178 	 */
   3179 	char path[PATH_MAX];
   3180 
   3181 	vis_lua_path_add(vis, VIS_PATH);
   3182 
   3183 	/* try to get users home directory */
   3184 	const char *home = getenv("HOME");
   3185 	if (!home || !*home) {
   3186 		struct passwd *pw = getpwuid(getuid());
   3187 		if (pw)
   3188 			home = pw->pw_dir;
   3189 	}
   3190 
   3191 	vis_lua_path_add(vis, "/etc/vis");
   3192 
   3193 	const char *xdg_config = getenv("XDG_CONFIG_HOME");
   3194 	if (xdg_config) {
   3195 		snprintf(path, sizeof path, "%s/vis", xdg_config);
   3196 		vis_lua_path_add(vis, path);
   3197 	} else if (home && *home) {
   3198 		snprintf(path, sizeof path, "%s/.config/vis", home);
   3199 		vis_lua_path_add(vis, path);
   3200 	}
   3201 
   3202 	ssize_t len = readlink("/proc/self/exe", path, sizeof(path)-1);
   3203 	if (len > 0) {
   3204 		path[len] = '\0';
   3205 		/* some idiotic dirname(3) implementations return pointers to statically
   3206 		 * allocated memory, hence we use memmove to copy it back */
   3207 		char *dir = dirname(path);
   3208 		if (dir) {
   3209 			size_t len = strlen(dir)+1;
   3210 			if (len < sizeof(path) - sizeof("/lua")) {
   3211 				memmove(path, dir, len);
   3212 				strcat(path, "/lua");
   3213 				vis_lua_path_add(vis, path);
   3214 			}
   3215 		}
   3216 	}
   3217 
   3218 	vis_lua_path_add(vis, getenv("VIS_PATH"));
   3219 
   3220 	/* table in registry to lookup object type, stores metatable -> type mapping */
   3221 	lua_newtable(L);
   3222 	lua_setfield(L, LUA_REGISTRYINDEX, "vis.types");
   3223 	/* table in registry to track lifetimes of C objects */
   3224 	lua_newtable(L);
   3225 	lua_setfield(L, LUA_REGISTRYINDEX, "vis.objects");
   3226 	/* table in registry to store references to Lua functions */
   3227 	lua_newtable(L);
   3228 	lua_setfield(L, LUA_REGISTRYINDEX, "vis.functions");
   3229 	/* metatable used to type check user data */
   3230 	obj_type_new(L, VIS_LUA_TYPE_VIS);
   3231 	luaL_setfuncs(L, vis_lua, 0);
   3232 	lua_newtable(L);
   3233 	lua_setfield(L, -2, "types");
   3234 	/* create reference to main vis object, such that the further
   3235 	 * calls to obj_type_new can register the type meta tables in
   3236 	 * vis.types[name] */
   3237 	obj_ref_new(L, vis, "vis");
   3238 	lua_setglobal(L, "vis");
   3239 
   3240 	obj_type_new(L, VIS_LUA_TYPE_FILE);
   3241 
   3242 	const struct {
   3243 		enum VisTextObject id;
   3244 		const char *name;
   3245 	} textobjects[] = {
   3246 		{ VIS_TEXTOBJECT_INNER_WORD, "text_object_word" },
   3247 		{ VIS_TEXTOBJECT_INNER_LONGWORD, "text_object_longword" },
   3248 	};
   3249 
   3250 	for (size_t i = 0; i < LENGTH(textobjects); i++) {
   3251 		lua_pushunsigned(L, textobjects[i].id);
   3252 		lua_pushcclosure(L, file_text_object, 1);
   3253 		lua_setfield(L, -2, textobjects[i].name);
   3254 	}
   3255 
   3256 	luaL_setfuncs(L, file_funcs, 0);
   3257 
   3258 	obj_type_new(L, VIS_LUA_TYPE_TEXT);
   3259 	luaL_setfuncs(L, file_lines_funcs, 0);
   3260 	obj_type_new(L, VIS_LUA_TYPE_WINDOW);
   3261 	luaL_setfuncs(L, window_funcs, 0);
   3262 
   3263 	const struct {
   3264 		enum UiStyle id;
   3265 		const char *name;
   3266 	} styles[] = {
   3267 		{ UI_STYLE_LEXER_MAX,         "STYLE_LEXER_MAX"         },
   3268 		{ UI_STYLE_DEFAULT,           "STYLE_DEFAULT"           },
   3269 		{ UI_STYLE_CURSOR,            "STYLE_CURSOR"            },
   3270 		{ UI_STYLE_CURSOR_PRIMARY,    "STYLE_CURSOR_PRIMARY"    },
   3271 		{ UI_STYLE_CURSOR_LINE,       "STYLE_CURSOR_LINE"       },
   3272 		{ UI_STYLE_SELECTION,         "STYLE_SELECTION"         },
   3273 		{ UI_STYLE_LINENUMBER,        "STYLE_LINENUMBER"        },
   3274 		{ UI_STYLE_LINENUMBER_CURSOR, "STYLE_LINENUMBER_CURSOR" },
   3275 		{ UI_STYLE_COLOR_COLUMN,      "STYLE_COLOR_COLUMN"      },
   3276 		{ UI_STYLE_STATUS,            "STYLE_STATUS"            },
   3277 		{ UI_STYLE_STATUS_FOCUSED,    "STYLE_STATUS_FOCUSED"    },
   3278 		{ UI_STYLE_SEPARATOR,         "STYLE_SEPARATOR"         },
   3279 		{ UI_STYLE_INFO,              "STYLE_INFO"              },
   3280 		{ UI_STYLE_EOF,               "STYLE_EOF"               },
   3281 	};
   3282 
   3283 	for (size_t i = 0; i < LENGTH(styles); i++) {
   3284 		lua_pushunsigned(L, styles[i].id);
   3285 		lua_setfield(L, -2, styles[i].name);
   3286 	}
   3287 
   3288 	obj_type_new(L, VIS_LUA_TYPE_WIN_OPTS);
   3289 	luaL_setfuncs(L, window_option_funcs, 0);
   3290 
   3291 	obj_type_new(L, VIS_LUA_TYPE_MARK);
   3292 	obj_type_new(L, VIS_LUA_TYPE_MARKS);
   3293 	lua_pushlightuserdata(L, vis);
   3294 	luaL_setfuncs(L, window_marks_funcs, 1);
   3295 
   3296 	obj_type_new(L, VIS_LUA_TYPE_SELECTION);
   3297 	luaL_setfuncs(L, window_selection_funcs, 0);
   3298 	obj_type_new(L, VIS_LUA_TYPE_SELECTIONS);
   3299 	luaL_setfuncs(L, window_selections_funcs, 0);
   3300 
   3301 	obj_type_new(L, VIS_LUA_TYPE_UI);
   3302 	luaL_setfuncs(L, ui_funcs, 0);
   3303 	lua_pushunsigned(L, ui_terminal_colors());
   3304 	lua_setfield(L, -2, "colors");
   3305 	lua_newtable(L);
   3306 	static const struct {
   3307 		enum UiLayout id;
   3308 		const char *name;
   3309 	} layouts[] = {
   3310 		{ UI_LAYOUT_HORIZONTAL, "HORIZONTAL" },
   3311 		{ UI_LAYOUT_VERTICAL, "VERTICAL" },
   3312 	};
   3313 	for (size_t i = 0; i <  LENGTH(layouts); i++) {
   3314 		lua_pushunsigned(L, layouts[i].id);
   3315 		lua_setfield(L, -2, layouts[i].name);
   3316 	}
   3317 	lua_setfield(L, -2, "layouts");
   3318 
   3319 	obj_type_new(L, VIS_LUA_TYPE_REGISTERS);
   3320 	lua_pushlightuserdata(L, vis);
   3321 	luaL_setfuncs(L, registers_funcs, 1);
   3322 
   3323 	obj_type_new(L, VIS_LUA_TYPE_KEYACTION);
   3324 
   3325 	lua_getglobal(L, "vis");
   3326 	lua_getmetatable(L, -1);
   3327 
   3328 	lua_pushstring(L, VERSION);
   3329 	lua_setfield(L, -2, "VERSION");
   3330 
   3331 	lua_newtable(L);
   3332 	static const struct {
   3333 		enum VisMode id;
   3334 		const char *name;
   3335 	} modes[] = {
   3336 		{ VIS_MODE_NORMAL,           "NORMAL"           },
   3337 		{ VIS_MODE_OPERATOR_PENDING, "OPERATOR_PENDING" },
   3338 		{ VIS_MODE_VISUAL,           "VISUAL"           },
   3339 		{ VIS_MODE_VISUAL_LINE,      "VISUAL_LINE"      },
   3340 		{ VIS_MODE_INSERT,           "INSERT"           },
   3341 		{ VIS_MODE_REPLACE,          "REPLACE"          },
   3342 	};
   3343 	for (size_t i = 0; i < LENGTH(modes); i++) {
   3344 		lua_pushunsigned(L, modes[i].id);
   3345 		lua_setfield(L, -2, modes[i].name);
   3346 	}
   3347 	lua_setfield(L, -2, "modes");
   3348 
   3349 	obj_type_new(L, VIS_LUA_TYPE_VIS_OPTS);
   3350 	luaL_setfuncs(L, vis_option_funcs, 0);
   3351 
   3352 	if (!package_exist(vis, L, "visrc")) {
   3353 		vis_info_show(vis, "WARNING: failed to load visrc.lua");
   3354 	} else {
   3355 		lua_getglobal(L, "require");
   3356 		lua_pushstring(L, "visrc");
   3357 		pcall(vis, L, 1, 0);
   3358 		vis_lua_event_call(vis, "init");
   3359 	}
   3360 }
   3361 
   3362 /***
   3363  * Editor startup completed.
   3364  * This event is emitted immediately before the main loop starts.
   3365  * At this point all files are loaded and corresponding windows are created.
   3366  * We are about to process interactive keyboard input.
   3367  * @function start
   3368  */
   3369 static void vis_lua_start(Vis *vis) {
   3370 	vis_lua_event_call(vis, "start");
   3371 }
   3372 
   3373 /**
   3374  * Editor is about to terminate.
   3375  * @function quit
   3376  */
   3377 static void vis_lua_quit(Vis *vis) {
   3378 	if (!vis->lua)
   3379 		return;
   3380 	vis_lua_event_call(vis, "quit");
   3381 	lua_close(vis->lua);
   3382 	vis->lua = NULL;
   3383 }
   3384 
   3385 /***
   3386  * Input key event in either input or replace mode.
   3387  * @function input
   3388  * @tparam string key
   3389  * @treturn bool whether the key was consumed or not
   3390  */
   3391 static bool vis_lua_input(Vis *vis, const char *key, size_t len) {
   3392 	lua_State *L = vis->lua;
   3393 	if (!L || !vis->win || vis->win->file->internal)
   3394 		return false;
   3395 	bool ret = false;
   3396 	vis_lua_event_get(L, "input");
   3397 	if (lua_isfunction(L, -1)) {
   3398 		lua_pushlstring(L, key, len);
   3399 		if (pcall(vis, L, 1, 1) == 0) {
   3400 			ret = lua_isboolean(L, -1) && lua_toboolean(L, -1);
   3401 			lua_pop(L, 1);
   3402 		}
   3403 	}
   3404 	lua_pop(L, 1);
   3405 	return ret;
   3406 }
   3407 
   3408 void vis_event_mode_insert_input(Vis *vis, const char *key, size_t len) {
   3409 	if (!vis_lua_input(vis, key, len))
   3410 		vis_insert_key(vis, key, len);
   3411 }
   3412 
   3413 void vis_event_mode_replace_input(Vis *vis, const char *key, size_t len) {
   3414 	if (!vis_lua_input(vis, key, len))
   3415 		vis_replace_key(vis, key, len);
   3416 }
   3417 
   3418 /***
   3419  * File open.
   3420  * @function file_open
   3421  * @tparam File file the file to be opened
   3422  */
   3423 static void vis_lua_file_open(Vis *vis, File *file) {
   3424 	debug("event: file-open: %s %p %p\n", file->name ? file->name : "unnamed", (void*)file, (void*)file->text);
   3425 	lua_State *L = vis->lua;
   3426 	if (!L)
   3427 		return;
   3428 	vis_lua_event_get(L, "file_open");
   3429 	if (lua_isfunction(L, -1)) {
   3430 		obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
   3431 		pcall(vis, L, 1, 0);
   3432 	}
   3433 	lua_pop(L, 1);
   3434 }
   3435 
   3436 /***
   3437  * File pre save.
   3438  * Triggered *before* the file is being written.
   3439  * @function file_save_pre
   3440  * @tparam File file the file being written
   3441  * @tparam string path the absolute path to which the file will be written, `nil` if standard output
   3442  * @treturn bool whether the write operation should be proceeded
   3443  */
   3444 static bool vis_lua_file_save_pre(Vis *vis, File *file, const char *path) {
   3445 	lua_State *L = vis->lua;
   3446 	if (!L)
   3447 		return true;
   3448 	vis_lua_event_get(L, "file_save_pre");
   3449 	if (lua_isfunction(L, -1)) {
   3450 		obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
   3451 		lua_pushstring(L, path);
   3452 		if (pcall(vis, L, 2, 1) != 0)
   3453 			return false;
   3454 		return !lua_isboolean(L, -1) || lua_toboolean(L, -1);
   3455 	}
   3456 	lua_pop(L, 1);
   3457 	return true;
   3458 }
   3459 
   3460 /***
   3461  * File post save.
   3462  * Triggered *after* a successful write operation.
   3463  * @function file_save_post
   3464  * @tparam File file the file which was written
   3465  * @tparam string path the absolute path to which it was written, `nil` if standard output
   3466  */
   3467 static void vis_lua_file_save_post(Vis *vis, File *file, const char *path) {
   3468 	lua_State *L = vis->lua;
   3469 	if (!L)
   3470 		return;
   3471 	vis_lua_event_get(L, "file_save_post");
   3472 	if (lua_isfunction(L, -1)) {
   3473 		obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
   3474 		lua_pushstring(L, path);
   3475 		pcall(vis, L, 2, 0);
   3476 	}
   3477 	lua_pop(L, 1);
   3478 }
   3479 
   3480 /***
   3481  * File close.
   3482  * The last window displaying the file has been closed.
   3483  * @function file_close
   3484  * @tparam File file the file being closed
   3485  */
   3486 static void vis_lua_file_close(Vis *vis, File *file) {
   3487 	debug("event: file-close: %s %p %p\n", file->name ? file->name : "unnamed", (void*)file, (void*)file->text);
   3488 	lua_State *L = vis->lua;
   3489 	if (!L)
   3490 		return;
   3491 	vis_lua_event_get(L, "file_close");
   3492 	if (lua_isfunction(L, -1)) {
   3493 		obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
   3494 		pcall(vis, L, 1, 0);
   3495 	}
   3496 	obj_ref_free(L, file->marks);
   3497 	obj_ref_free(L, file->text);
   3498 	obj_ref_free(L, file);
   3499 	lua_pop(L, 1);
   3500 }
   3501 
   3502 /***
   3503  * Window open.
   3504  * A new window has been created.
   3505  * @function win_open
   3506  * @tparam Window win the window being opened
   3507  */
   3508 static void vis_lua_win_open(Vis *vis, Win *win) {
   3509 	debug("event: win-open: %s %p %p\n", win->file->name ? win->file->name : "unnamed", (void*)win, (void*)win->view);
   3510 	lua_State *L = vis->lua;
   3511 	if (!L)
   3512 		return;
   3513 	vis_lua_event_get(L, "win_open");
   3514 	if (lua_isfunction(L, -1)) {
   3515 		obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
   3516 		pcall(vis, L, 1, 0);
   3517 	}
   3518 	lua_pop(L, 1);
   3519 }
   3520 
   3521 /***
   3522  * Window close.
   3523  * An window is being closed.
   3524  * @function win_close
   3525  * @tparam Window win the window being closed
   3526  */
   3527 static void vis_lua_win_close(Vis *vis, Win *win) {
   3528 	debug("event: win-close: %s %p %p\n", win->file->name ? win->file->name : "unnamed", (void*)win, (void*)win->view);
   3529 	lua_State *L = vis->lua;
   3530 	if (!L)
   3531 		return;
   3532 	vis_lua_event_get(L, "win_close");
   3533 	if (lua_isfunction(L, -1)) {
   3534 		obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
   3535 		pcall(vis, L, 1, 0);
   3536 	}
   3537 	obj_ref_free(L, &win->view);
   3538 	obj_ref_free(L, win);
   3539 	lua_pop(L, 1);
   3540 }
   3541 
   3542 /**
   3543  * Window highlight.
   3544  * The window has been redrawn and the syntax highlighting needs to be performed.
   3545  * @function win_highlight
   3546  * @tparam Window win the window being redrawn
   3547  * @see style
   3548  */
   3549 static void vis_lua_win_highlight(Vis *vis, Win *win) {
   3550 	lua_State *L = vis->lua;
   3551 	if (!L)
   3552 		return;
   3553 	vis_lua_event_get(L, "win_highlight");
   3554 	if (lua_isfunction(L, -1)) {
   3555 		obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
   3556 		pcall(vis, L, 1, 0);
   3557 	}
   3558 	lua_pop(L, 1);
   3559 }
   3560 
   3561 /***
   3562  * Window status bar redraw.
   3563  * @function win_status
   3564  * @tparam Window win the affected window
   3565  * @see status
   3566  */
   3567 static void vis_lua_win_status(Vis *vis, Win *win) {
   3568 	lua_State *L = vis->lua;
   3569 	if (!L || win->file->internal) {
   3570 		window_status_update(vis, win);
   3571 		return;
   3572 	}
   3573 	vis_lua_event_get(L, "win_status");
   3574 	if (lua_isfunction(L, -1)) {
   3575 		obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
   3576 		pcall(vis, L, 1, 0);
   3577 	} else {
   3578 		window_status_update(vis, win);
   3579 	}
   3580 	lua_pop(L, 1);
   3581 }
   3582 
   3583 /***
   3584  * CSI command received from terminal.
   3585  * @function term_csi
   3586  * @param List of CSI parameters
   3587  */
   3588 static void vis_lua_term_csi(Vis *vis, const long *csi) {
   3589 	lua_State *L = vis->lua;
   3590 	if (!L)
   3591 		return;
   3592 	vis_lua_event_get(L, "term_csi");
   3593 	if (lua_isfunction(L, -1)) {
   3594 		int nargs = csi[1];
   3595 		lua_pushinteger(L, csi[0]);
   3596 		for (int i = 0; i < nargs; i++)
   3597 			lua_pushinteger(L, csi[2 + i]);
   3598 		pcall(vis, L, 1 + nargs, 0);
   3599 	}
   3600 	lua_pop(L, 1);
   3601 }
   3602 /***
   3603  * The response received from the process started via @{Vis:communicate}.
   3604  * @function process_response
   3605  * @tparam string name the name of process given to @{Vis:communicate}
   3606  * @tparam string response_type can be "STDOUT" or "STDERR" if new output was received in corresponding channel, "SIGNAL" if the process was terminated by a signal or "EXIT" when the process terminated normally
   3607  * @tparam int code the exit code number if response_type is "EXIT", or the signal number if response_type is "SIGNAL"
   3608  * @tparam string buffer the available content sent by the process
   3609  */
   3610 void vis_lua_process_response(Vis *vis, const char *name,
   3611                               char *buffer, size_t len, ResponseType rtype) {
   3612 	lua_State *L = vis->lua;
   3613 	if (!L) {
   3614 		return;
   3615 	}
   3616 	vis_lua_event_get(L, "process_response");
   3617 	if (lua_isfunction(L, -1)) {
   3618 		lua_pushstring(L, name);
   3619 		switch (rtype) {
   3620 		case STDOUT: lua_pushstring(L, "STDOUT"); break;
   3621 		case STDERR: lua_pushstring(L, "STDERR"); break;
   3622 		case SIGNAL: lua_pushstring(L, "SIGNAL"); break;
   3623 		case EXIT: lua_pushstring(L, "EXIT"); break;
   3624 		}
   3625 		switch (rtype) {
   3626 		case EXIT:
   3627 		case SIGNAL:
   3628 			lua_pushinteger(L, len);
   3629 			lua_pushnil(L);
   3630 			break;
   3631 		default:
   3632 			lua_pushnil(L);
   3633 			lua_pushlstring(L, buffer, len);
   3634 		}
   3635 		pcall(vis, L, 4, 0);
   3636 	}
   3637 	lua_pop(L, 1);
   3638 }
   3639 
   3640 /***
   3641  * Emitted immediately before the UI is drawn to the screen.
   3642  * Allows last-minute overrides to the styling of UI elements.
   3643  *
   3644  * *WARNING:* This is emitted every screen draw!
   3645  * Use sparingly and check for `nil` values!
   3646  * @function ui_draw
   3647  */
   3648 static void vis_lua_ui_draw(Vis *vis) {
   3649 	vis_lua_event_call(vis, "ui_draw");
   3650 }
   3651 
   3652 bool vis_event_emit(Vis *vis, enum VisEvents id, ...) {
   3653 	va_list ap;
   3654 	va_start(ap, id);
   3655 	bool ret = true;
   3656 
   3657 	switch (id) {
   3658 	case VIS_EVENT_INIT:
   3659 		vis_lua_init(vis);
   3660 		break;
   3661 	case VIS_EVENT_START:
   3662 		vis_lua_start(vis);
   3663 		break;
   3664 	case VIS_EVENT_FILE_OPEN:
   3665 	case VIS_EVENT_FILE_SAVE_PRE:
   3666 	case VIS_EVENT_FILE_SAVE_POST:
   3667 	case VIS_EVENT_FILE_CLOSE:
   3668 	{
   3669 		File *file = va_arg(ap, File*);
   3670 		if (file->internal)
   3671 			break;
   3672 		if (id == VIS_EVENT_FILE_OPEN) {
   3673 			vis_lua_file_open(vis, file);
   3674 		} else if (id == VIS_EVENT_FILE_SAVE_PRE) {
   3675 			const char *path = va_arg(ap, const char*);
   3676 			ret = vis_lua_file_save_pre(vis, file, path);
   3677 		} else if (id == VIS_EVENT_FILE_SAVE_POST) {
   3678 			const char *path = va_arg(ap, const char*);
   3679 			vis_lua_file_save_post(vis, file, path);
   3680 		} else if (id == VIS_EVENT_FILE_CLOSE) {
   3681 			vis_lua_file_close(vis, file);
   3682 		}
   3683 		break;
   3684 	}
   3685 	case VIS_EVENT_WIN_OPEN:
   3686 	case VIS_EVENT_WIN_CLOSE:
   3687 	case VIS_EVENT_WIN_HIGHLIGHT:
   3688 	case VIS_EVENT_WIN_STATUS:
   3689 	{
   3690 		Win *win = va_arg(ap, Win*);
   3691 		if (win->file->internal && id != VIS_EVENT_WIN_STATUS)
   3692 			break;
   3693 		if (id == VIS_EVENT_WIN_OPEN) {
   3694 			vis_lua_win_open(vis, win);
   3695 		} else if (id == VIS_EVENT_WIN_CLOSE) {
   3696 			vis_lua_win_close(vis, win);
   3697 		} else if (id == VIS_EVENT_WIN_HIGHLIGHT) {
   3698 			vis_lua_win_highlight(vis, win);
   3699 		} else if (id == VIS_EVENT_WIN_STATUS) {
   3700 			vis_lua_win_status(vis, win);
   3701 		}
   3702 		break;
   3703 	}
   3704 	case VIS_EVENT_QUIT:
   3705 		vis_lua_quit(vis);
   3706 		break;
   3707 	case VIS_EVENT_TERM_CSI:
   3708 		vis_lua_term_csi(vis, va_arg(ap, const long *));
   3709 		break;
   3710 	case VIS_EVENT_UI_DRAW:
   3711 		vis_lua_ui_draw(vis);
   3712 		break;
   3713 	}
   3714 
   3715 	va_end(ap);
   3716 	return ret;
   3717 }
   3718 
   3719 #endif