vis-lua: expose current input_queue content
[vis.git] / vis-lua.c
blob0031421ab61e3709d1fdc021ee1047ed9b20913a
1 /***
2 * Lua Extension API for the [Vis Editor](https://github.com/martanne/vis).
4 * *WARNING:* there is no stability guarantee at this time, the API might
5 * change without notice!
7 * This document might be out of date, run `make luadoc` to regenerate it.
9 * @module vis
10 * @author Marc André Tanner
11 * @license ISC
12 * @release RELEASE
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>
24 #include "vis-lua.h"
25 #include "vis-core.h"
26 #include "text-motions.h"
27 #include "util.h"
29 #ifndef VIS_PATH
30 #define VIS_PATH "/usr/local/share/vis"
31 #endif
33 #define VIS_LUA_TYPE_VIS "vis"
34 #define VIS_LUA_TYPE_FILE "file"
35 #define VIS_LUA_TYPE_TEXT "text"
36 #define VIS_LUA_TYPE_MARK "mark"
37 #define VIS_LUA_TYPE_MARKS "marks"
38 #define VIS_LUA_TYPE_WINDOW "window"
39 #define VIS_LUA_TYPE_SELECTION "selection"
40 #define VIS_LUA_TYPE_SELECTIONS "selections"
41 #define VIS_LUA_TYPE_UI "ui"
42 #define VIS_LUA_TYPE_REGISTERS "registers"
43 #define VIS_LUA_TYPE_KEYACTION "keyaction"
45 #ifndef DEBUG_LUA
46 #define DEBUG_LUA 0
47 #endif
49 #if DEBUG_LUA
50 #define debug(...) do { printf(__VA_ARGS__); fflush(stdout); } while (0)
51 #else
52 #define debug(...) do { } while (0)
53 #endif
55 static void window_status_update(Vis *vis, Win *win) {
56 char left_parts[4][255] = { "", "", "", "" };
57 char right_parts[4][32] = { "", "", "", "" };
58 char left[sizeof(left_parts)+LENGTH(left_parts)*8];
59 char right[sizeof(right_parts)+LENGTH(right_parts)*8];
60 char status[sizeof(left)+sizeof(right)+1];
61 size_t left_count = 0;
62 size_t right_count = 0;
64 View *view = win->view;
65 File *file = win->file;
66 Text *txt = file->text;
67 int width = vis_window_width_get(win);
68 enum UiOption options = view_options_get(view);
69 bool focused = vis->win == win;
70 const char *filename = file_name_get(file);
71 const char *mode = vis->mode->status;
73 if (focused && mode)
74 strcpy(left_parts[left_count++], mode);
76 snprintf(left_parts[left_count], sizeof(left_parts[left_count])-1, "%s%s%s",
77 filename ? filename : "[No Name]",
78 text_modified(txt) ? " [+]" : "",
79 vis_macro_recording(vis) ? " @": "");
80 left_count++;
82 int sel_count = view_selections_count(view);
83 if (sel_count > 1) {
84 Selection *s = view_selections_primary_get(view);
85 int sel_number = view_selections_number(s) + 1;
86 snprintf(right_parts[right_count], sizeof(right_parts[right_count])-1,
87 "%d/%d", sel_number, sel_count);
88 right_count++;
91 size_t size = text_size(txt);
92 size_t pos = view_cursor_get(view);
93 size_t percent = 0;
94 if (size > 0) {
95 double tmp = ((double)pos/(double)size)*100;
96 percent = (size_t)(tmp+1);
98 snprintf(right_parts[right_count], sizeof(right_parts[right_count])-1,
99 "%zu%%", percent);
100 right_count++;
102 if (!(options & UI_OPTION_LARGE_FILE)) {
103 Selection *sel = view_selections_primary_get(win->view);
104 size_t line = view_cursors_line(sel);
105 size_t col = view_cursors_col(sel);
106 if (col > UI_LARGE_FILE_LINE_SIZE) {
107 options |= UI_OPTION_LARGE_FILE;
108 view_options_set(win->view, options);
110 snprintf(right_parts[right_count], sizeof(right_parts[right_count])-1,
111 "%zu, %zu", line, col);
112 right_count++;
115 int left_len = snprintf(left, sizeof(left)-1, " %s%s%s%s%s%s%s",
116 left_parts[0],
117 left_parts[1][0] ? " » " : "",
118 left_parts[1],
119 left_parts[2][0] ? " » " : "",
120 left_parts[2],
121 left_parts[3][0] ? " » " : "",
122 left_parts[3]);
124 int right_len = snprintf(right, sizeof(right)-1, "%s%s%s%s%s%s%s ",
125 right_parts[0],
126 right_parts[1][0] ? " « " : "",
127 right_parts[1],
128 right_parts[2][0] ? " « " : "",
129 right_parts[2],
130 right_parts[3][0] ? " « " : "",
131 right_parts[3]);
133 if (left_len < 0 || right_len < 0)
134 return;
135 int left_width = text_string_width(left, left_len);
136 int right_width = text_string_width(right, right_len);
138 int spaces = width - left_width - right_width;
139 if (spaces < 1)
140 spaces = 1;
142 snprintf(status, sizeof(status)-1, "%s%*s%s", left, spaces, " ", right);
143 vis_window_status(win, status);
146 #if !CONFIG_LUA
148 bool vis_lua_path_add(Vis *vis, const char *path) { return true; }
149 bool vis_lua_paths_get(Vis *vis, char **lpath, char **cpath) { return false; }
150 void vis_lua_init(Vis *vis) { }
151 void vis_lua_start(Vis *vis) { }
152 void vis_lua_quit(Vis *vis) { }
153 void vis_lua_file_open(Vis *vis, File *file) { }
154 bool vis_lua_file_save_pre(Vis *vis, File *file, const char *path) { return true; }
155 void vis_lua_file_save_post(Vis *vis, File *file, const char *path) { }
156 void vis_lua_file_close(Vis *vis, File *file) { }
157 void vis_lua_win_open(Vis *vis, Win *win) { }
158 void vis_lua_win_close(Vis *vis, Win *win) { }
159 void vis_lua_win_highlight(Vis *vis, Win *win) { }
160 void vis_lua_win_status(Vis *vis, Win *win) { window_status_update(vis, win); }
162 #else
164 #if DEBUG_LUA
165 static void stack_dump_entry(lua_State *L, int i) {
166 int t = lua_type(L, i);
167 switch (t) {
168 case LUA_TNIL:
169 printf("nil");
170 break;
171 case LUA_TBOOLEAN:
172 printf(lua_toboolean(L, i) ? "true" : "false");
173 break;
174 case LUA_TLIGHTUSERDATA:
175 printf("lightuserdata(%p)", lua_touserdata(L, i));
176 break;
177 case LUA_TNUMBER:
178 printf("%g", lua_tonumber(L, i));
179 break;
180 case LUA_TSTRING:
181 printf("`%s'", lua_tostring(L, i));
182 break;
183 case LUA_TTABLE:
184 printf("table[");
185 lua_pushnil(L); /* first key */
186 while (lua_next(L, i > 0 ? i : i - 1)) {
187 stack_dump_entry(L, -2);
188 printf("=");
189 stack_dump_entry(L, -1);
190 printf(",");
191 lua_pop(L, 1); /* remove value, keep key */
193 printf("]");
194 break;
195 case LUA_TUSERDATA:
196 printf("userdata(%p)", lua_touserdata(L, i));
197 break;
198 default: /* other values */
199 printf("%s", lua_typename(L, t));
200 break;
204 static void stack_dump(lua_State *L, const char *format, ...) {
205 va_list ap;
206 va_start(ap, format);
207 vprintf(format, ap);
208 va_end(ap);
209 int top = lua_gettop(L);
210 for (int i = 1; i <= top; i++) {
211 printf("%d: ", i);
212 stack_dump_entry(L, i);
213 printf("\n");
215 printf("\n\n");
216 fflush(stdout);
219 #endif
221 static int panic_handler(lua_State *L) {
222 void *ud = NULL;
223 lua_getallocf(L, &ud);
224 if (ud) {
225 Vis *vis = ud;
226 vis->lua = NULL;
227 const char *msg = NULL;
228 if (lua_type(L, -1) == LUA_TSTRING)
229 msg = lua_tostring(L, -1);
230 vis_info_show(vis, "Fatal Lua error: %s", msg ? msg : "unknown reason");
231 lua_close(L);
232 if (vis->running)
233 siglongjmp(vis->sigbus_jmpbuf, 1);
235 return 0;
238 static int error_handler(lua_State *L) {
239 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
240 if (vis->errorhandler)
241 return 1;
242 vis->errorhandler = true;
243 size_t len;
244 const char *msg = lua_tostring(L, 1);
245 if (msg)
246 luaL_traceback(L, L, msg, 1);
247 msg = lua_tolstring(L, 1, &len);
248 vis_message_show(vis, msg);
249 vis->errorhandler = false;
250 return 1;
253 static int pcall(Vis *vis, lua_State *L, int nargs, int nresults) {
254 /* insert a custom error function below all arguments */
255 int msgh = lua_gettop(L) - nargs;
256 lua_pushlightuserdata(L, vis);
257 lua_pushcclosure(L, error_handler, 1);
258 lua_insert(L, msgh);
259 int ret = lua_pcall(L, nargs, nresults, msgh);
260 lua_remove(L, msgh);
261 return ret;
264 /* expects a lua function at stack position `narg` and stores a
265 * reference to it in the registry. The return value can be used
266 * to look it up.
268 * registry["vis.functions"][(void*)(function)] = function
270 static const void *func_ref_new(lua_State *L, int narg) {
271 const void *addr = lua_topointer(L, narg);
272 if (!lua_isfunction(L, narg) || !addr)
273 luaL_argerror(L, narg, "function expected");
274 lua_getfield(L, LUA_REGISTRYINDEX, "vis.functions");
275 lua_pushlightuserdata(L, (void*)addr);
276 lua_pushvalue(L, narg);
277 lua_settable(L, -3);
278 lua_pop(L, 1);
279 return addr;
282 /* retrieve function from registry and place it at the top of the stack */
283 static bool func_ref_get(lua_State *L, const void *addr) {
284 if (!addr)
285 return false;
286 lua_getfield(L, LUA_REGISTRYINDEX, "vis.functions");
287 lua_pushlightuserdata(L, (void*)addr);
288 lua_gettable(L, -2);
289 lua_remove(L, -2);
290 if (!lua_isfunction(L, -1)) {
291 lua_pop(L, 1);
292 return false;
294 return true;
297 /* creates a new metatable for a given type and stores a mapping:
299 * registry["vis.types"][metatable] = type
301 * leaves the metatable at the top of the stack.
303 static void obj_type_new(lua_State *L, const char *type) {
304 luaL_newmetatable(L, type);
305 lua_getglobal(L, "vis");
306 if (!lua_isnil(L, -1)) {
307 lua_getfield(L, -1, "types");
308 lua_pushvalue(L, -3);
309 lua_setfield(L, -2, type);
310 lua_pop(L, 1);
312 lua_pop(L, 1);
313 lua_getfield(L, LUA_REGISTRYINDEX, "vis.types");
314 lua_pushvalue(L, -2);
315 lua_pushstring(L, type);
316 lua_settable(L, -3);
317 lua_pop(L, 1);
320 /* get type of userdatum at the top of the stack:
322 * return registry["vis.types"][getmetatable(userdata)]
324 const char *obj_type_get(lua_State *L) {
325 if (lua_isnil(L, -1))
326 return "nil";
327 lua_getfield(L, LUA_REGISTRYINDEX, "vis.types");
328 lua_getmetatable(L, -2);
329 lua_gettable(L, -2);
330 // XXX: in theory string might become invalid when poped from stack
331 const char *type = lua_tostring(L, -1);
332 lua_pop(L, 2);
333 return type;
336 static void *obj_new(lua_State *L, size_t size, const char *type) {
337 void *obj = lua_newuserdata(L, size);
338 luaL_getmetatable(L, type);
339 lua_setmetatable(L, -2);
340 lua_newtable(L);
341 lua_setuservalue(L, -2);
342 return obj;
345 /* returns registry["vis.objects"][addr] if it is of correct type */
346 static void *obj_ref_get(lua_State *L, void *addr, const char *type) {
347 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
348 lua_pushlightuserdata(L, addr);
349 lua_gettable(L, -2);
350 lua_remove(L, -2);
351 if (lua_isnil(L, -1)) {
352 debug("get: vis.objects[%p] = nil\n", addr);
353 lua_pop(L, 1);
354 return NULL;
356 if (DEBUG_LUA) {
357 const char *actual_type = obj_type_get(L);
358 if (strcmp(type, actual_type) != 0)
359 debug("get: vis.objects[%p] = %s (BUG: expected %s)\n", addr, actual_type, type);
360 void **handle = luaL_checkudata(L, -1, type);
361 if (!handle)
362 debug("get: vis.objects[%p] = %s (BUG: invalid handle)\n", addr, type);
363 else if (*handle != addr)
364 debug("get: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr, type, *handle);
366 return luaL_checkudata(L, -1, type);
369 /* expects a userdatum at the top of the stack and sets
371 * registry["vis.objects"][addr] = userdata
373 static void obj_ref_set(lua_State *L, void *addr) {
374 //debug("set: vis.objects[%p] = %s\n", addr, obj_type_get(L));
375 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
376 lua_pushlightuserdata(L, addr);
377 lua_pushvalue(L, -3);
378 lua_settable(L, -3);
379 lua_pop(L, 1);
382 /* invalidates an object reference
384 * registry["vis.objects"][addr] = nil
386 static void obj_ref_free(lua_State *L, void *addr) {
387 if (DEBUG_LUA) {
388 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
389 lua_pushlightuserdata(L, addr);
390 lua_gettable(L, -2);
391 lua_remove(L, -2);
392 if (lua_isnil(L, -1))
393 debug("free-unused: %p\n", addr);
394 else
395 debug("free: vis.objects[%p] = %s\n", addr, obj_type_get(L));
396 lua_pop(L, 1);
398 lua_pushnil(L);
399 obj_ref_set(L, addr);
402 /* creates a new object reference of given type if it does not already exist in the registry:
404 * if (registry["vis.types"][metatable(registry["vis.objects"][addr])] != type) {
405 * // XXX: should not happen
406 * registry["vis.objects"][addr] = new_obj(addr, type)
408 * return registry["vis.objects"][addr];
410 static void *obj_ref_new(lua_State *L, void *addr, const char *type) {
411 if (!addr) {
412 lua_pushnil(L);
413 return NULL;
415 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
416 lua_pushlightuserdata(L, addr);
417 lua_gettable(L, -2);
418 lua_remove(L, -2);
419 const char *old_type = obj_type_get(L);
420 if (strcmp(type, old_type) == 0) {
421 debug("new: vis.objects[%p] = %s (returning existing object)\n", addr, old_type);
422 void **handle = luaL_checkudata(L, -1, type);
423 if (!handle)
424 debug("new: vis.objects[%p] = %s (BUG: invalid handle)\n", addr, old_type);
425 else if (*handle != addr)
426 debug("new: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr, old_type, *handle);
427 return addr;
429 if (!lua_isnil(L, -1))
430 debug("new: vis.objects[%p] = %s (WARNING: changing object type from %s)\n", addr, type, old_type);
431 else
432 debug("new: vis.objects[%p] = %s (creating new object)\n", addr, type);
433 lua_pop(L, 1);
434 void **handle = obj_new(L, sizeof(addr), type);
435 obj_ref_set(L, addr);
436 *handle = addr;
437 return addr;
440 /* retrieve object stored in reference at stack location `idx' */
441 static void *obj_ref_check_get(lua_State *L, int idx, const char *type) {
442 void **addr = luaL_checkudata(L, idx, type);
443 if (!obj_ref_get(L, *addr, type))
444 return NULL;
445 return *addr;
448 /* (type) check validity of object reference at stack location `idx' */
449 static void *obj_ref_check(lua_State *L, int idx, const char *type) {
450 void *obj = obj_ref_check_get(L, idx, type);
451 if (obj)
452 lua_pop(L, 1);
453 else
454 luaL_argerror(L, idx, "invalid object reference");
455 return obj;
458 static void *obj_ref_check_containerof(lua_State *L, int idx, const char *type, size_t offset) {
459 void *obj = obj_ref_check(L, idx, type);
460 return obj ? ((char*)obj-offset) : obj;
463 static void *obj_lightref_new(lua_State *L, void *addr, const char *type) {
464 if (!addr)
465 return NULL;
466 void **handle = obj_new(L, sizeof(addr), type);
467 *handle = addr;
468 return addr;
471 static void *obj_lightref_check(lua_State *L, int idx, const char *type) {
472 void **addr = luaL_checkudata(L, idx, type);
473 return *addr;
476 static int index_common(lua_State *L) {
477 lua_getmetatable(L, 1);
478 lua_pushvalue(L, 2);
479 lua_gettable(L, -2);
480 if (lua_isnil(L, -1)) {
481 lua_getuservalue(L, 1);
482 lua_pushvalue(L, 2);
483 lua_gettable(L, -2);
485 return 1;
488 static int newindex_common(lua_State *L) {
489 lua_getuservalue(L, 1);
490 lua_pushvalue(L, 2);
491 lua_pushvalue(L, 3);
492 lua_settable(L, -3);
493 return 0;
496 static size_t getpos(lua_State *L, int narg) {
497 return lua_tounsigned(L, narg);
500 static size_t checkpos(lua_State *L, int narg) {
501 lua_Number n = luaL_checknumber(L, narg);
502 if (n >= 0 && n <= SIZE_MAX && n == (size_t)n)
503 return n;
504 return luaL_argerror(L, narg, "expected position, got number");
507 static void pushpos(lua_State *L, size_t pos) {
508 if (pos == EPOS)
509 lua_pushnil(L);
510 else
511 lua_pushunsigned(L, pos);
514 static void pushrange(lua_State *L, Filerange *r) {
515 if (!r || !text_range_valid(r)) {
516 lua_pushnil(L);
517 return;
519 lua_createtable(L, 0, 2);
520 lua_pushstring(L, "start");
521 lua_pushunsigned(L, r->start);
522 lua_settable(L, -3);
523 lua_pushstring(L, "finish");
524 lua_pushunsigned(L, r->end);
525 lua_settable(L, -3);
528 static Filerange getrange(lua_State *L, int index) {
529 Filerange range = text_range_empty();
530 if (lua_istable(L, index)) {
531 lua_getfield(L, index, "start");
532 range.start = checkpos(L, -1);
533 lua_pop(L, 1);
534 lua_getfield(L, index, "finish");
535 range.end = checkpos(L, -1);
536 lua_pop(L, 1);
537 } else {
538 range.start = checkpos(L, index);
539 range.end = range.start + checkpos(L, index+1);
541 return range;
544 static const char *keymapping(Vis *vis, const char *keys, const Arg *arg) {
545 lua_State *L = vis->lua;
546 if (!func_ref_get(L, arg->v))
547 return keys;
548 lua_pushstring(L, keys);
549 if (pcall(vis, L, 1, 1) != 0)
550 return keys;
551 if (lua_type(L, -1) != LUA_TNUMBER)
552 return keys; /* invalid or no return value, assume zero */
553 lua_Number number = lua_tonumber(L, -1);
554 lua_Integer integer = lua_tointeger(L, -1);
555 if (number != integer)
556 return keys;
557 if (integer < 0)
558 return NULL; /* need more input */
559 size_t len = integer;
560 size_t max = strlen(keys);
561 return (len <= max) ? keys+len : keys;
564 /***
565 * The main editor object.
566 * @type Vis
569 /***
570 * Version information.
571 * @tfield string VERSION
572 * version information in `git describe` format, same as reported by `vis -v`.
574 /***
575 * Lua API object types
576 * @field types meta tables of userdata objects used for type checking
577 * @local
579 /***
580 * User interface.
581 * @tfield Ui ui the user interface being used
583 /***
584 * Mode constants.
585 * @tfield modes modes
587 /***
588 * Events.
589 * @tfield events events
591 /***
592 * Registers.
593 * @field registers array to access the register by single letter name
595 /***
596 * Scintillua lexer module.
597 * @field lexers might be `nil` if module is not found
599 /***
600 * LPeg lexer module.
601 * @field lpeg might be `nil` if module is not found
603 /***
604 * Current count.
605 * @tfield int count the specified count for the current command or `nil` if none was given
608 /***
609 * Create an iterator over all windows.
610 * @function windows
611 * @return the new iterator
612 * @see win
613 * @usage
614 * for win in vis:windows() do
615 * -- do something with win
616 * end
618 static int windows_iter(lua_State *L);
619 static int windows(lua_State *L) {
620 Vis *vis = obj_ref_check(L, 1, "vis");
621 Win **handle = lua_newuserdata(L, sizeof *handle), *next;
622 for (next = vis->windows; next && next->file->internal; next = next->next);
623 *handle = next;
624 lua_pushcclosure(L, windows_iter, 1);
625 return 1;
628 static int windows_iter(lua_State *L) {
629 Win **handle = lua_touserdata(L, lua_upvalueindex(1));
630 if (!*handle)
631 return 0;
632 Win *win = obj_ref_new(L, *handle, VIS_LUA_TYPE_WINDOW), *next;
633 if (win) {
634 for (next = win->next; next && next->file->internal; next = next->next);
635 *handle = next;
637 return 1;
640 /***
641 * Create an iterator over all files.
642 * @function files
643 * @return the new iterator
644 * @usage
645 * for file in vis:files() do
646 * -- do something with file
647 * end
649 static int files_iter(lua_State *L);
650 static int files(lua_State *L) {
651 Vis *vis = obj_ref_check(L, 1, "vis");
652 File **handle = lua_newuserdata(L, sizeof *handle);
653 *handle = vis->files;
654 lua_pushcclosure(L, files_iter, 1);
655 return 1;
658 static int files_iter(lua_State *L) {
659 File **handle = lua_touserdata(L, lua_upvalueindex(1));
660 if (!*handle)
661 return 0;
662 File *file = obj_ref_new(L, *handle, VIS_LUA_TYPE_FILE);
663 if (file)
664 *handle = file->next;
665 return 1;
668 /***
669 * Create an iterator over all mark names.
670 * @function mark_names
671 * @return the new iterator
672 * @usage
673 * local marks = vis.win.marks
674 * for name in vis:mark_names() do
675 * local mark = marks[name]
676 * for i = 1, #mark do
677 * -- do somthing with: name, mark[i].start, mark[i].finish
678 * end
679 * end
681 static int mark_names_iter(lua_State *L);
682 static int mark_names(lua_State *L) {
683 enum VisMark *handle = lua_newuserdata(L, sizeof *handle);
684 *handle = 0;
685 lua_pushcclosure(L, mark_names_iter, 1);
686 return 1;
689 static int mark_names_iter(lua_State *L) {
690 char mark = '\0';
691 enum VisMark *handle = lua_touserdata(L, lua_upvalueindex(1));
692 if (*handle < LENGTH(vis_marks))
693 mark = vis_marks[*handle].name;
694 else if (VIS_MARK_a <= *handle && *handle <= VIS_MARK_z)
695 mark = 'a' + *handle - VIS_MARK_a;
696 if (mark) {
697 char name[2] = { mark, '\0' };
698 lua_pushstring(L, name);
699 (*handle)++;
700 return 1;
702 return 0;
705 /***
706 * Create an iterator over all register names.
707 * @function register_names
708 * @return the new iterator
709 * @usage
710 * for name in vis:register_names() do
711 * local reg = vis.registers[name]
712 * for i = 1, #reg do
713 * -- do something with register value reg[i]
714 * end
715 * end
717 static int register_names_iter(lua_State *L);
718 static int register_names(lua_State *L) {
719 enum VisRegister *handle = lua_newuserdata(L, sizeof *handle);
720 *handle = 0;
721 lua_pushcclosure(L, register_names_iter, 1);
722 return 1;
725 static int register_names_iter(lua_State *L) {
726 char reg = '\0';
727 enum VisRegister *handle = lua_touserdata(L, lua_upvalueindex(1));
728 if (*handle < LENGTH(vis_registers))
729 reg = vis_registers[*handle].name;
730 else if (VIS_REG_a <= *handle && *handle <= VIS_REG_z)
731 reg = 'a' + *handle - VIS_REG_a;
732 if (reg) {
733 char name[2] = { reg, '\0' };
734 lua_pushstring(L, name);
735 (*handle)++;
736 return 1;
738 return 0;
741 /***
742 * Execute a `:`-command.
743 * @function command
744 * @tparam string command the command to execute
745 * @treturn bool whether the command succeeded
746 * @usage
747 * vis:command("set number")
749 static int command(lua_State *L) {
750 Vis *vis = obj_ref_check(L, 1, "vis");
751 const char *cmd = luaL_checkstring(L, 2);
752 bool ret = vis_cmd(vis, cmd);
753 lua_pushboolean(L, ret);
754 return 1;
757 /***
758 * Display a short message.
760 * The single line message will be displayed at the bottom of
761 * the scren and automatically hidden once a key is pressed.
763 * @function info
764 * @tparam string message the message to display
766 static int info(lua_State *L) {
767 Vis *vis = obj_ref_check(L, 1, "vis");
768 const char *msg = luaL_checkstring(L, 2);
769 vis_info_show(vis, "%s", msg);
770 return 0;
773 /***
774 * Display a multi line message.
776 * Opens a new window and displays an arbitrarily long message.
778 * @function message
779 * @tparam string message the message to display
781 static int message(lua_State *L) {
782 Vis *vis = obj_ref_check(L, 1, "vis");
783 const char *msg = luaL_checkstring(L, 2);
784 vis_message_show(vis, msg);
785 return 0;
788 /***
789 * Register a Lua function as key action.
790 * @function action_register
791 * @tparam string name the name of the action, can be referred to in key bindings as `<name>` pseudo key
792 * @tparam Function func the lua function implementing the key action (see @{keyhandler})
793 * @tparam[opt] string help the single line help text as displayed in `:help`
794 * @treturn KeyAction action the registered key action
795 * @see Vis:map
796 * @see Window:map
798 static int action_register(lua_State *L) {
799 Vis *vis = obj_ref_check(L, 1, "vis");
800 const char *name = luaL_checkstring(L, 2);
801 const void *func = func_ref_new(L, 3);
802 const char *help = luaL_optstring(L, 4, NULL);
803 KeyAction *action = vis_action_new(vis, name, help, keymapping, (Arg){ .v = func });
804 if (!action)
805 goto err;
806 if (!vis_action_register(vis, action))
807 goto err;
808 obj_ref_new(L, action, VIS_LUA_TYPE_KEYACTION);
809 return 1;
810 err:
811 vis_action_free(vis, action);
812 lua_pushnil(L);
813 return 1;
816 static int keymap(lua_State *L, Vis *vis, Win *win) {
817 int mode = luaL_checkint(L, 2);
818 const char *key = luaL_checkstring(L, 3);
819 const char *help = luaL_optstring(L, 5, NULL);
820 KeyBinding *binding = vis_binding_new(vis);
821 if (!binding)
822 goto err;
823 if (lua_isstring(L, 4)) {
824 const char *alias = luaL_checkstring(L, 4);
825 if (!(binding->alias = strdup(alias)))
826 goto err;
827 } else if (lua_isfunction(L, 4)) {
828 const void *func = func_ref_new(L, 4);
829 if (!(binding->action = vis_action_new(vis, NULL, help, keymapping, (Arg){ .v = func })))
830 goto err;
831 } else if (lua_isuserdata(L, 4)) {
832 binding->action = obj_ref_check(L, 4, VIS_LUA_TYPE_KEYACTION);
835 if (win) {
836 if (!vis_window_mode_map(win, mode, true, key, binding))
837 goto err;
838 } else {
839 if (!vis_mode_map(vis, mode, true, key, binding))
840 goto err;
843 lua_pushboolean(L, true);
844 return 1;
845 err:
846 vis_binding_free(vis, binding);
847 lua_pushboolean(L, false);
848 return 1;
851 /***
852 * Map a key to a Lua function.
854 * Creates a new key mapping in a given mode.
856 * @function map
857 * @tparam int mode the mode to which the mapping should be added
858 * @tparam string key the key to map
859 * @tparam function func the Lua function to handle the key mapping (see @{keyhandler})
860 * @tparam[opt] string help the single line help text as displayed in `:help`
861 * @treturn bool whether the mapping was successfully established
862 * @see Window:map
863 * @usage
864 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
865 * if #keys < 2 then
866 * return -1 -- need more input
867 * end
868 * local digraph = keys:sub(1, 2)
869 * if digraph == "l*" then
870 * vis:feedkeys('λ')
871 * return 2 -- consume 2 bytes of input
872 * end
873 * end, "Insert digraph")
875 /***
876 * Setup a key alias.
878 * This is equivalent to `vis:command('map! mode key alias')`.
880 * Mappings are always recursive!
881 * @function map
882 * @tparam int mode the mode to which the mapping should be added
883 * @tparam string key the key to map
884 * @tparam string alias the key to map to
885 * @treturn bool whether the mapping was successfully established
886 * @see Window:map
887 * @usage
888 * vis:map(vis.modes.NORMAL, "j", "k")
890 /***
891 * Map a key to a key action.
893 * @function map
894 * @tparam int mode the mode to which the mapping should be added
895 * @tparam string key the key to map
896 * @param action the action to map
897 * @treturn bool whether the mapping was successfully established
898 * @see Window:map
899 * @usage
900 * local action = vis:action_register("info", function()
901 * vis:info("Mapping works!")
902 * end, "Info message help text")
903 * vis:map(vis.modes.NORMAL, "gh", action)
904 * vis:map(vis.modes.NORMAL, "gl", action)
906 static int map(lua_State *L) {
907 Vis *vis = obj_ref_check(L, 1, "vis");
908 return keymap(L, vis, NULL);
911 /***
912 * Unmap a global key binding.
914 * @function unmap
915 * @tparam int mode the mode from which the mapping should be removed
916 * @tparam string key the mapping to remove
917 * @treturn bool whether the mapping was successfully removed
918 * @see Window:unmap
920 static int keyunmap(lua_State *L, Vis *vis, Win *win) {
921 enum VisMode mode = luaL_checkint(L, 2);
922 const char *key = luaL_checkstring(L, 3);
923 bool ret;
924 if (!win)
925 ret = vis_mode_unmap(vis, mode, key);
926 else
927 ret = vis_window_mode_unmap(win, mode, key);
928 lua_pushboolean(L, ret);
929 return 1;
932 static int unmap(lua_State *L) {
933 Vis *vis = obj_ref_check(L, 1, "vis");
934 return keyunmap(L, vis, NULL);
937 /***
938 * Get all currently active mappings of a mode.
940 * @function mappings
941 * @tparam int mode the mode to query
942 * @treturn table the active mappings and their associated help texts
943 * @usage
944 * local bindings = vis:mappings(vis.modes.NORMAL)
945 * for key, help in pairs(bindings) do
946 * -- do something
947 * end
948 * @see Vis:map
950 static bool binding_collect(const char *key, void *value, void *ctx) {
951 lua_State *L = ctx;
952 KeyBinding *binding = value;
953 lua_getfield(L, -1, key);
954 bool new = lua_isnil(L, -1);
955 lua_pop(L, 1);
956 if (new) {
957 const char *help = binding->alias ? binding->alias : VIS_HELP_USE(binding->action->help);
958 lua_pushstring(L, help ? help : "");
959 lua_setfield(L, -2, key);
961 return true;
964 static int mappings(lua_State *L) {
965 Vis *vis = obj_ref_check(L, 1, "vis");
966 lua_newtable(L);
967 for (Mode *mode = mode_get(vis, luaL_checkint(L, 2)); mode; mode = mode->parent) {
968 if (!mode->bindings)
969 continue;
970 map_iterate(mode->bindings, binding_collect, vis->lua);
972 return 1;
975 /***
976 * Execute a motion.
978 * @function motion
979 * @tparam int id the id of the motion to execute
980 * @treturn bool whether the id was valid
981 * @local
983 static int motion(lua_State *L) {
984 Vis *vis = obj_ref_check(L, 1, "vis");
985 enum VisMotion id = luaL_checkunsigned(L, 2);
986 // TODO handle var args?
987 lua_pushboolean(L, vis && vis_motion(vis, id));
988 return 1;
991 static size_t motion_lua(Vis *vis, Win *win, void *data, size_t pos) {
992 lua_State *L = vis->lua;
993 if (!L || !func_ref_get(L, data) || !obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW))
994 return EPOS;
996 lua_pushunsigned(L, pos);
997 if (pcall(vis, L, 2, 1) != 0)
998 return EPOS;
999 return getpos(L, -1);
1002 /***
1003 * Register a custom motion.
1005 * @function motion_register
1006 * @tparam function motion the Lua function implementing the motion
1007 * @treturn int the associated motion id, or `-1` on failure
1008 * @see motion, motion_new
1009 * @local
1010 * @usage
1011 * -- custom motion advancing to the next byte
1012 * local id = vis:motion_register(function(win, pos)
1013 * return pos+1
1014 * end)
1016 static int motion_register(lua_State *L) {
1017 Vis *vis = obj_ref_check(L, 1, "vis");
1018 const void *func = func_ref_new(L, 2);
1019 int id = vis_motion_register(vis, (void*)func, motion_lua);
1020 lua_pushinteger(L, id);
1021 return 1;
1024 /***
1025 * Execute an operator.
1027 * @function operator
1028 * @tparam int id the id of the operator to execute
1029 * @treturn bool whether the id was valid
1030 * @local
1032 static int operator(lua_State *L) {
1033 Vis *vis = obj_ref_check(L, 1, "vis");
1034 enum VisOperator id = luaL_checkunsigned(L, 2);
1035 // TODO handle var args?
1036 lua_pushboolean(L, vis && vis_operator(vis, id));
1037 return 1;
1040 static size_t operator_lua(Vis *vis, Text *text, OperatorContext *c) {
1041 lua_State *L = vis->lua;
1042 if (!L || !func_ref_get(L, c->context))
1043 return EPOS;
1044 File *file = vis->files;
1045 while (file && (file->internal || file->text != text))
1046 file = file->next;
1047 if (!file || !obj_ref_new(L, file, VIS_LUA_TYPE_FILE))
1048 return EPOS;
1049 pushrange(L, &c->range);
1050 pushpos(L, c->pos);
1051 if (pcall(vis, L, 3, 1) != 0)
1052 return EPOS;
1053 return getpos(L, -1);
1056 /***
1057 * Register a custom operator.
1059 * @function operator_register
1060 * @tparam function operator the Lua function implementing the operator
1061 * @treturn int the associated operator id, or `-1` on failure
1062 * @see operator, operator_new
1063 * @local
1064 * @usage
1065 * -- custom operator replacing every 'a' with 'b'
1066 * local id = vis:operator_register(function(file, range, pos)
1067 * local data = file:content(range)
1068 * data = data:gsub("a", "b")
1069 * file:delete(range)
1070 * file:insert(range.start, data)
1071 * return range.start -- new cursor location
1072 * end)
1074 static int operator_register(lua_State *L) {
1075 Vis *vis = obj_ref_check(L, 1, "vis");
1076 const void *func = func_ref_new(L, 2);
1077 int id = vis_operator_register(vis, operator_lua, (void*)func);
1078 lua_pushinteger(L, id);
1079 return 1;
1082 /***
1083 * Execute a text object.
1085 * @function textobject
1086 * @tparam int id the id of the text object to execute
1087 * @treturn bool whether the id was valid
1088 * @see textobject_register, textobject_new
1089 * @local
1091 static int textobject(lua_State *L) {
1092 Vis *vis = obj_ref_check(L, 1, "vis");
1093 enum VisTextObject id = luaL_checkunsigned(L, 2);
1094 lua_pushboolean(L, vis_textobject(vis, id));
1095 return 1;
1098 static Filerange textobject_lua(Vis *vis, Win *win, void *data, size_t pos) {
1099 lua_State *L = vis->lua;
1100 if (!L || !func_ref_get(L, data) || !obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW))
1101 return text_range_empty();
1102 lua_pushunsigned(L, pos);
1103 if (pcall(vis, L, 2, 2) != 0 || lua_isnil(L, -1))
1104 return text_range_empty();
1105 return text_range_new(getpos(L, -2), getpos(L, -1));
1108 /***
1109 * Register a custom text object.
1111 * @function textobject_register
1112 * @tparam function textobject the Lua function implementing the text object
1113 * @treturn int the associated text object id, or `-1` on failure
1114 * @see textobject, textobject_new
1115 * @local
1116 * @usage
1117 * -- custom text object covering the next byte
1118 * local id = vis:textobject_register(function(win, pos)
1119 * return pos, pos+1
1120 * end)
1122 static int textobject_register(lua_State *L) {
1123 Vis *vis = obj_ref_check(L, 1, "vis");
1124 const void *func = func_ref_new(L, 2);
1125 int id = vis_textobject_register(vis, 0, (void*)func, textobject_lua);
1126 lua_pushinteger(L, id);
1127 return 1;
1130 static bool option_lua(Vis *vis, Win *win, void *context, bool toggle,
1131 enum VisOption flags, const char *name, Arg *value) {
1132 lua_State *L = vis->lua;
1133 if (!L || !func_ref_get(L, context))
1134 return false;
1135 if (flags & VIS_OPTION_TYPE_BOOL)
1136 lua_pushboolean(L, value->b);
1137 else if (flags & VIS_OPTION_TYPE_STRING)
1138 lua_pushstring(L, value->s);
1139 else if (flags & VIS_OPTION_TYPE_NUMBER)
1140 lua_pushnumber(L, value->i);
1141 else
1142 return false;
1143 lua_pushboolean(L, toggle);
1144 return pcall(vis, L, 2, 2) == 0 && (!lua_isboolean(L, -1) || lua_toboolean(L, -1));
1147 /***
1148 * Register a custom `:set` option.
1150 * @function option_register
1151 * @tparam string name the option name
1152 * @tparam string type the option type (`bool`, `string` or `number`)
1153 * @tparam function handler the Lua function being called when the option is changed
1154 * @tparam[opt] string help the single line help text as displayed in `:help`
1155 * @treturn bool whether the option was successfully registered
1156 * @usage
1157 * vis:option_register("foo", "bool", function(value, toogle)
1158 * if not vis.win then return false end
1159 * vis.win.foo = toogle and not vis.win.foo or value
1160 * vis:info("Option foo = " .. tostring(vis.win.foo))
1161 * return true
1162 * end, "Foo enables superpowers")
1164 static int option_register(lua_State *L) {
1165 Vis *vis = obj_ref_check(L, 1, "vis");
1166 const char *name = luaL_checkstring(L, 2);
1167 const char *type = luaL_checkstring(L, 3);
1168 const void *func = func_ref_new(L, 4);
1169 const char *help = luaL_optstring(L, 5, NULL);
1170 const char *names[] = { name, NULL };
1171 enum VisOption flags = 0;
1172 if (strcmp(type, "string") == 0)
1173 flags |= VIS_OPTION_TYPE_STRING;
1174 else if (strcmp(type, "number") == 0)
1175 flags |= VIS_OPTION_TYPE_NUMBER;
1176 else
1177 flags |= VIS_OPTION_TYPE_BOOL;
1178 bool ret = vis_option_register(vis, names, flags, option_lua, (void*)func, help);
1179 lua_pushboolean(L, ret);
1180 return 1;
1183 /***
1184 * Unregister a `:set` option.
1186 * @function option_unregister
1187 * @tparam string name the option name
1188 * @treturn bool whether the option was successfully unregistered
1190 static int option_unregister(lua_State *L) {
1191 Vis *vis = obj_ref_check(L, 1, "vis");
1192 const char *name = luaL_checkstring(L, 2);
1193 bool ret = vis_option_unregister(vis, name);
1194 lua_pushboolean(L, ret);
1195 return 1;
1198 static bool command_lua(Vis *vis, Win *win, void *data, bool force, const char *argv[], Selection *sel, Filerange *range) {
1199 lua_State *L = vis->lua;
1200 if (!L || !func_ref_get(L, data))
1201 return false;
1202 lua_newtable(L);
1203 for (size_t i = 0; argv[i]; i++) {
1204 lua_pushunsigned(L, i);
1205 lua_pushstring(L, argv[i]);
1206 lua_settable(L, -3);
1208 lua_pushboolean(L, force);
1209 if (!obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW))
1210 return false;
1211 if (!sel)
1212 sel = view_selections_primary_get(win->view);
1213 if (!obj_lightref_new(L, sel, VIS_LUA_TYPE_SELECTION))
1214 return false;
1215 pushrange(L, range);
1216 if (pcall(vis, L, 5, 1) != 0)
1217 return false;
1218 return lua_toboolean(L, -1);
1221 /***
1222 * Register a custom `:`-command.
1224 * @function command_register
1225 * @tparam string name the command name
1226 * @tparam function command the Lua function implementing the command
1227 * @tparam[opt] string help the single line help text as displayed in `:help`
1228 * @treturn bool whether the command has been successfully registered
1229 * @usage
1230 * vis:command_register("foo", function(argv, force, win, selection, range)
1231 * for i,arg in ipairs(argv) do
1232 * print(i..": "..arg)
1233 * end
1234 * print("was command forced with ! "..(force and "yes" or "no"))
1235 * print(win.file.name)
1236 * print(selection.pos)
1237 * print(range ~= nil and ('['..range.start..', '..range.finish..']') or "invalid range")
1238 * return true;
1239 * end)
1241 static int command_register(lua_State *L) {
1242 Vis *vis = obj_ref_check(L, 1, "vis");
1243 const char *name = luaL_checkstring(L, 2);
1244 const void *func = func_ref_new(L, 3);
1245 const char *help = luaL_optstring(L, 4, "");
1246 bool ret = vis_cmd_register(vis, name, help, (void*)func, command_lua);
1247 lua_pushboolean(L, ret);
1248 return 1;
1251 /***
1252 * Push keys to input queue and interpret them.
1254 * The keys are processed as if they were read from the keyboard.
1256 * @function feedkeys
1257 * @tparam string keys the keys to interpret
1259 static int feedkeys(lua_State *L) {
1260 Vis *vis = obj_ref_check(L, 1, "vis");
1261 const char *keys = luaL_checkstring(L, 2);
1262 vis_keys_feed(vis, keys);
1263 return 0;
1266 /***
1267 * Insert keys at all cursor positions of active window.
1269 * This function behaves as if the keys were entered in insert mode,
1270 * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
1271 * meaning mappings do not apply and the keys will not be recorded in macros.
1273 * @function insert
1274 * @tparam string keys the keys to insert
1275 * @see Vis:feedkeys
1277 static int insert(lua_State *L) {
1278 Vis *vis = obj_ref_check(L, 1, "vis");
1279 size_t len;
1280 const char *keys = luaL_checklstring(L, 2, &len);
1281 vis_insert_key(vis, keys, len);
1282 return 0;
1285 /***
1286 * Replace keys at all cursor positions of active window.
1288 * This function behaves as if the keys were entered in replace mode,
1289 * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
1290 * meaning mappings do not apply and the keys will not be recorded in macros.
1292 * @function replace
1293 * @tparam string keys the keys to insert
1294 * @see Vis:feedkeys
1296 static int replace(lua_State *L) {
1297 Vis *vis = obj_ref_check(L, 1, "vis");
1298 size_t len;
1299 const char *keys = luaL_checklstring(L, 2, &len);
1300 vis_replace_key(vis, keys, len);
1301 return 0;
1304 /***
1305 * Terminate editor process.
1307 * Termination happens upon the next iteration of the main event loop.
1308 * This means the calling Lua code will be executed further until it
1309 * eventually hands over control to the editor core. The exit status
1310 * of the most recent call is used.
1312 * All unsaved chanes will be lost!
1314 * @function exit
1315 * @tparam int code the exit status returned to the operating system
1317 static int exit_func(lua_State *L) {
1318 Vis *vis = obj_ref_check(L, 1, "vis");
1319 int code = luaL_checkint(L, 2);
1320 vis_exit(vis, code);
1321 return 0;
1324 /***
1325 * Pipe file range to external process and collect output.
1327 * The editor core will be blocked while the external process is running.
1329 * @function pipe
1330 * @tparam File file the file to which the range applies
1331 * @tparam Range range the range to pipe
1332 * @tparam string command the command to execute
1333 * @treturn int code the exit status of the executed command
1334 * @treturn string stdout the data written to stdout
1335 * @treturn string stderr the data written to stderr
1337 static int pipe_func(lua_State *L) {
1338 Vis *vis = obj_ref_check(L, 1, "vis");
1339 File *file = obj_ref_check(L, 2, VIS_LUA_TYPE_FILE);
1340 Filerange range = getrange(L, 3);
1341 const char *cmd = luaL_checkstring(L, 4);
1342 char *out = NULL, *err = NULL;
1343 int status = vis_pipe_collect(vis, file, &range, (const char*[]){ cmd, NULL }, &out, &err);
1344 lua_pushinteger(L, status);
1345 if (out)
1346 lua_pushstring(L, out);
1347 else
1348 lua_pushnil(L);
1349 free(out);
1350 if (err)
1351 lua_pushstring(L, err);
1352 else
1353 lua_pushnil(L);
1354 free(err);
1355 vis_draw(vis);
1356 return 3;
1358 /***
1359 * Currently active window.
1360 * @tfield Window win
1361 * @see windows
1363 /***
1364 * Currently active mode.
1365 * @tfield modes mode
1367 /***
1368 * Whether a macro is being recorded.
1369 * @tfield bool recording
1371 /***
1372 * Currently unconsumed keys in the input queue.
1373 * @tfield string input_queue
1375 static int vis_index(lua_State *L) {
1376 Vis *vis = obj_ref_check(L, 1, "vis");
1378 if (lua_isstring(L, 2)) {
1379 const char *key = lua_tostring(L, 2);
1380 if (strcmp(key, "win") == 0) {
1381 if (vis->win)
1382 obj_ref_new(L, vis->win, VIS_LUA_TYPE_WINDOW);
1383 else
1384 lua_pushnil(L);
1385 return 1;
1388 if (strcmp(key, "mode") == 0) {
1389 lua_pushunsigned(L, vis->mode->id);
1390 return 1;
1393 if (strcmp(key, "input_queue") == 0) {
1394 lua_pushstring(L, buffer_content0(&vis->input_queue));
1395 return 1;
1398 if (strcmp(key, "recording") == 0) {
1399 lua_pushboolean(L, vis_macro_recording(vis));
1400 return 1;
1403 if (strcmp(key, "count") == 0) {
1404 int count = vis_count_get(vis);
1405 if (count == VIS_COUNT_UNKNOWN)
1406 lua_pushnil(L);
1407 else
1408 lua_pushunsigned(L, count);
1409 return 1;
1412 if (strcmp(key, "registers") == 0) {
1413 obj_ref_new(L, vis->ui, VIS_LUA_TYPE_REGISTERS);
1414 return 1;
1417 if (strcmp(key, "ui") == 0) {
1418 obj_ref_new(L, vis->ui, VIS_LUA_TYPE_UI);
1419 return 1;
1423 return index_common(L);
1426 static int vis_newindex(lua_State *L) {
1427 Vis *vis = obj_ref_check(L, 1, "vis");
1428 if (lua_isstring(L, 2)) {
1429 const char *key = lua_tostring(L, 2);
1430 if (strcmp(key, "mode") == 0) {
1431 enum VisMode mode = luaL_checkunsigned(L, 3);
1432 vis_mode_switch(vis, mode);
1433 return 0;
1436 if (strcmp(key, "count") == 0) {
1437 int count;
1438 if (lua_isnil(L, 3))
1439 count = VIS_COUNT_UNKNOWN;
1440 else
1441 count = luaL_checkunsigned(L, 3);
1442 vis_count_set(vis, count);
1443 return 0;
1446 if (strcmp(key, "win") == 0) {
1447 vis_window_focus(obj_ref_check(L, 3, VIS_LUA_TYPE_WINDOW));
1448 return 0;
1451 return newindex_common(L);
1454 static const struct luaL_Reg vis_lua[] = {
1455 { "files", files },
1456 { "windows", windows },
1457 { "mark_names", mark_names },
1458 { "register_names", register_names },
1459 { "command", command },
1460 { "info", info },
1461 { "message", message },
1462 { "map", map },
1463 { "unmap", unmap },
1464 { "mappings", mappings },
1465 { "operator", operator },
1466 { "operator_register", operator_register },
1467 { "motion", motion },
1468 { "motion_register", motion_register },
1469 { "textobject", textobject },
1470 { "textobject_register", textobject_register },
1471 { "option_register", option_register },
1472 { "option_unregister", option_unregister },
1473 { "command_register", command_register },
1474 { "feedkeys", feedkeys },
1475 { "insert", insert },
1476 { "replace", replace },
1477 { "action_register", action_register },
1478 { "exit", exit_func },
1479 { "pipe", pipe_func },
1480 { "__index", vis_index },
1481 { "__newindex", vis_newindex },
1482 { NULL, NULL },
1485 static const struct luaL_Reg ui_funcs[] = {
1486 { "__index", index_common },
1487 { NULL, NULL },
1490 static int registers_index(lua_State *L) {
1491 lua_newtable(L);
1492 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
1493 const char *symbol = luaL_checkstring(L, 2);
1494 if (strlen(symbol) != 1)
1495 return 1;
1496 enum VisRegister reg = vis_register_from(vis, symbol[0]);
1497 if (reg >= VIS_REG_INVALID)
1498 return 1;
1499 Array data = vis_register_get(vis, reg);
1500 for (size_t i = 0, len = array_length(&data); i < len; i++) {
1501 TextString *string = array_get(&data, i);
1502 lua_pushunsigned(L, i+1);
1503 lua_pushlstring(L, string->data, string->len);
1504 lua_settable(L, -3);
1506 array_release(&data);
1507 return 1;
1510 static int registers_newindex(lua_State *L) {
1511 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
1512 const char *symbol = luaL_checkstring(L, 2);
1513 if (strlen(symbol) != 1)
1514 return 0;
1515 enum VisRegister reg = vis_register_from(vis, symbol[0]);
1516 Array data;
1517 array_init_sized(&data, sizeof(TextString));
1519 if (lua_istable(L, 3)) {
1520 lua_pushnil(L);
1521 while (lua_next(L, 3)) {
1522 TextString string;
1523 string.data = luaL_checklstring(L, -1, &string.len);
1524 array_add(&data, &string);
1525 lua_pop(L, 1);
1529 vis_register_set(vis, reg, &data);
1530 array_release(&data);
1531 return 0;
1534 static int registers_len(lua_State *L) {
1535 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
1536 lua_pushunsigned(L, LENGTH(vis->registers));
1537 return 1;
1540 static const struct luaL_Reg registers_funcs[] = {
1541 { "__index", registers_index },
1542 { "__newindex", registers_newindex },
1543 { "__len", registers_len },
1544 { NULL, NULL },
1547 /***
1548 * A window object.
1549 * @type Window
1552 /***
1553 * Viewport currently being displayed.
1554 * @tfield Range viewport
1556 /***
1557 * The window width.
1558 * @tfield int width
1560 /***
1561 * The window height.
1562 * @tfield int height
1564 /***
1565 * The file being displayed in this window.
1566 * @tfield File file
1568 /***
1569 * The primary selection of this window.
1570 * @tfield Selection selection
1572 /***
1573 * The selections of this window.
1574 * @tfield Array(Selection) selections
1576 /***
1577 * Window marks.
1578 * Most of these marks are stored in the associated File object, meaning they
1579 * are the same in all windows displaying the same file.
1580 * @field marks array to access the marks of this window by single letter name
1581 * @see Vis:marks_names
1583 static int window_index(lua_State *L) {
1584 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1586 if (lua_isstring(L, 2)) {
1587 const char *key = lua_tostring(L, 2);
1589 if (strcmp(key, "viewport") == 0) {
1590 Filerange r = view_viewport_get(win->view);
1591 pushrange(L, &r);
1592 return 1;
1595 if (strcmp(key, "width") == 0) {
1596 lua_pushunsigned(L, vis_window_width_get(win));
1597 return 1;
1600 if (strcmp(key, "height") == 0) {
1601 lua_pushunsigned(L, vis_window_height_get(win));
1602 return 1;
1605 if (strcmp(key, "file") == 0) {
1606 obj_ref_new(L, win->file, VIS_LUA_TYPE_FILE);
1607 return 1;
1610 if (strcmp(key, "selection") == 0) {
1611 Selection *sel = view_selections_primary_get(win->view);
1612 obj_lightref_new(L, sel, VIS_LUA_TYPE_SELECTION);
1613 return 1;
1616 if (strcmp(key, "selections") == 0) {
1617 obj_ref_new(L, win->view, VIS_LUA_TYPE_SELECTIONS);
1618 return 1;
1621 if (strcmp(key, "marks") == 0) {
1622 obj_ref_new(L, &win->saved_selections, VIS_LUA_TYPE_MARKS);
1623 return 1;
1627 return index_common(L);
1630 static int window_selections_iterator_next(lua_State *L) {
1631 Selection **handle = lua_touserdata(L, lua_upvalueindex(1));
1632 if (!*handle)
1633 return 0;
1634 Selection *sel = obj_lightref_new(L, *handle, VIS_LUA_TYPE_SELECTION);
1635 if (!sel)
1636 return 0;
1637 *handle = view_selections_next(sel);
1638 return 1;
1641 /***
1642 * Create an iterator over all selections of this window.
1643 * @function selections_iterator
1644 * @return the new iterator
1646 static int window_selections_iterator(lua_State *L) {
1647 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1648 Selection **handle = lua_newuserdata(L, sizeof *handle);
1649 *handle = view_selections(win->view);
1650 lua_pushcclosure(L, window_selections_iterator_next, 1);
1651 return 1;
1654 /***
1655 * Set up a window local key mapping.
1656 * The function signatures are the same as for @{Vis:map}.
1657 * @function map
1658 * @param ...
1659 * @see Vis:map
1661 static int window_map(lua_State *L) {
1662 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1663 return keymap(L, win->vis, win);
1666 /***
1667 * Remove a window local key mapping.
1668 * The function signature is the same as for @{Vis:unmap}.
1669 * @function unmap
1670 * @param ...
1671 * @see Vis:unmap
1673 static int window_unmap(lua_State *L) {
1674 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1675 return keyunmap(L, win->vis, win);
1678 /***
1679 * Define a display style.
1680 * @function style_define
1681 * @tparam int id the style id to use
1682 * @tparam string style the style definition
1683 * @treturn bool whether the style definition has been successfully
1684 * associated with the given id
1685 * @see style
1686 * @usage
1687 * win:style_define(win.STYLE_DEFAULT, "fore:red")
1689 static int window_style_define(lua_State *L) {
1690 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1691 enum UiStyle id = luaL_checkunsigned(L, 2);
1692 const char *style = luaL_checkstring(L, 3);
1693 bool ret = view_style_define(win->view, id, style);
1694 lua_pushboolean(L, ret);
1695 return 1;
1698 /***
1699 * Style a window range.
1701 * The style will be cleared after every window redraw.
1702 * @function style
1703 * @tparam int id the display style as registered with @{style_define}
1704 * @tparam int start the absolute file position in bytes
1705 * @tparam int len the length in bytes to style
1706 * @see style_define
1707 * @usage
1708 * win:style(win.STYLE_DEFAULT, 0, 10)
1710 static int window_style(lua_State *L) {
1711 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1712 enum UiStyle style = luaL_checkunsigned(L, 2);
1713 size_t start = checkpos(L, 3);
1714 size_t end = checkpos(L, 4);
1715 view_style(win->view, style, start, end);
1716 return 0;
1719 /***
1720 * Set window status line.
1722 * @function status
1723 * @tparam string left the left aligned part of the status line
1724 * @tparam[opt] string right the right aligned part of the status line
1726 static int window_status(lua_State *L) {
1727 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1728 char status[1024] = "";
1729 int width = vis_window_width_get(win);
1730 const char *left = luaL_checkstring(L, 2);
1731 const char *right = luaL_optstring(L, 3, "");
1732 int left_width = text_string_width(left, strlen(left));
1733 int right_width = text_string_width(right, strlen(right));
1734 int spaces = width - left_width - right_width;
1735 if (spaces < 1)
1736 spaces = 1;
1737 snprintf(status, sizeof(status)-1, "%s%*s%s", left, spaces, " ", right);
1738 vis_window_status(win, status);
1739 return 0;
1742 /***
1743 * Redraw window content.
1745 * @function draw
1747 static int window_draw(lua_State *L) {
1748 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1749 view_draw(win->view);
1750 return 0;
1753 /***
1754 * Close window.
1756 * After a successful call the Window reference becomes invalid and
1757 * must no longer be used. Attempting to close the last window will
1758 * always fail.
1760 * @function close
1761 * @see exit
1762 * @tparam bool force whether unsaved changes should be discarded
1763 * @treturn bool whether the window was closed
1765 static int window_close(lua_State *L) {
1766 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1767 int count = 0;
1768 for (Win *w = win->vis->windows; w; w = w->next) {
1769 if (!w->file->internal)
1770 count++;
1772 bool force = lua_isboolean(L, 2) && lua_toboolean(L, 2);
1773 bool close = count > 1 && (force || vis_window_closable(win));
1774 if (close)
1775 vis_window_close(win);
1776 lua_pushboolean(L, close);
1777 return 1;
1780 static const struct luaL_Reg window_funcs[] = {
1781 { "__index", window_index },
1782 { "__newindex", newindex_common },
1783 { "selections_iterator", window_selections_iterator },
1784 { "map", window_map },
1785 { "unmap", window_unmap },
1786 { "style_define", window_style_define },
1787 { "style", window_style },
1788 { "status", window_status },
1789 { "draw", window_draw },
1790 { "close", window_close },
1791 { NULL, NULL },
1794 static int window_selections_index(lua_State *L) {
1795 View *view = obj_ref_check(L, 1, VIS_LUA_TYPE_SELECTIONS);
1796 size_t index = luaL_checkunsigned(L, 2);
1797 size_t count = view_selections_count(view);
1798 if (index == 0 || index > count)
1799 goto err;
1800 for (Selection *s = view_selections(view); s; s = view_selections_next(s)) {
1801 if (!--index) {
1802 obj_lightref_new(L, s, VIS_LUA_TYPE_SELECTION);
1803 return 1;
1806 err:
1807 lua_pushnil(L);
1808 return 1;
1811 static int window_selections_len(lua_State *L) {
1812 View *view = obj_ref_check(L, 1, VIS_LUA_TYPE_SELECTIONS);
1813 lua_pushunsigned(L, view_selections_count(view));
1814 return 1;
1817 static const struct luaL_Reg window_selections_funcs[] = {
1818 { "__index", window_selections_index },
1819 { "__len", window_selections_len },
1820 { NULL, NULL },
1823 /***
1824 * A selection object.
1826 * A selection is a non-empty, directed range with two endpoints called
1827 * *cursor* and *anchor*. A selection can be anchored in which case
1828 * the anchor remains fixed while only the position of the cursor is
1829 * adjusted. For non-anchored selections both endpoints are updated. A
1830 * singleton selection covers one character on which both cursor and
1831 * anchor reside. There always exists a primary selection which remains
1832 * visible (i.e. changes to its position will adjust the viewport).
1834 * The range covered by a selection is represented as an interval whose
1835 * endpoints are absolute byte offsets from the start of the file.
1836 * Valid addresses are within the closed interval `[0, file.size]`.
1838 * Selections are currently implemented using character marks into
1839 * the underlying persistent
1840 * [text management data structure](https://github.com/martanne/vis/wiki/Text-management-using-a-piece-chain).
1842 * This has a few consequences you should be aware of:
1844 * - A selection becomes invalid when the delimiting boundaries of the underlying
1845 * text it is referencing is deleted:
1847 * -- leaves selection in an invalid state
1848 * win.file:delete(win.selection.pos, 1)
1849 * assert(win.selection.pos == nil)
1851 * Like a regular mark it will become valid again when the text is reverted
1852 * to the state before the deletion.
1854 * - Inserts after the selection position (`> selection.pos`) will not affect the
1855 * selection postion.
1857 * local pos = win.selection.pos
1858 * win.file:insert(pos+1, "-")
1859 * assert(win.selection.pos == pos)
1861 * - Non-cached inserts before the selection position (`<= selection.pos`) will
1862 * affect the mark and adjust the selection postion by the number of bytes
1863 * which were inserted.
1865 * local pos = win.selection.pos
1866 * win.file:insert(pos, "-")
1867 * assert(win.selection.pos == pos+1)
1869 * - Cached inserts before the selection position (`<= selection.pos`) will
1870 * not affect the selection position because the underlying text is replaced
1871 * inplace.
1873 * For these reasons it is generally recommended to update the selection position
1874 * after a modification. The general procedure amounts to:
1876 * 1. Read out the current selection position
1877 * 2. Perform text modifications
1878 * 3. Update the selection postion
1880 * This is what @{Vis:insert} and @{Vis:replace} do internally.
1882 * @type Selection
1883 * @usage
1884 * local data = "new text"
1885 * local pos = win.selection.pos
1886 * win.file:insert(pos, data)
1887 * win.selection.pos = pos + #data
1890 /***
1891 * The zero based byte position in the file.
1893 * Might be `nil` if the selection is in an invalid state.
1894 * Setting this field will move the cursor endpoint of the
1895 * selection to the given position.
1896 * @tfield int pos
1898 /***
1899 * The 1-based line the cursor of this selection resides on.
1901 * @tfield int line
1902 * @see to
1904 /***
1905 * The 1-based column position the cursor of this selection resides on.
1906 * @tfield int col
1907 * @see to
1909 /***
1910 * The 1-based selection index.
1911 * @tfield int number
1913 /***
1914 * The range covered by this selection.
1915 * @tfield Range range
1917 /***
1918 * Whether this selection is anchored.
1919 * @tfield bool anchored
1921 static int window_selection_index(lua_State *L) {
1922 Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
1923 if (!sel) {
1924 lua_pushnil(L);
1925 return 1;
1928 if (lua_isstring(L, 2)) {
1929 const char *key = lua_tostring(L, 2);
1930 if (strcmp(key, "pos") == 0) {
1931 pushpos(L, view_cursors_pos(sel));
1932 return 1;
1935 if (strcmp(key, "line") == 0) {
1936 lua_pushunsigned(L, view_cursors_line(sel));
1937 return 1;
1940 if (strcmp(key, "col") == 0) {
1941 lua_pushunsigned(L, view_cursors_col(sel));
1942 return 1;
1945 if (strcmp(key, "number") == 0) {
1946 lua_pushunsigned(L, view_selections_number(sel)+1);
1947 return 1;
1950 if (strcmp(key, "range") == 0) {
1951 Filerange range = view_selections_get(sel);
1952 pushrange(L, &range);
1953 return 1;
1956 if (strcmp(key, "anchored") == 0) {
1957 lua_pushboolean(L, view_selections_anchored(sel));
1958 return 1;
1963 return index_common(L);
1966 static int window_selection_newindex(lua_State *L) {
1967 Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
1968 if (!sel)
1969 return 0;
1970 if (lua_isstring(L, 2)) {
1971 const char *key = lua_tostring(L, 2);
1972 if (strcmp(key, "pos") == 0) {
1973 size_t pos = checkpos(L, 3);
1974 view_cursors_to(sel, pos);
1975 return 0;
1978 if (strcmp(key, "range") == 0) {
1979 Filerange range = getrange(L, 3);
1980 if (text_range_valid(&range)) {
1981 view_selections_set(sel, &range);
1982 view_selections_anchor(sel, true);
1983 } else {
1984 view_selection_clear(sel);
1986 return 0;
1989 if (strcmp(key, "anchored") == 0) {
1990 view_selections_anchor(sel, lua_toboolean(L, 3));
1991 return 0;
1994 return newindex_common(L);
1997 /***
1998 * Move cursor of selection.
1999 * @function to
2000 * @tparam int line the 1-based line number
2001 * @tparam int col the 1-based column number
2003 static int window_selection_to(lua_State *L) {
2004 Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
2005 if (sel) {
2006 size_t line = checkpos(L, 2);
2007 size_t col = checkpos(L, 3);
2008 view_cursors_place(sel, line, col);
2010 return 0;
2013 static const struct luaL_Reg window_selection_funcs[] = {
2014 { "__index", window_selection_index },
2015 { "__newindex", window_selection_newindex },
2016 { "to", window_selection_to },
2017 { NULL, NULL },
2020 /***
2021 * A file object.
2022 * @type File
2024 /***
2025 * File name.
2026 * @tfield string name the file name relative to current working directory or `nil` if not yet named
2028 /***
2029 * File path.
2030 * @tfield string path the absolute file path or `nil` if not yet named
2032 /***
2033 * File content by logical lines.
2035 * Assigning to array element `0` (`#lines+1`) will insert a new line at
2036 * the beginning (end) of the file.
2037 * @tfield Array(string) lines the file content accessible as 1-based array
2038 * @see content
2039 * @usage
2040 * local lines = vis.win.file.lines
2041 * for i=1, #lines do
2042 * lines[i] = i .. ": " .. lines[i]
2043 * end
2045 /***
2046 * File size in bytes.
2047 * @tfield int size the current file size in bytes
2049 /***
2050 * File state.
2051 * @tfield bool modified whether the file contains unsaved changes
2053 static int file_index(lua_State *L) {
2054 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2056 if (lua_isstring(L, 2)) {
2057 const char *key = lua_tostring(L, 2);
2058 if (strcmp(key, "name") == 0) {
2059 lua_pushstring(L, file_name_get(file));
2060 return 1;
2063 if (strcmp(key, "path") == 0) {
2064 lua_pushstring(L, file->name);
2065 return 1;
2068 if (strcmp(key, "lines") == 0) {
2069 obj_ref_new(L, file->text, VIS_LUA_TYPE_TEXT);
2070 return 1;
2073 if (strcmp(key, "size") == 0) {
2074 lua_pushunsigned(L, text_size(file->text));
2075 return 1;
2078 if (strcmp(key, "modified") == 0) {
2079 lua_pushboolean(L, text_modified(file->text));
2080 return 1;
2084 return index_common(L);
2087 /***
2088 * Insert data at position.
2089 * @function insert
2090 * @tparam int pos the 0-based file position in bytes
2091 * @tparam string data the data to insert
2092 * @treturn bool whether the file content was successfully changed
2094 static int file_insert(lua_State *L) {
2095 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2096 size_t pos = checkpos(L, 2);
2097 size_t len;
2098 luaL_checkstring(L, 3);
2099 const char *data = lua_tolstring(L, 3, &len);
2100 lua_pushboolean(L, text_insert(file->text, pos, data, len));
2101 return 1;
2104 /***
2105 * Delete data at position.
2107 * @function delete
2108 * @tparam int pos the 0-based file position in bytes
2109 * @tparam int len the length in bytes to delete
2110 * @treturn bool whether the file content was successfully changed
2112 /***
2113 * Delete file range.
2115 * @function delete
2116 * @tparam Range range the range to delete
2117 * @treturn bool whether the file content was successfully changed
2119 static int file_delete(lua_State *L) {
2120 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2121 Filerange range = getrange(L, 2);
2122 lua_pushboolean(L, text_delete_range(file->text, &range));
2123 return 1;
2126 /***
2127 * Create an iterator over all lines of the file.
2129 * For large files this is probably faster than @{lines}.
2130 * @function lines_iterator
2131 * @return the new iterator
2132 * @see lines
2133 * @usage
2134 * for line in file:lines_iterator() do
2135 * -- do something with line
2136 * end
2138 static int file_lines_iterator_it(lua_State *L);
2139 static int file_lines_iterator(lua_State *L) {
2140 /* need to check second parameter first, because obj_ref_check_get
2141 * modifies the stack */
2142 size_t line = luaL_optunsigned(L, 2, 1);
2143 File *file = obj_ref_check_get(L, 1, VIS_LUA_TYPE_FILE);
2144 size_t *pos = lua_newuserdata(L, sizeof *pos);
2145 *pos = text_pos_by_lineno(file->text, line);
2146 lua_pushcclosure(L, file_lines_iterator_it, 2);
2147 return 1;
2150 static int file_lines_iterator_it(lua_State *L) {
2151 File *file = *(File**)lua_touserdata(L, lua_upvalueindex(1));
2152 size_t *start = lua_touserdata(L, lua_upvalueindex(2));
2153 if (*start == text_size(file->text))
2154 return 0;
2155 size_t end = text_line_end(file->text, *start);
2156 size_t len = end - *start;
2157 char *buf = malloc(len);
2158 if (!buf && len)
2159 return 0;
2160 len = text_bytes_get(file->text, *start, len, buf);
2161 lua_pushlstring(L, buf, len);
2162 free(buf);
2163 *start = text_line_next(file->text, end);
2164 return 1;
2167 /***
2168 * Get file content of position and length.
2170 * @function content
2171 * @tparam int pos the 0-based file position in bytes
2172 * @tparam int len the length in bytes to read
2173 * @treturn string the file content corresponding to the range
2174 * @see lines
2175 * @usage
2176 * local file = vis.win.file
2177 * local text = file:content(0, file.size)
2179 /***
2180 * Get file content of range.
2182 * @function content
2183 * @tparam Range range the range to read
2184 * @treturn string the file content corresponding to the range
2186 static int file_content(lua_State *L) {
2187 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2188 Filerange range = getrange(L, 2);
2189 if (!text_range_valid(&range))
2190 goto err;
2191 size_t len = text_range_size(&range);
2192 char *data = malloc(len);
2193 if (!data)
2194 goto err;
2195 len = text_bytes_get(file->text, range.start, len, data);
2196 lua_pushlstring(L, data, len);
2197 free(data);
2198 return 1;
2199 err:
2200 lua_pushnil(L);
2201 return 1;
2204 /***
2205 * Set mark.
2206 * @function mark_set
2207 * @tparam int pos the position to set the mark to, must be in [0, file.size]
2208 * @treturn Mark mark the mark which can be looked up later
2210 static int file_mark_set(lua_State *L) {
2211 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2212 size_t pos = checkpos(L, 2);
2213 Mark mark = text_mark_set(file->text, pos);
2214 if (mark)
2215 obj_lightref_new(L, (void*)mark, VIS_LUA_TYPE_MARK);
2216 else
2217 lua_pushnil(L);
2218 return 1;
2221 /***
2222 * Get position of mark.
2223 * @function mark_get
2224 * @tparam Mark mark the mark to look up
2225 * @treturn int pos the position of the mark, or `nil` if invalid
2227 static int file_mark_get(lua_State *L) {
2228 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2229 Mark mark = (Mark)obj_lightref_check(L, 2, VIS_LUA_TYPE_MARK);
2230 size_t pos = text_mark_get(file->text, mark);
2231 if (pos == EPOS)
2232 lua_pushnil(L);
2233 else
2234 lua_pushunsigned(L, pos);
2235 return 1;
2238 /***
2239 * Word text object.
2241 * @function text_object_word
2242 * @tparam int pos the position which must be part of the word
2243 * @treturn Range range the range
2246 /***
2247 * WORD text object.
2249 * @function text_object_longword
2250 * @tparam int pos the position which must be part of the word
2251 * @treturn Range range the range
2254 static int file_text_object(lua_State *L) {
2255 Filerange range = text_range_empty();
2256 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2257 size_t pos = checkpos(L, 2);
2258 size_t idx = lua_tointeger(L, lua_upvalueindex(1));
2259 if (idx < LENGTH(vis_textobjects)) {
2260 const TextObject *txtobj = &vis_textobjects[idx];
2261 if (txtobj->txt)
2262 range = txtobj->txt(file->text, pos);
2264 pushrange(L, &range);
2265 return 1;
2268 static const struct luaL_Reg file_funcs[] = {
2269 { "__index", file_index },
2270 { "__newindex", newindex_common },
2271 { "insert", file_insert },
2272 { "delete", file_delete },
2273 { "lines_iterator", file_lines_iterator },
2274 { "content", file_content },
2275 { "mark_set", file_mark_set },
2276 { "mark_get", file_mark_get },
2277 { NULL, NULL },
2280 static int file_lines_index(lua_State *L) {
2281 Text *txt = obj_ref_check(L, 1, VIS_LUA_TYPE_TEXT);
2282 size_t line = luaL_checkunsigned(L, 2);
2283 size_t start = text_pos_by_lineno(txt, line);
2284 size_t end = text_line_end(txt, start);
2285 if (start != EPOS && end != EPOS) {
2286 size_t size = end - start;
2287 char *data = malloc(size);
2288 if (!data && size)
2289 goto err;
2290 size = text_bytes_get(txt, start, size, data);
2291 lua_pushlstring(L, data, size);
2292 free(data);
2293 return 1;
2295 err:
2296 lua_pushnil(L);
2297 return 1;
2300 static int file_lines_newindex(lua_State *L) {
2301 Text *txt = obj_ref_check(L, 1, VIS_LUA_TYPE_TEXT);
2302 size_t line = luaL_checkunsigned(L, 2);
2303 size_t size;
2304 const char *data = luaL_checklstring(L, 3, &size);
2305 if (line == 0) {
2306 text_insert(txt, 0, data, size);
2307 text_insert(txt, size, "\n", 1);
2308 return 0;
2310 size_t start = text_pos_by_lineno(txt, line);
2311 size_t end = text_line_end(txt, start);
2312 if (start != EPOS && end != EPOS) {
2313 text_delete(txt, start, end - start);
2314 text_insert(txt, start, data, size);
2315 if (text_size(txt) == start + size)
2316 text_insert(txt, text_size(txt), "\n", 1);
2318 return 0;
2321 static int file_lines_len(lua_State *L) {
2322 Text *txt = obj_ref_check(L, 1, VIS_LUA_TYPE_TEXT);
2323 size_t lines = 0;
2324 char lastchar;
2325 size_t size = text_size(txt);
2326 if (size > 0)
2327 lines = text_lineno_by_pos(txt, size);
2328 if (lines > 1 && text_byte_get(txt, size-1, &lastchar) && lastchar == '\n')
2329 lines--;
2330 lua_pushunsigned(L, lines);
2331 return 1;
2334 static const struct luaL_Reg file_lines_funcs[] = {
2335 { "__index", file_lines_index },
2336 { "__newindex", file_lines_newindex },
2337 { "__len", file_lines_len },
2338 { NULL, NULL },
2341 static int window_marks_index(lua_State *L) {
2342 lua_newtable(L);
2343 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
2344 Win *win = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_MARKS, offsetof(Win, saved_selections));
2345 if (!win)
2346 return 1;
2347 const char *symbol = luaL_checkstring(L, 2);
2348 if (strlen(symbol) != 1)
2349 return 1;
2350 enum VisMark mark = vis_mark_from(vis, symbol[0]);
2351 if (mark == VIS_MARK_INVALID)
2352 return 1;
2354 Array arr = vis_mark_get(win, mark);
2355 for (size_t i = 0, len = array_length(&arr); i < len; i++) {
2356 Filerange *range = array_get(&arr, i);
2357 lua_pushunsigned(L, i+1);
2358 pushrange(L, range);
2359 lua_settable(L, -3);
2361 array_release(&arr);
2362 return 1;
2365 static int window_marks_newindex(lua_State *L) {
2366 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
2367 Win *win = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_MARKS, offsetof(Win, saved_selections));
2368 if (!win)
2369 return 0;
2370 const char *symbol = luaL_checkstring(L, 2);
2371 if (strlen(symbol) != 1)
2372 return 0;
2373 enum VisMark mark = vis_mark_from(vis, symbol[0]);
2374 if (mark == VIS_MARK_INVALID)
2375 return 0;
2377 Array ranges;
2378 array_init_sized(&ranges, sizeof(Filerange));
2380 if (lua_istable(L, 3)) {
2381 lua_pushnil(L);
2382 while (lua_next(L, 3)) {
2383 Filerange range = getrange(L, -1);
2384 if (text_range_valid(&range))
2385 array_add(&ranges, &range);
2386 lua_pop(L, 1);
2390 vis_mark_set(win, mark, &ranges);
2391 array_release(&ranges);
2392 return 0;
2395 static int window_marks_len(lua_State *L) {
2396 lua_pushunsigned(L, VIS_MARK_INVALID);
2397 return 1;
2400 static const struct luaL_Reg window_marks_funcs[] = {
2401 { "__index", window_marks_index },
2402 { "__newindex", window_marks_newindex },
2403 { "__len", window_marks_len },
2404 { NULL, NULL },
2407 /***
2408 * The user interface.
2410 * @type Ui
2412 /***
2413 * Number of available colors.
2414 * @tfield int colors
2417 /***
2418 * A file range.
2420 * For a valid range `start <= finish` holds.
2421 * An invalid range is represented as `nil`.
2422 * @type Range
2424 /***
2425 * The being of the range.
2426 * @tfield int start
2428 /***
2429 * The end of the range.
2430 * @tfield int finish
2433 /***
2434 * Modes.
2435 * @section Modes
2438 /***
2439 * Mode constants.
2440 * @table modes
2441 * @tfield int NORMAL
2442 * @tfield int OPERATOR_PENDING
2443 * @tfield int INSERT
2444 * @tfield int REPLACE
2445 * @tfield int VISUAL
2446 * @tfield int VISUAL_LINE
2447 * @see Vis:map
2448 * @see Window:map
2451 /***
2452 * Key Handling.
2454 * This section describes the contract between the editor core and Lua
2455 * key handling functions mapped to symbolic keys using either @{Vis:map}
2456 * or @{Window:map}.
2458 * @section Key_Handling
2461 /***
2462 * Example of a key handling function.
2464 * The keyhandler is invoked with the pending content of the input queue
2465 * given as argument. This might be the empty string if no further input
2466 * is available.
2468 * The function is expected to return the number of *bytes* it has
2469 * consumed from the passed input keys. A negative return value is
2470 * interpreted as an indication that not enough input was available. The
2471 * function will be called again once the user has provided more input. A
2472 * missing return value (i.e. `nil`) is interpreted as zero, meaning
2473 * no further input was consumed but the function completed successfully.
2475 * @function keyhandler
2476 * @tparam string keys the keys following the mapping
2477 * @treturn int the number of *bytes* being consumed by the function (see above)
2478 * @see Vis:action_register
2479 * @see Vis:map
2480 * @see Window:map
2481 * @usage
2482 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
2483 * if #keys < 2 then
2484 * return -1 -- need more input
2485 * end
2486 * local digraph = keys:sub(1, 2)
2487 * if digraph == "l*" then
2488 * vis:feedkeys('λ')
2489 * return 2 -- consume 2 bytes of input
2490 * end
2491 * end, "Insert digraph")
2494 /***
2495 * Core Events.
2497 * These events are invoked from the editor core.
2498 * The following functions are invoked if they are registered in the
2499 * `vis.events` table. Users scripts should generally use the [Events](#events)
2500 * mechanism instead which multiplexes these core events.
2502 * @section Core_Events
2505 static void vis_lua_event_get(lua_State *L, const char *name) {
2506 lua_getglobal(L, "vis");
2507 lua_getfield(L, -1, "events");
2508 if (lua_istable(L, -1)) {
2509 lua_getfield(L, -1, name);
2511 lua_remove(L, -2);
2514 static void vis_lua_event_call(Vis *vis, const char *name) {
2515 lua_State *L = vis->lua;
2516 vis_lua_event_get(L, name);
2517 if (lua_isfunction(L, -1))
2518 pcall(vis, L, 0, 0);
2519 lua_pop(L, 1);
2522 static bool vis_lua_path_strip(Vis *vis) {
2523 lua_State *L = vis->lua;
2524 lua_getglobal(L, "package");
2526 for (const char **var = (const char*[]){ "path", "cpath", NULL }; *var; var++) {
2528 lua_getfield(L, -1, *var);
2529 const char *path = lua_tostring(L, -1);
2530 lua_pop(L, 1);
2531 if (!path)
2532 return false;
2534 char *copy = strdup(path), *stripped = calloc(1, strlen(path)+2);
2535 if (!copy || !stripped) {
2536 free(copy);
2537 free(stripped);
2538 return false;
2541 for (char *elem = copy, *stripped_elem = stripped, *next; elem; elem = next) {
2542 if ((next = strstr(elem, ";")))
2543 *next++ = '\0';
2544 if (strstr(elem, "./"))
2545 continue; /* skip relative path entries */
2546 stripped_elem += sprintf(stripped_elem, "%s;", elem);
2549 lua_pushstring(L, stripped);
2550 lua_setfield(L, -2, *var);
2552 free(copy);
2553 free(stripped);
2556 lua_pop(L, 1); /* package */
2557 return true;
2560 bool vis_lua_path_add(Vis *vis, const char *path) {
2561 lua_State *L = vis->lua;
2562 if (!L || !path)
2563 return false;
2564 lua_getglobal(L, "package");
2565 lua_pushstring(L, path);
2566 lua_pushstring(L, "/?.lua;");
2567 lua_getfield(L, -3, "path");
2568 lua_concat(L, 3);
2569 lua_setfield(L, -2, "path");
2570 lua_pop(L, 1); /* package */
2571 return true;
2574 bool vis_lua_paths_get(Vis *vis, char **lpath, char **cpath) {
2575 lua_State *L = vis->lua;
2576 if (!L)
2577 return false;
2578 const char *s;
2579 lua_getglobal(L, "package");
2580 lua_getfield(L, -1, "path");
2581 s = lua_tostring(L, -1);
2582 *lpath = s ? strdup(s) : NULL;
2583 lua_getfield(L, -2, "cpath");
2584 s = lua_tostring(L, -1);
2585 *cpath = s ? strdup(s) : NULL;
2586 return true;
2589 static bool package_exist(Vis *vis, lua_State *L, const char *name) {
2590 const char lua[] =
2591 "local name = ...\n"
2592 "for _, searcher in ipairs(package.searchers or package.loaders) do\n"
2593 "local loader = searcher(name)\n"
2594 "if type(loader) == 'function' then\n"
2595 "return true\n"
2596 "end\n"
2597 "end\n"
2598 "return false\n";
2599 if (luaL_loadstring(L, lua) != LUA_OK)
2600 return false;
2601 lua_pushstring(L, name);
2602 /* an error indicates package exists */
2603 bool ret = lua_pcall(L, 1, 1, 0) != LUA_OK || lua_toboolean(L, -1);
2604 lua_pop(L, 1);
2605 return ret;
2608 static void *alloc_lua(void *ud, void *ptr, size_t osize, size_t nsize) {
2609 if (nsize == 0) {
2610 free(ptr);
2611 return NULL;
2612 } else {
2613 return realloc(ptr, nsize);
2617 /***
2618 * Editor initialization completed.
2619 * This event is emitted immediately after `visrc.lua` has been sourced, but
2620 * before any other events have occured, in particular the command line arguments
2621 * have not yet been processed.
2623 * Can be used to set *global* configuration options.
2624 * @function init
2626 void vis_lua_init(Vis *vis) {
2627 lua_State *L = lua_newstate(alloc_lua, vis);
2628 if (!L)
2629 return;
2630 vis->lua = L;
2631 lua_atpanic(L, &panic_handler);
2633 luaL_openlibs(L);
2635 #if CONFIG_LPEG
2636 extern int luaopen_lpeg(lua_State *L);
2637 lua_getglobal(L, "package");
2638 lua_getfield(L, -1, "preload");
2639 lua_pushcfunction(L, luaopen_lpeg);
2640 lua_setfield(L, -2, "lpeg");
2641 lua_pop(L, 2);
2642 #endif
2644 /* remove any relative paths from lua's default package.path */
2645 vis_lua_path_strip(vis);
2647 /* extends lua's package.path with:
2648 * - $VIS_PATH
2649 * - ./lua (relative path to the binary location)
2650 * - $XDG_CONFIG_HOME/vis (defaulting to $HOME/.config/vis)
2651 * - /etc/vis (for system-wide configuration provided by administrator)
2652 * - /usr/(local/)?share/vis (or whatever is specified during ./configure)
2653 * - package.path (standard lua search path)
2655 char path[PATH_MAX];
2657 vis_lua_path_add(vis, VIS_PATH);
2659 /* try to get users home directory */
2660 const char *home = getenv("HOME");
2661 if (!home || !*home) {
2662 struct passwd *pw = getpwuid(getuid());
2663 if (pw)
2664 home = pw->pw_dir;
2667 vis_lua_path_add(vis, "/etc/vis");
2669 const char *xdg_config = getenv("XDG_CONFIG_HOME");
2670 if (xdg_config) {
2671 snprintf(path, sizeof path, "%s/vis", xdg_config);
2672 vis_lua_path_add(vis, path);
2673 } else if (home && *home) {
2674 snprintf(path, sizeof path, "%s/.config/vis", home);
2675 vis_lua_path_add(vis, path);
2678 ssize_t len = readlink("/proc/self/exe", path, sizeof(path)-1);
2679 if (len > 0) {
2680 path[len] = '\0';
2681 /* some idotic dirname(3) implementations return pointers to statically
2682 * allocated memory, hence we use memmove to copy it back */
2683 char *dir = dirname(path);
2684 if (dir) {
2685 size_t len = strlen(dir)+1;
2686 if (len < sizeof(path) - sizeof("/lua")) {
2687 memmove(path, dir, len);
2688 strcat(path, "/lua");
2689 vis_lua_path_add(vis, path);
2694 vis_lua_path_add(vis, getenv("VIS_PATH"));
2696 /* table in registry to lookup object type, stores metatable -> type mapping */
2697 lua_newtable(L);
2698 lua_setfield(L, LUA_REGISTRYINDEX, "vis.types");
2699 /* table in registry to track lifetimes of C objects */
2700 lua_newtable(L);
2701 lua_setfield(L, LUA_REGISTRYINDEX, "vis.objects");
2702 /* table in registry to store references to Lua functions */
2703 lua_newtable(L);
2704 lua_setfield(L, LUA_REGISTRYINDEX, "vis.functions");
2705 /* metatable used to type check user data */
2706 obj_type_new(L, VIS_LUA_TYPE_VIS);
2707 luaL_setfuncs(L, vis_lua, 0);
2708 lua_newtable(L);
2709 lua_setfield(L, -2, "types");
2710 /* create reference to main vis object, such that the further
2711 * calls to obj_type_new can register the type meta tables in
2712 * vis.types[name] */
2713 obj_ref_new(L, vis, "vis");
2714 lua_setglobal(L, "vis");
2716 obj_type_new(L, VIS_LUA_TYPE_FILE);
2718 const struct {
2719 enum VisTextObject id;
2720 const char *name;
2721 } textobjects[] = {
2722 { VIS_TEXTOBJECT_INNER_WORD, "text_object_word" },
2723 { VIS_TEXTOBJECT_INNER_LONGWORD, "text_object_longword" },
2726 for (size_t i = 0; i < LENGTH(textobjects); i++) {
2727 lua_pushunsigned(L, textobjects[i].id);
2728 lua_pushcclosure(L, file_text_object, 1);
2729 lua_setfield(L, -2, textobjects[i].name);
2732 luaL_setfuncs(L, file_funcs, 0);
2734 obj_type_new(L, VIS_LUA_TYPE_TEXT);
2735 luaL_setfuncs(L, file_lines_funcs, 0);
2736 obj_type_new(L, VIS_LUA_TYPE_WINDOW);
2737 luaL_setfuncs(L, window_funcs, 0);
2739 const struct {
2740 enum UiStyle id;
2741 const char *name;
2742 } styles[] = {
2743 { UI_STYLE_DEFAULT, "STYLE_DEFAULT" },
2744 { UI_STYLE_CURSOR, "STYLE_CURSOR" },
2745 { UI_STYLE_CURSOR_PRIMARY, "STYLE_CURSOR_PRIMARY" },
2746 { UI_STYLE_CURSOR_LINE, "STYLE_CURSOR_LINE" },
2747 { UI_STYLE_SELECTION, "STYLE_SELECTION" },
2748 { UI_STYLE_LINENUMBER, "STYLE_LINENUMBER" },
2749 { UI_STYLE_LINENUMBER_CURSOR, "STYLE_LINENUMBER_CURSOR" },
2750 { UI_STYLE_COLOR_COLUMN, "STYLE_COLOR_COLUMN" },
2751 { UI_STYLE_STATUS, "STYLE_STATUS" },
2752 { UI_STYLE_STATUS_FOCUSED, "STYLE_STATUS_FOCUSED" },
2753 { UI_STYLE_SEPARATOR, "STYLE_SEPARATOR" },
2754 { UI_STYLE_INFO, "STYLE_INFO" },
2755 { UI_STYLE_EOF, "STYLE_EOF" },
2758 for (size_t i = 0; i < LENGTH(styles); i++) {
2759 lua_pushunsigned(L, styles[i].id);
2760 lua_setfield(L, -2, styles[i].name);
2763 obj_type_new(L, VIS_LUA_TYPE_MARK);
2764 obj_type_new(L, VIS_LUA_TYPE_MARKS);
2765 lua_pushlightuserdata(L, vis);
2766 luaL_setfuncs(L, window_marks_funcs, 1);
2768 obj_type_new(L, VIS_LUA_TYPE_SELECTION);
2769 luaL_setfuncs(L, window_selection_funcs, 0);
2770 obj_type_new(L, VIS_LUA_TYPE_SELECTIONS);
2771 luaL_setfuncs(L, window_selections_funcs, 0);
2773 obj_type_new(L, VIS_LUA_TYPE_UI);
2774 luaL_setfuncs(L, ui_funcs, 0);
2775 lua_pushunsigned(L, vis->ui->colors(vis->ui));
2776 lua_setfield(L, -2, "colors");
2778 obj_type_new(L, VIS_LUA_TYPE_REGISTERS);
2779 lua_pushlightuserdata(L, vis);
2780 luaL_setfuncs(L, registers_funcs, 1);
2782 obj_type_new(L, VIS_LUA_TYPE_KEYACTION);
2784 lua_getglobal(L, "vis");
2785 lua_getmetatable(L, -1);
2787 lua_pushstring(L, VERSION);
2788 lua_setfield(L, -2, "VERSION");
2790 lua_newtable(L);
2792 static const struct {
2793 enum VisMode id;
2794 const char *name;
2795 } modes[] = {
2796 { VIS_MODE_NORMAL, "NORMAL" },
2797 { VIS_MODE_OPERATOR_PENDING, "OPERATOR_PENDING" },
2798 { VIS_MODE_VISUAL, "VISUAL" },
2799 { VIS_MODE_VISUAL_LINE, "VISUAL_LINE" },
2800 { VIS_MODE_INSERT, "INSERT" },
2801 { VIS_MODE_REPLACE, "REPLACE" },
2804 for (size_t i = 0; i < LENGTH(modes); i++) {
2805 lua_pushunsigned(L, modes[i].id);
2806 lua_setfield(L, -2, modes[i].name);
2809 lua_setfield(L, -2, "modes");
2811 if (!package_exist(vis, L, "visrc")) {
2812 vis_info_show(vis, "WARNING: failed to load visrc.lua");
2813 } else {
2814 lua_getglobal(L, "require");
2815 lua_pushstring(L, "visrc");
2816 pcall(vis, L, 1, 0);
2817 vis_lua_event_call(vis, "init");
2821 /***
2822 * Editor startup completed.
2823 * This event is emitted immediately before the main loop starts.
2824 * At this point all files are loaded and corresponding windows are created.
2825 * We are about to process interactive keyboard input.
2826 * @function start
2828 void vis_lua_start(Vis *vis) {
2829 vis_lua_event_call(vis, "start");
2833 * Editor is about to terminate.
2834 * @function quit
2836 void vis_lua_quit(Vis *vis) {
2837 if (!vis->lua)
2838 return;
2839 vis_lua_event_call(vis, "quit");
2840 lua_close(vis->lua);
2841 vis->lua = NULL;
2844 /***
2845 * Input key event in either input or replace mode.
2846 * @function input
2847 * @tparam string key
2848 * @treturn bool whether the key was cosumed or not
2850 static bool vis_lua_input(Vis *vis, const char *key, size_t len) {
2851 lua_State *L = vis->lua;
2852 if (!L || vis->win->file->internal)
2853 return false;
2854 bool ret = false;
2855 vis_lua_event_get(L, "input");
2856 if (lua_isfunction(L, -1)) {
2857 lua_pushlstring(L, key, len);
2858 if (pcall(vis, L, 1, 1) == 0) {
2859 ret = lua_isboolean(L, -1) && lua_toboolean(L, -1);
2860 lua_pop(L, 1);
2863 lua_pop(L, 1);
2864 return ret;
2867 void vis_lua_mode_insert_input(Vis *vis, const char *key, size_t len) {
2868 if (!vis_lua_input(vis, key, len))
2869 vis_insert_key(vis, key, len);
2872 void vis_lua_mode_replace_input(Vis *vis, const char *key, size_t len) {
2873 if (!vis_lua_input(vis, key, len))
2874 vis_replace_key(vis, key, len);
2877 /***
2878 * File open.
2879 * @function file_open
2880 * @tparam File file the file to be opened
2882 void vis_lua_file_open(Vis *vis, File *file) {
2883 debug("event: file-open: %s %p %p\n", file->name ? file->name : "unnamed", (void*)file, (void*)file->text);
2884 lua_State *L = vis->lua;
2885 if (!L)
2886 return;
2887 vis_lua_event_get(L, "file_open");
2888 if (lua_isfunction(L, -1)) {
2889 obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
2890 pcall(vis, L, 1, 0);
2892 lua_pop(L, 1);
2895 /***
2896 * File pre save.
2897 * Triggered *before* the file is being written.
2898 * @function file_save_pre
2899 * @tparam File file the file being written
2900 * @tparam string path the absolute path to which the file will be written, `nil` if standard output
2901 * @treturn bool whether the write operation should be proceeded
2903 bool vis_lua_file_save_pre(Vis *vis, File *file, const char *path) {
2904 lua_State *L = vis->lua;
2905 if (!L)
2906 return true;
2907 vis_lua_event_get(L, "file_save_pre");
2908 if (lua_isfunction(L, -1)) {
2909 obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
2910 lua_pushstring(L, path);
2911 if (pcall(vis, L, 2, 1) != 0)
2912 return false;
2913 return !lua_isboolean(L, -1) || lua_toboolean(L, -1);
2915 lua_pop(L, 1);
2916 return true;
2919 /***
2920 * File post save.
2921 * Triggered *after* a successfull write operation.
2922 * @function file_save_post
2923 * @tparam File file the file which was written
2924 * @tparam string path the absolute path to which it was written, `nil` if standard output
2926 void vis_lua_file_save_post(Vis *vis, File *file, const char *path) {
2927 lua_State *L = vis->lua;
2928 if (!L)
2929 return;
2930 vis_lua_event_get(L, "file_save_post");
2931 if (lua_isfunction(L, -1)) {
2932 obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
2933 lua_pushstring(L, path);
2934 pcall(vis, L, 2, 0);
2936 lua_pop(L, 1);
2939 /***
2940 * File close.
2941 * The last window displaying the file has been closed.
2942 * @function file_close
2943 * @tparam File file the file being closed
2945 void vis_lua_file_close(Vis *vis, File *file) {
2946 debug("event: file-close: %s %p %p\n", file->name ? file->name : "unnamed", (void*)file, (void*)file->text);
2947 lua_State *L = vis->lua;
2948 if (!L)
2949 return;
2950 vis_lua_event_get(L, "file_close");
2951 if (lua_isfunction(L, -1)) {
2952 obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
2953 pcall(vis, L, 1, 0);
2955 obj_ref_free(L, file->marks);
2956 obj_ref_free(L, file->text);
2957 obj_ref_free(L, file);
2958 lua_pop(L, 1);
2961 /***
2962 * Window open.
2963 * A new window has been created.
2964 * @function win_open
2965 * @tparam Window win the window being opened
2967 void vis_lua_win_open(Vis *vis, Win *win) {
2968 debug("event: win-open: %s %p %p\n", win->file->name ? win->file->name : "unnamed", (void*)win, (void*)win->view);
2969 lua_State *L = vis->lua;
2970 if (!L)
2971 return;
2972 vis_lua_event_get(L, "win_open");
2973 if (lua_isfunction(L, -1)) {
2974 obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
2975 pcall(vis, L, 1, 0);
2977 lua_pop(L, 1);
2980 /***
2981 * Window close.
2982 * An window is being closed.
2983 * @function win_close
2984 * @tparam Window win the window being closed
2986 void vis_lua_win_close(Vis *vis, Win *win) {
2987 debug("event: win-close: %s %p %p\n", win->file->name ? win->file->name : "unnamed", (void*)win, (void*)win->view);
2988 lua_State *L = vis->lua;
2989 if (!L)
2990 return;
2991 vis_lua_event_get(L, "win_close");
2992 if (lua_isfunction(L, -1)) {
2993 obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
2994 pcall(vis, L, 1, 0);
2996 obj_ref_free(L, win->view);
2997 obj_ref_free(L, win);
2998 lua_pop(L, 1);
3002 * Window highlight.
3003 * The window has been redrawn and the syntax highlighting needs to be performed.
3004 * @function win_highlight
3005 * @tparam Window win the window being redrawn
3006 * @see style
3008 void vis_lua_win_highlight(Vis *vis, Win *win) {
3009 lua_State *L = vis->lua;
3010 if (!L)
3011 return;
3012 vis_lua_event_get(L, "win_highlight");
3013 if (lua_isfunction(L, -1)) {
3014 obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
3015 pcall(vis, L, 1, 0);
3017 lua_pop(L, 1);
3020 /***
3021 * Window status bar redraw.
3022 * @function win_status
3023 * @tparam Window win the affected window
3024 * @see status
3026 void vis_lua_win_status(Vis *vis, Win *win) {
3027 lua_State *L = vis->lua;
3028 if (!L || win->file->internal) {
3029 window_status_update(vis, win);
3030 return;
3032 vis_lua_event_get(L, "win_status");
3033 if (lua_isfunction(L, -1)) {
3034 obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
3035 pcall(vis, L, 1, 0);
3036 } else {
3037 window_status_update(vis, win);
3039 lua_pop(L, 1);
3042 #endif