text: improve text_line_down on the last line of the file
[vis.git] / vis-lua.c
blobf59528c5981ab162b6e5a843a0077fa77dc58e40
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[0]), "%s%s%s",
77 filename ? filename : "[No Name]",
78 text_modified(txt) ? " [+]" : "",
79 vis_macro_recording(vis) ? " @": "");
81 int count = vis_count_get(vis);
82 const char *keys = buffer_content0(&vis->input_queue);
83 if (keys && keys[0])
84 snprintf(right_parts[right_count++], sizeof(right_parts[0]), "%s", keys);
85 else if (count != VIS_COUNT_UNKNOWN)
86 snprintf(right_parts[right_count++], sizeof(right_parts[0]), "%d", count);
88 int sel_count = view_selections_count(view);
89 if (sel_count > 1) {
90 Selection *s = view_selections_primary_get(view);
91 int sel_number = view_selections_number(s) + 1;
92 snprintf(right_parts[right_count++], sizeof(right_parts[0]),
93 "%d/%d", sel_number, sel_count);
96 size_t size = text_size(txt);
97 size_t pos = view_cursor_get(view);
98 size_t percent = 0;
99 if (size > 0) {
100 double tmp = ((double)pos/(double)size)*100;
101 percent = (size_t)(tmp+1);
103 snprintf(right_parts[right_count++], sizeof(right_parts[0]),
104 "%zu%%", percent);
106 if (!(options & UI_OPTION_LARGE_FILE)) {
107 Selection *sel = view_selections_primary_get(win->view);
108 size_t line = view_cursors_line(sel);
109 size_t col = view_cursors_col(sel);
110 if (col > UI_LARGE_FILE_LINE_SIZE) {
111 options |= UI_OPTION_LARGE_FILE;
112 view_options_set(win->view, options);
114 snprintf(right_parts[right_count++], sizeof(right_parts[0]),
115 "%zu, %zu", line, col);
118 int left_len = snprintf(left, sizeof(left), " %s%s%s%s%s%s%s",
119 left_parts[0],
120 left_parts[1][0] ? " » " : "",
121 left_parts[1],
122 left_parts[2][0] ? " » " : "",
123 left_parts[2],
124 left_parts[3][0] ? " » " : "",
125 left_parts[3]);
127 int right_len = snprintf(right, sizeof(right), "%s%s%s%s%s%s%s ",
128 right_parts[0],
129 right_parts[1][0] ? " « " : "",
130 right_parts[1],
131 right_parts[2][0] ? " « " : "",
132 right_parts[2],
133 right_parts[3][0] ? " « " : "",
134 right_parts[3]);
136 if (left_len < 0 || right_len < 0)
137 return;
138 int left_width = text_string_width(left, left_len);
139 int right_width = text_string_width(right, right_len);
141 int spaces = width - left_width - right_width;
142 if (spaces < 1)
143 spaces = 1;
145 snprintf(status, sizeof(status), "%s%*s%s", left, spaces, " ", right);
146 vis_window_status(win, status);
149 #if !CONFIG_LUA
151 bool vis_lua_path_add(Vis *vis, const char *path) { return true; }
152 bool vis_lua_paths_get(Vis *vis, char **lpath, char **cpath) { return false; }
153 void vis_lua_init(Vis *vis) { }
154 void vis_lua_start(Vis *vis) { }
155 void vis_lua_quit(Vis *vis) { }
156 void vis_lua_file_open(Vis *vis, File *file) { }
157 bool vis_lua_file_save_pre(Vis *vis, File *file, const char *path) { return true; }
158 void vis_lua_file_save_post(Vis *vis, File *file, const char *path) { }
159 void vis_lua_file_close(Vis *vis, File *file) { }
160 void vis_lua_win_open(Vis *vis, Win *win) { }
161 void vis_lua_win_close(Vis *vis, Win *win) { }
162 void vis_lua_win_highlight(Vis *vis, Win *win) { }
163 void vis_lua_win_status(Vis *vis, Win *win) { window_status_update(vis, win); }
165 #else
167 #if DEBUG_LUA
168 static void stack_dump_entry(lua_State *L, int i) {
169 int t = lua_type(L, i);
170 switch (t) {
171 case LUA_TNIL:
172 printf("nil");
173 break;
174 case LUA_TBOOLEAN:
175 printf(lua_toboolean(L, i) ? "true" : "false");
176 break;
177 case LUA_TLIGHTUSERDATA:
178 printf("lightuserdata(%p)", lua_touserdata(L, i));
179 break;
180 case LUA_TNUMBER:
181 printf("%g", lua_tonumber(L, i));
182 break;
183 case LUA_TSTRING:
184 printf("`%s'", lua_tostring(L, i));
185 break;
186 case LUA_TTABLE:
187 printf("table[");
188 lua_pushnil(L); /* first key */
189 while (lua_next(L, i > 0 ? i : i - 1)) {
190 stack_dump_entry(L, -2);
191 printf("=");
192 stack_dump_entry(L, -1);
193 printf(",");
194 lua_pop(L, 1); /* remove value, keep key */
196 printf("]");
197 break;
198 case LUA_TUSERDATA:
199 printf("userdata(%p)", lua_touserdata(L, i));
200 break;
201 default: /* other values */
202 printf("%s", lua_typename(L, t));
203 break;
207 static void stack_dump(lua_State *L, const char *format, ...) {
208 va_list ap;
209 va_start(ap, format);
210 vprintf(format, ap);
211 va_end(ap);
212 int top = lua_gettop(L);
213 for (int i = 1; i <= top; i++) {
214 printf("%d: ", i);
215 stack_dump_entry(L, i);
216 printf("\n");
218 printf("\n\n");
219 fflush(stdout);
222 #endif
224 static int panic_handler(lua_State *L) {
225 void *ud = NULL;
226 lua_getallocf(L, &ud);
227 if (ud) {
228 Vis *vis = ud;
229 vis->lua = NULL;
230 const char *msg = NULL;
231 if (lua_type(L, -1) == LUA_TSTRING)
232 msg = lua_tostring(L, -1);
233 vis_info_show(vis, "Fatal Lua error: %s", msg ? msg : "unknown reason");
234 lua_close(L);
235 if (vis->running)
236 siglongjmp(vis->sigbus_jmpbuf, 1);
238 return 0;
241 static int error_handler(lua_State *L) {
242 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
243 if (vis->errorhandler)
244 return 1;
245 vis->errorhandler = true;
246 size_t len;
247 const char *msg = lua_tostring(L, 1);
248 if (msg)
249 luaL_traceback(L, L, msg, 1);
250 msg = lua_tolstring(L, 1, &len);
251 vis_message_show(vis, msg);
252 vis->errorhandler = false;
253 return 1;
256 static int pcall(Vis *vis, lua_State *L, int nargs, int nresults) {
257 /* insert a custom error function below all arguments */
258 int msgh = lua_gettop(L) - nargs;
259 lua_pushlightuserdata(L, vis);
260 lua_pushcclosure(L, error_handler, 1);
261 lua_insert(L, msgh);
262 int ret = lua_pcall(L, nargs, nresults, msgh);
263 lua_remove(L, msgh);
264 return ret;
267 /* expects a lua function at stack position `narg` and stores a
268 * reference to it in the registry. The return value can be used
269 * to look it up.
271 * registry["vis.functions"][(void*)(function)] = function
273 static const void *func_ref_new(lua_State *L, int narg) {
274 const void *addr = lua_topointer(L, narg);
275 if (!lua_isfunction(L, narg) || !addr)
276 luaL_argerror(L, narg, "function expected");
277 lua_getfield(L, LUA_REGISTRYINDEX, "vis.functions");
278 lua_pushlightuserdata(L, (void*)addr);
279 lua_pushvalue(L, narg);
280 lua_settable(L, -3);
281 lua_pop(L, 1);
282 return addr;
285 /* retrieve function from registry and place it at the top of the stack */
286 static bool func_ref_get(lua_State *L, const void *addr) {
287 if (!addr)
288 return false;
289 lua_getfield(L, LUA_REGISTRYINDEX, "vis.functions");
290 lua_pushlightuserdata(L, (void*)addr);
291 lua_gettable(L, -2);
292 lua_remove(L, -2);
293 if (!lua_isfunction(L, -1)) {
294 lua_pop(L, 1);
295 return false;
297 return true;
300 /* creates a new metatable for a given type and stores a mapping:
302 * registry["vis.types"][metatable] = type
304 * leaves the metatable at the top of the stack.
306 static void obj_type_new(lua_State *L, const char *type) {
307 luaL_newmetatable(L, type);
308 lua_getglobal(L, "vis");
309 if (!lua_isnil(L, -1)) {
310 lua_getfield(L, -1, "types");
311 lua_pushvalue(L, -3);
312 lua_setfield(L, -2, type);
313 lua_pop(L, 1);
315 lua_pop(L, 1);
316 lua_getfield(L, LUA_REGISTRYINDEX, "vis.types");
317 lua_pushvalue(L, -2);
318 lua_pushstring(L, type);
319 lua_settable(L, -3);
320 lua_pop(L, 1);
323 /* get type of userdatum at the top of the stack:
325 * return registry["vis.types"][getmetatable(userdata)]
327 const char *obj_type_get(lua_State *L) {
328 if (lua_isnil(L, -1))
329 return "nil";
330 lua_getfield(L, LUA_REGISTRYINDEX, "vis.types");
331 lua_getmetatable(L, -2);
332 lua_gettable(L, -2);
333 // XXX: in theory string might become invalid when poped from stack
334 const char *type = lua_tostring(L, -1);
335 lua_pop(L, 2);
336 return type;
339 static void *obj_new(lua_State *L, size_t size, const char *type) {
340 void *obj = lua_newuserdata(L, size);
341 luaL_getmetatable(L, type);
342 lua_setmetatable(L, -2);
343 lua_newtable(L);
344 lua_setuservalue(L, -2);
345 return obj;
348 /* returns registry["vis.objects"][addr] if it is of correct type */
349 static void *obj_ref_get(lua_State *L, void *addr, const char *type) {
350 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
351 lua_pushlightuserdata(L, addr);
352 lua_gettable(L, -2);
353 lua_remove(L, -2);
354 if (lua_isnil(L, -1)) {
355 debug("get: vis.objects[%p] = nil\n", addr);
356 lua_pop(L, 1);
357 return NULL;
359 if (DEBUG_LUA) {
360 const char *actual_type = obj_type_get(L);
361 if (strcmp(type, actual_type) != 0)
362 debug("get: vis.objects[%p] = %s (BUG: expected %s)\n", addr, actual_type, type);
363 void **handle = luaL_checkudata(L, -1, type);
364 if (!handle)
365 debug("get: vis.objects[%p] = %s (BUG: invalid handle)\n", addr, type);
366 else if (*handle != addr)
367 debug("get: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr, type, *handle);
369 return luaL_checkudata(L, -1, type);
372 /* expects a userdatum at the top of the stack and sets
374 * registry["vis.objects"][addr] = userdata
376 static void obj_ref_set(lua_State *L, void *addr) {
377 //debug("set: vis.objects[%p] = %s\n", addr, obj_type_get(L));
378 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
379 lua_pushlightuserdata(L, addr);
380 lua_pushvalue(L, -3);
381 lua_settable(L, -3);
382 lua_pop(L, 1);
385 /* invalidates an object reference
387 * registry["vis.objects"][addr] = nil
389 static void obj_ref_free(lua_State *L, void *addr) {
390 if (DEBUG_LUA) {
391 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
392 lua_pushlightuserdata(L, addr);
393 lua_gettable(L, -2);
394 lua_remove(L, -2);
395 if (lua_isnil(L, -1))
396 debug("free-unused: %p\n", addr);
397 else
398 debug("free: vis.objects[%p] = %s\n", addr, obj_type_get(L));
399 lua_pop(L, 1);
401 lua_pushnil(L);
402 obj_ref_set(L, addr);
405 /* creates a new object reference of given type if it does not already exist in the registry:
407 * if (registry["vis.types"][metatable(registry["vis.objects"][addr])] != type) {
408 * // XXX: should not happen
409 * registry["vis.objects"][addr] = new_obj(addr, type)
411 * return registry["vis.objects"][addr];
413 static void *obj_ref_new(lua_State *L, void *addr, const char *type) {
414 if (!addr) {
415 lua_pushnil(L);
416 return NULL;
418 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
419 lua_pushlightuserdata(L, addr);
420 lua_gettable(L, -2);
421 lua_remove(L, -2);
422 const char *old_type = obj_type_get(L);
423 if (strcmp(type, old_type) == 0) {
424 debug("new: vis.objects[%p] = %s (returning existing object)\n", addr, old_type);
425 void **handle = luaL_checkudata(L, -1, type);
426 if (!handle)
427 debug("new: vis.objects[%p] = %s (BUG: invalid handle)\n", addr, old_type);
428 else if (*handle != addr)
429 debug("new: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr, old_type, *handle);
430 return addr;
432 if (!lua_isnil(L, -1))
433 debug("new: vis.objects[%p] = %s (WARNING: changing object type from %s)\n", addr, type, old_type);
434 else
435 debug("new: vis.objects[%p] = %s (creating new object)\n", addr, type);
436 lua_pop(L, 1);
437 void **handle = obj_new(L, sizeof(addr), type);
438 obj_ref_set(L, addr);
439 *handle = addr;
440 return addr;
443 /* retrieve object stored in reference at stack location `idx' */
444 static void *obj_ref_check_get(lua_State *L, int idx, const char *type) {
445 void **addr = luaL_checkudata(L, idx, type);
446 if (!obj_ref_get(L, *addr, type))
447 return NULL;
448 return *addr;
451 /* (type) check validity of object reference at stack location `idx' */
452 static void *obj_ref_check(lua_State *L, int idx, const char *type) {
453 void *obj = obj_ref_check_get(L, idx, type);
454 if (obj)
455 lua_pop(L, 1);
456 else
457 luaL_argerror(L, idx, "invalid object reference");
458 return obj;
461 static void *obj_ref_check_containerof(lua_State *L, int idx, const char *type, size_t offset) {
462 void *obj = obj_ref_check(L, idx, type);
463 return obj ? ((char*)obj-offset) : obj;
466 static void *obj_lightref_new(lua_State *L, void *addr, const char *type) {
467 if (!addr)
468 return NULL;
469 void **handle = obj_new(L, sizeof(addr), type);
470 *handle = addr;
471 return addr;
474 static void *obj_lightref_check(lua_State *L, int idx, const char *type) {
475 void **addr = luaL_checkudata(L, idx, type);
476 return *addr;
479 static int index_common(lua_State *L) {
480 lua_getmetatable(L, 1);
481 lua_pushvalue(L, 2);
482 lua_gettable(L, -2);
483 if (lua_isnil(L, -1)) {
484 lua_getuservalue(L, 1);
485 lua_pushvalue(L, 2);
486 lua_gettable(L, -2);
488 return 1;
491 static int newindex_common(lua_State *L) {
492 lua_getuservalue(L, 1);
493 lua_pushvalue(L, 2);
494 lua_pushvalue(L, 3);
495 lua_settable(L, -3);
496 return 0;
499 static size_t getpos(lua_State *L, int narg) {
500 return lua_tounsigned(L, narg);
503 static size_t checkpos(lua_State *L, int narg) {
504 lua_Number n = luaL_checknumber(L, narg);
505 if (n >= 0 && n <= SIZE_MAX && n == (size_t)n)
506 return n;
507 return luaL_argerror(L, narg, "expected position, got number");
510 static void pushpos(lua_State *L, size_t pos) {
511 if (pos == EPOS)
512 lua_pushnil(L);
513 else
514 lua_pushunsigned(L, pos);
517 static void pushrange(lua_State *L, Filerange *r) {
518 if (!r || !text_range_valid(r)) {
519 lua_pushnil(L);
520 return;
522 lua_createtable(L, 0, 2);
523 lua_pushstring(L, "start");
524 lua_pushunsigned(L, r->start);
525 lua_settable(L, -3);
526 lua_pushstring(L, "finish");
527 lua_pushunsigned(L, r->end);
528 lua_settable(L, -3);
531 static Filerange getrange(lua_State *L, int index) {
532 Filerange range = text_range_empty();
533 if (lua_istable(L, index)) {
534 lua_getfield(L, index, "start");
535 range.start = checkpos(L, -1);
536 lua_pop(L, 1);
537 lua_getfield(L, index, "finish");
538 range.end = checkpos(L, -1);
539 lua_pop(L, 1);
540 } else {
541 range.start = checkpos(L, index);
542 range.end = range.start + checkpos(L, index+1);
544 return range;
547 static const char *keymapping(Vis *vis, const char *keys, const Arg *arg) {
548 lua_State *L = vis->lua;
549 if (!func_ref_get(L, arg->v))
550 return keys;
551 lua_pushstring(L, keys);
552 if (pcall(vis, L, 1, 1) != 0)
553 return keys;
554 if (lua_type(L, -1) != LUA_TNUMBER)
555 return keys; /* invalid or no return value, assume zero */
556 lua_Number number = lua_tonumber(L, -1);
557 lua_Integer integer = lua_tointeger(L, -1);
558 if (number != integer)
559 return keys;
560 if (integer < 0)
561 return NULL; /* need more input */
562 size_t len = integer;
563 size_t max = strlen(keys);
564 return (len <= max) ? keys+len : keys;
567 /***
568 * The main editor object.
569 * @type Vis
572 /***
573 * Version information.
574 * @tfield string VERSION
575 * version information in `git describe` format, same as reported by `vis -v`.
577 /***
578 * Lua API object types
579 * @field types meta tables of userdata objects used for type checking
580 * @local
582 /***
583 * User interface.
584 * @tfield Ui ui the user interface being used
586 /***
587 * Mode constants.
588 * @tfield modes modes
590 /***
591 * Events.
592 * @tfield events events
594 /***
595 * Registers.
596 * @field registers array to access the register by single letter name
598 /***
599 * Scintillua lexer module.
600 * @field lexers might be `nil` if module is not found
602 /***
603 * LPeg lexer module.
604 * @field lpeg might be `nil` if module is not found
606 /***
607 * Current count.
608 * @tfield int count the specified count for the current command or `nil` if none was given
611 /***
612 * Create an iterator over all windows.
613 * @function windows
614 * @return the new iterator
615 * @see win
616 * @usage
617 * for win in vis:windows() do
618 * -- do something with win
619 * end
621 static int windows_iter(lua_State *L);
622 static int windows(lua_State *L) {
623 Vis *vis = obj_ref_check(L, 1, "vis");
624 Win **handle = lua_newuserdata(L, sizeof *handle), *next;
625 for (next = vis->windows; next && next->file->internal; next = next->next);
626 *handle = next;
627 lua_pushcclosure(L, windows_iter, 1);
628 return 1;
631 static int windows_iter(lua_State *L) {
632 Win **handle = lua_touserdata(L, lua_upvalueindex(1));
633 if (!*handle)
634 return 0;
635 Win *win = obj_ref_new(L, *handle, VIS_LUA_TYPE_WINDOW), *next;
636 if (win) {
637 for (next = win->next; next && next->file->internal; next = next->next);
638 *handle = next;
640 return 1;
643 /***
644 * Create an iterator over all files.
645 * @function files
646 * @return the new iterator
647 * @usage
648 * for file in vis:files() do
649 * -- do something with file
650 * end
652 static int files_iter(lua_State *L);
653 static int files(lua_State *L) {
654 Vis *vis = obj_ref_check(L, 1, "vis");
655 File **handle = lua_newuserdata(L, sizeof *handle);
656 *handle = vis->files;
657 lua_pushcclosure(L, files_iter, 1);
658 return 1;
661 static int files_iter(lua_State *L) {
662 File **handle = lua_touserdata(L, lua_upvalueindex(1));
663 if (!*handle)
664 return 0;
665 File *file = obj_ref_new(L, *handle, VIS_LUA_TYPE_FILE);
666 if (file)
667 *handle = file->next;
668 return 1;
671 /***
672 * Create an iterator over all mark names.
673 * @function mark_names
674 * @return the new iterator
675 * @usage
676 * local marks = vis.win.marks
677 * for name in vis:mark_names() do
678 * local mark = marks[name]
679 * for i = 1, #mark do
680 * -- do somthing with: name, mark[i].start, mark[i].finish
681 * end
682 * end
684 static int mark_names_iter(lua_State *L);
685 static int mark_names(lua_State *L) {
686 Vis *vis = obj_ref_check(L, 1, "vis");
687 lua_pushlightuserdata(L, vis);
688 enum VisMark *handle = lua_newuserdata(L, sizeof *handle);
689 *handle = 0;
690 lua_pushcclosure(L, mark_names_iter, 2);
691 return 1;
694 static int mark_names_iter(lua_State *L) {
695 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
696 enum VisMark *handle = lua_touserdata(L, lua_upvalueindex(2));
697 char mark = vis_mark_to(vis, *handle);
698 if (mark) {
699 lua_pushlstring(L, &mark, 1);
700 (*handle)++;
701 return 1;
703 return 0;
706 /***
707 * Create an iterator over all register names.
708 * @function register_names
709 * @return the new iterator
710 * @usage
711 * for name in vis:register_names() do
712 * local reg = vis.registers[name]
713 * for i = 1, #reg do
714 * -- do something with register value reg[i]
715 * end
716 * end
718 static int register_names_iter(lua_State *L);
719 static int register_names(lua_State *L) {
720 Vis *vis = obj_ref_check(L, 1, "vis");
721 lua_pushlightuserdata(L, vis);
722 enum VisRegister *handle = lua_newuserdata(L, sizeof *handle);
723 *handle = 0;
724 lua_pushcclosure(L, register_names_iter, 2);
725 return 1;
728 static int register_names_iter(lua_State *L) {
729 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
730 enum VisRegister *handle = lua_touserdata(L, lua_upvalueindex(2));
731 char reg = vis_register_to(vis, *handle);
732 if (reg) {
733 lua_pushlstring(L, &reg, 1);
734 (*handle)++;
735 return 1;
737 return 0;
740 /***
741 * Execute a `:`-command.
742 * @function command
743 * @tparam string command the command to execute
744 * @treturn bool whether the command succeeded
745 * @usage
746 * vis:command("set number")
748 static int command(lua_State *L) {
749 Vis *vis = obj_ref_check(L, 1, "vis");
750 const char *cmd = luaL_checkstring(L, 2);
751 bool ret = vis_cmd(vis, cmd);
752 lua_pushboolean(L, ret);
753 return 1;
756 /***
757 * Display a short message.
759 * The single line message will be displayed at the bottom of
760 * the scren and automatically hidden once a key is pressed.
762 * @function info
763 * @tparam string message the message to display
765 static int info(lua_State *L) {
766 Vis *vis = obj_ref_check(L, 1, "vis");
767 const char *msg = luaL_checkstring(L, 2);
768 vis_info_show(vis, "%s", msg);
769 return 0;
772 /***
773 * Display a multi line message.
775 * Opens a new window and displays an arbitrarily long message.
777 * @function message
778 * @tparam string message the message to display
780 static int message(lua_State *L) {
781 Vis *vis = obj_ref_check(L, 1, "vis");
782 const char *msg = luaL_checkstring(L, 2);
783 vis_message_show(vis, msg);
784 return 0;
787 /***
788 * Register a Lua function as key action.
789 * @function action_register
790 * @tparam string name the name of the action, can be referred to in key bindings as `<name>` pseudo key
791 * @tparam Function func the lua function implementing the key action (see @{keyhandler})
792 * @tparam[opt] string help the single line help text as displayed in `:help`
793 * @treturn KeyAction action the registered key action
794 * @see Vis:map
795 * @see Window:map
797 static int action_register(lua_State *L) {
798 Vis *vis = obj_ref_check(L, 1, "vis");
799 const char *name = luaL_checkstring(L, 2);
800 const void *func = func_ref_new(L, 3);
801 const char *help = luaL_optstring(L, 4, NULL);
802 KeyAction *action = vis_action_new(vis, name, help, keymapping, (Arg){ .v = func });
803 if (!action)
804 goto err;
805 if (!vis_action_register(vis, action))
806 goto err;
807 obj_ref_new(L, action, VIS_LUA_TYPE_KEYACTION);
808 return 1;
809 err:
810 vis_action_free(vis, action);
811 lua_pushnil(L);
812 return 1;
815 static int keymap(lua_State *L, Vis *vis, Win *win) {
816 int mode = luaL_checkint(L, 2);
817 const char *key = luaL_checkstring(L, 3);
818 const char *help = luaL_optstring(L, 5, NULL);
819 KeyBinding *binding = vis_binding_new(vis);
820 if (!binding)
821 goto err;
822 if (lua_isstring(L, 4)) {
823 const char *alias = luaL_checkstring(L, 4);
824 if (!(binding->alias = strdup(alias)))
825 goto err;
826 } else if (lua_isfunction(L, 4)) {
827 const void *func = func_ref_new(L, 4);
828 if (!(binding->action = vis_action_new(vis, NULL, help, keymapping, (Arg){ .v = func })))
829 goto err;
830 } else if (lua_isuserdata(L, 4)) {
831 binding->action = obj_ref_check(L, 4, VIS_LUA_TYPE_KEYACTION);
834 if (win) {
835 if (!vis_window_mode_map(win, mode, true, key, binding))
836 goto err;
837 } else {
838 if (!vis_mode_map(vis, mode, true, key, binding))
839 goto err;
842 lua_pushboolean(L, true);
843 return 1;
844 err:
845 vis_binding_free(vis, binding);
846 lua_pushboolean(L, false);
847 return 1;
850 /***
851 * Map a key to a Lua function.
853 * Creates a new key mapping in a given mode.
855 * @function map
856 * @tparam int mode the mode to which the mapping should be added
857 * @tparam string key the key to map
858 * @tparam function func the Lua function to handle the key mapping (see @{keyhandler})
859 * @tparam[opt] string help the single line help text as displayed in `:help`
860 * @treturn bool whether the mapping was successfully established
861 * @see Window:map
862 * @usage
863 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
864 * if #keys < 2 then
865 * return -1 -- need more input
866 * end
867 * local digraph = keys:sub(1, 2)
868 * if digraph == "l*" then
869 * vis:feedkeys('λ')
870 * return 2 -- consume 2 bytes of input
871 * end
872 * end, "Insert digraph")
874 /***
875 * Setup a key alias.
877 * This is equivalent to `vis:command('map! mode key alias')`.
879 * Mappings are always recursive!
880 * @function map
881 * @tparam int mode the mode to which the mapping should be added
882 * @tparam string key the key to map
883 * @tparam string alias the key to map to
884 * @treturn bool whether the mapping was successfully established
885 * @see Window:map
886 * @usage
887 * vis:map(vis.modes.NORMAL, "j", "k")
889 /***
890 * Map a key to a key action.
892 * @function map
893 * @tparam int mode the mode to which the mapping should be added
894 * @tparam string key the key to map
895 * @param action the action to map
896 * @treturn bool whether the mapping was successfully established
897 * @see Window:map
898 * @usage
899 * local action = vis:action_register("info", function()
900 * vis:info("Mapping works!")
901 * end, "Info message help text")
902 * vis:map(vis.modes.NORMAL, "gh", action)
903 * vis:map(vis.modes.NORMAL, "gl", action)
905 static int map(lua_State *L) {
906 Vis *vis = obj_ref_check(L, 1, "vis");
907 return keymap(L, vis, NULL);
910 /***
911 * Unmap a global key binding.
913 * @function unmap
914 * @tparam int mode the mode from which the mapping should be removed
915 * @tparam string key the mapping to remove
916 * @treturn bool whether the mapping was successfully removed
917 * @see Window:unmap
919 static int keyunmap(lua_State *L, Vis *vis, Win *win) {
920 enum VisMode mode = luaL_checkint(L, 2);
921 const char *key = luaL_checkstring(L, 3);
922 bool ret;
923 if (!win)
924 ret = vis_mode_unmap(vis, mode, key);
925 else
926 ret = vis_window_mode_unmap(win, mode, key);
927 lua_pushboolean(L, ret);
928 return 1;
931 static int unmap(lua_State *L) {
932 Vis *vis = obj_ref_check(L, 1, "vis");
933 return keyunmap(L, vis, NULL);
936 /***
937 * Get all currently active mappings of a mode.
939 * @function mappings
940 * @tparam int mode the mode to query
941 * @treturn table the active mappings and their associated help texts
942 * @usage
943 * local bindings = vis:mappings(vis.modes.NORMAL)
944 * for key, help in pairs(bindings) do
945 * -- do something
946 * end
947 * @see Vis:map
949 static bool binding_collect(const char *key, void *value, void *ctx) {
950 lua_State *L = ctx;
951 KeyBinding *binding = value;
952 lua_getfield(L, -1, key);
953 bool new = lua_isnil(L, -1);
954 lua_pop(L, 1);
955 if (new) {
956 const char *help = binding->alias ? binding->alias : VIS_HELP_USE(binding->action->help);
957 lua_pushstring(L, help ? help : "");
958 lua_setfield(L, -2, key);
960 return true;
963 static int mappings(lua_State *L) {
964 Vis *vis = obj_ref_check(L, 1, "vis");
965 lua_newtable(L);
966 for (Mode *mode = mode_get(vis, luaL_checkint(L, 2)); mode; mode = mode->parent) {
967 if (!mode->bindings)
968 continue;
969 map_iterate(mode->bindings, binding_collect, vis->lua);
971 return 1;
974 /***
975 * Execute a motion.
977 * @function motion
978 * @tparam int id the id of the motion to execute
979 * @treturn bool whether the id was valid
980 * @local
982 static int motion(lua_State *L) {
983 Vis *vis = obj_ref_check(L, 1, "vis");
984 enum VisMotion id = luaL_checkunsigned(L, 2);
985 // TODO handle var args?
986 lua_pushboolean(L, vis && vis_motion(vis, id));
987 return 1;
990 static size_t motion_lua(Vis *vis, Win *win, void *data, size_t pos) {
991 lua_State *L = vis->lua;
992 if (!L || !func_ref_get(L, data) || !obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW))
993 return EPOS;
995 lua_pushunsigned(L, pos);
996 if (pcall(vis, L, 2, 1) != 0)
997 return EPOS;
998 return getpos(L, -1);
1001 /***
1002 * Register a custom motion.
1004 * @function motion_register
1005 * @tparam function motion the Lua function implementing the motion
1006 * @treturn int the associated motion id, or `-1` on failure
1007 * @see motion, motion_new
1008 * @local
1009 * @usage
1010 * -- custom motion advancing to the next byte
1011 * local id = vis:motion_register(function(win, pos)
1012 * return pos+1
1013 * end)
1015 static int motion_register(lua_State *L) {
1016 Vis *vis = obj_ref_check(L, 1, "vis");
1017 const void *func = func_ref_new(L, 2);
1018 int id = vis_motion_register(vis, (void*)func, motion_lua);
1019 lua_pushinteger(L, id);
1020 return 1;
1023 /***
1024 * Execute an operator.
1026 * @function operator
1027 * @tparam int id the id of the operator to execute
1028 * @treturn bool whether the id was valid
1029 * @local
1031 static int operator(lua_State *L) {
1032 Vis *vis = obj_ref_check(L, 1, "vis");
1033 enum VisOperator id = luaL_checkunsigned(L, 2);
1034 // TODO handle var args?
1035 lua_pushboolean(L, vis && vis_operator(vis, id));
1036 return 1;
1039 static size_t operator_lua(Vis *vis, Text *text, OperatorContext *c) {
1040 lua_State *L = vis->lua;
1041 if (!L || !func_ref_get(L, c->context))
1042 return EPOS;
1043 File *file = vis->files;
1044 while (file && (file->internal || file->text != text))
1045 file = file->next;
1046 if (!file || !obj_ref_new(L, file, VIS_LUA_TYPE_FILE))
1047 return EPOS;
1048 pushrange(L, &c->range);
1049 pushpos(L, c->pos);
1050 if (pcall(vis, L, 3, 1) != 0)
1051 return EPOS;
1052 return getpos(L, -1);
1055 /***
1056 * Register a custom operator.
1058 * @function operator_register
1059 * @tparam function operator the Lua function implementing the operator
1060 * @treturn int the associated operator id, or `-1` on failure
1061 * @see operator, operator_new
1062 * @local
1063 * @usage
1064 * -- custom operator replacing every 'a' with 'b'
1065 * local id = vis:operator_register(function(file, range, pos)
1066 * local data = file:content(range)
1067 * data = data:gsub("a", "b")
1068 * file:delete(range)
1069 * file:insert(range.start, data)
1070 * return range.start -- new cursor location
1071 * end)
1073 static int operator_register(lua_State *L) {
1074 Vis *vis = obj_ref_check(L, 1, "vis");
1075 const void *func = func_ref_new(L, 2);
1076 int id = vis_operator_register(vis, operator_lua, (void*)func);
1077 lua_pushinteger(L, id);
1078 return 1;
1081 /***
1082 * Execute a text object.
1084 * @function textobject
1085 * @tparam int id the id of the text object to execute
1086 * @treturn bool whether the id was valid
1087 * @see textobject_register, textobject_new
1088 * @local
1090 static int textobject(lua_State *L) {
1091 Vis *vis = obj_ref_check(L, 1, "vis");
1092 enum VisTextObject id = luaL_checkunsigned(L, 2);
1093 lua_pushboolean(L, vis_textobject(vis, id));
1094 return 1;
1097 static Filerange textobject_lua(Vis *vis, Win *win, void *data, size_t pos) {
1098 lua_State *L = vis->lua;
1099 if (!L || !func_ref_get(L, data) || !obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW))
1100 return text_range_empty();
1101 lua_pushunsigned(L, pos);
1102 if (pcall(vis, L, 2, 2) != 0 || lua_isnil(L, -1))
1103 return text_range_empty();
1104 return text_range_new(getpos(L, -2), getpos(L, -1));
1107 /***
1108 * Register a custom text object.
1110 * @function textobject_register
1111 * @tparam function textobject the Lua function implementing the text object
1112 * @treturn int the associated text object id, or `-1` on failure
1113 * @see textobject, textobject_new
1114 * @local
1115 * @usage
1116 * -- custom text object covering the next byte
1117 * local id = vis:textobject_register(function(win, pos)
1118 * return pos, pos+1
1119 * end)
1121 static int textobject_register(lua_State *L) {
1122 Vis *vis = obj_ref_check(L, 1, "vis");
1123 const void *func = func_ref_new(L, 2);
1124 int id = vis_textobject_register(vis, 0, (void*)func, textobject_lua);
1125 lua_pushinteger(L, id);
1126 return 1;
1129 static bool option_lua(Vis *vis, Win *win, void *context, bool toggle,
1130 enum VisOption flags, const char *name, Arg *value) {
1131 lua_State *L = vis->lua;
1132 if (!L || !func_ref_get(L, context))
1133 return false;
1134 if (flags & VIS_OPTION_TYPE_BOOL)
1135 lua_pushboolean(L, value->b);
1136 else if (flags & VIS_OPTION_TYPE_STRING)
1137 lua_pushstring(L, value->s);
1138 else if (flags & VIS_OPTION_TYPE_NUMBER)
1139 lua_pushnumber(L, value->i);
1140 else
1141 return false;
1142 lua_pushboolean(L, toggle);
1143 return pcall(vis, L, 2, 2) == 0 && (!lua_isboolean(L, -1) || lua_toboolean(L, -1));
1146 /***
1147 * Register a custom `:set` option.
1149 * @function option_register
1150 * @tparam string name the option name
1151 * @tparam string type the option type (`bool`, `string` or `number`)
1152 * @tparam function handler the Lua function being called when the option is changed
1153 * @tparam[opt] string help the single line help text as displayed in `:help`
1154 * @treturn bool whether the option was successfully registered
1155 * @usage
1156 * vis:option_register("foo", "bool", function(value, toogle)
1157 * if not vis.win then return false end
1158 * vis.win.foo = toogle and not vis.win.foo or value
1159 * vis:info("Option foo = " .. tostring(vis.win.foo))
1160 * return true
1161 * end, "Foo enables superpowers")
1163 static int option_register(lua_State *L) {
1164 Vis *vis = obj_ref_check(L, 1, "vis");
1165 const char *name = luaL_checkstring(L, 2);
1166 const char *type = luaL_checkstring(L, 3);
1167 const void *func = func_ref_new(L, 4);
1168 const char *help = luaL_optstring(L, 5, NULL);
1169 const char *names[] = { name, NULL };
1170 enum VisOption flags = 0;
1171 if (strcmp(type, "string") == 0)
1172 flags |= VIS_OPTION_TYPE_STRING;
1173 else if (strcmp(type, "number") == 0)
1174 flags |= VIS_OPTION_TYPE_NUMBER;
1175 else
1176 flags |= VIS_OPTION_TYPE_BOOL;
1177 bool ret = vis_option_register(vis, names, flags, option_lua, (void*)func, help);
1178 lua_pushboolean(L, ret);
1179 return 1;
1182 /***
1183 * Unregister a `:set` option.
1185 * @function option_unregister
1186 * @tparam string name the option name
1187 * @treturn bool whether the option was successfully unregistered
1189 static int option_unregister(lua_State *L) {
1190 Vis *vis = obj_ref_check(L, 1, "vis");
1191 const char *name = luaL_checkstring(L, 2);
1192 bool ret = vis_option_unregister(vis, name);
1193 lua_pushboolean(L, ret);
1194 return 1;
1197 static bool command_lua(Vis *vis, Win *win, void *data, bool force, const char *argv[], Selection *sel, Filerange *range) {
1198 lua_State *L = vis->lua;
1199 if (!L || !func_ref_get(L, data))
1200 return false;
1201 lua_newtable(L);
1202 for (size_t i = 0; argv[i]; i++) {
1203 lua_pushunsigned(L, i);
1204 lua_pushstring(L, argv[i]);
1205 lua_settable(L, -3);
1207 lua_pushboolean(L, force);
1208 if (!obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW))
1209 return false;
1210 if (!sel)
1211 sel = view_selections_primary_get(win->view);
1212 if (!obj_lightref_new(L, sel, VIS_LUA_TYPE_SELECTION))
1213 return false;
1214 pushrange(L, range);
1215 if (pcall(vis, L, 5, 1) != 0)
1216 return false;
1217 return lua_toboolean(L, -1);
1220 /***
1221 * Register a custom `:`-command.
1223 * @function command_register
1224 * @tparam string name the command name
1225 * @tparam function command the Lua function implementing the command
1226 * @tparam[opt] string help the single line help text as displayed in `:help`
1227 * @treturn bool whether the command has been successfully registered
1228 * @usage
1229 * vis:command_register("foo", function(argv, force, win, selection, range)
1230 * for i,arg in ipairs(argv) do
1231 * print(i..": "..arg)
1232 * end
1233 * print("was command forced with ! "..(force and "yes" or "no"))
1234 * print(win.file.name)
1235 * print(selection.pos)
1236 * print(range ~= nil and ('['..range.start..', '..range.finish..']') or "invalid range")
1237 * return true;
1238 * end)
1240 static int command_register(lua_State *L) {
1241 Vis *vis = obj_ref_check(L, 1, "vis");
1242 const char *name = luaL_checkstring(L, 2);
1243 const void *func = func_ref_new(L, 3);
1244 const char *help = luaL_optstring(L, 4, "");
1245 bool ret = vis_cmd_register(vis, name, help, (void*)func, command_lua);
1246 lua_pushboolean(L, ret);
1247 return 1;
1250 /***
1251 * Push keys to input queue and interpret them.
1253 * The keys are processed as if they were read from the keyboard.
1255 * @function feedkeys
1256 * @tparam string keys the keys to interpret
1258 static int feedkeys(lua_State *L) {
1259 Vis *vis = obj_ref_check(L, 1, "vis");
1260 const char *keys = luaL_checkstring(L, 2);
1261 vis_keys_feed(vis, keys);
1262 return 0;
1265 /***
1266 * Insert keys at all cursor positions of active window.
1268 * This function behaves as if the keys were entered in insert mode,
1269 * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
1270 * meaning mappings do not apply and the keys will not be recorded in macros.
1272 * @function insert
1273 * @tparam string keys the keys to insert
1274 * @see Vis:feedkeys
1276 static int insert(lua_State *L) {
1277 Vis *vis = obj_ref_check(L, 1, "vis");
1278 size_t len;
1279 const char *keys = luaL_checklstring(L, 2, &len);
1280 vis_insert_key(vis, keys, len);
1281 return 0;
1284 /***
1285 * Replace keys at all cursor positions of active window.
1287 * This function behaves as if the keys were entered in replace mode,
1288 * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
1289 * meaning mappings do not apply and the keys will not be recorded in macros.
1291 * @function replace
1292 * @tparam string keys the keys to insert
1293 * @see Vis:feedkeys
1295 static int replace(lua_State *L) {
1296 Vis *vis = obj_ref_check(L, 1, "vis");
1297 size_t len;
1298 const char *keys = luaL_checklstring(L, 2, &len);
1299 vis_replace_key(vis, keys, len);
1300 return 0;
1303 /***
1304 * Terminate editor process.
1306 * Termination happens upon the next iteration of the main event loop.
1307 * This means the calling Lua code will be executed further until it
1308 * eventually hands over control to the editor core. The exit status
1309 * of the most recent call is used.
1311 * All unsaved chanes will be lost!
1313 * @function exit
1314 * @tparam int code the exit status returned to the operating system
1316 static int exit_func(lua_State *L) {
1317 Vis *vis = obj_ref_check(L, 1, "vis");
1318 int code = luaL_checkint(L, 2);
1319 vis_exit(vis, code);
1320 return 0;
1323 /***
1324 * Pipe file range to external process and collect output.
1326 * The editor core will be blocked while the external process is running.
1328 * @function pipe
1329 * @tparam File file the file to which the range applies
1330 * @tparam Range range the range to pipe
1331 * @tparam string command the command to execute
1332 * @treturn int code the exit status of the executed command
1333 * @treturn string stdout the data written to stdout
1334 * @treturn string stderr the data written to stderr
1336 static int pipe_func(lua_State *L) {
1337 Vis *vis = obj_ref_check(L, 1, "vis");
1338 File *file = obj_ref_check(L, 2, VIS_LUA_TYPE_FILE);
1339 Filerange range = getrange(L, 3);
1340 const char *cmd = luaL_checkstring(L, 4);
1341 char *out = NULL, *err = NULL;
1342 int status = vis_pipe_collect(vis, file, &range, (const char*[]){ cmd, NULL }, &out, &err);
1343 lua_pushinteger(L, status);
1344 if (out)
1345 lua_pushstring(L, out);
1346 else
1347 lua_pushnil(L);
1348 free(out);
1349 if (err)
1350 lua_pushstring(L, err);
1351 else
1352 lua_pushnil(L);
1353 free(err);
1354 vis_draw(vis);
1355 return 3;
1357 /***
1358 * Redraw complete user interface.
1360 * Will trigger redraw events, make sure to avoid recursive events.
1362 * @function redraw
1364 static int redraw(lua_State *L) {
1365 Vis *vis = obj_ref_check(L, 1, "vis");
1366 vis_redraw(vis);
1367 return 0;
1369 /***
1370 * Currently active window.
1371 * @tfield Window win
1372 * @see windows
1374 /***
1375 * Currently active mode.
1376 * @tfield modes mode
1378 /***
1379 * Whether a macro is being recorded.
1380 * @tfield bool recording
1382 /***
1383 * Currently unconsumed keys in the input queue.
1384 * @tfield string input_queue
1386 /***
1387 * Register name in use.
1388 * @tfield string register
1390 /***
1391 * Mark name in use.
1392 * @tfield string mark
1394 static int vis_index(lua_State *L) {
1395 Vis *vis = obj_ref_check(L, 1, "vis");
1397 if (lua_isstring(L, 2)) {
1398 const char *key = lua_tostring(L, 2);
1399 if (strcmp(key, "win") == 0) {
1400 if (vis->win)
1401 obj_ref_new(L, vis->win, VIS_LUA_TYPE_WINDOW);
1402 else
1403 lua_pushnil(L);
1404 return 1;
1407 if (strcmp(key, "mode") == 0) {
1408 lua_pushunsigned(L, vis->mode->id);
1409 return 1;
1412 if (strcmp(key, "input_queue") == 0) {
1413 lua_pushstring(L, buffer_content0(&vis->input_queue));
1414 return 1;
1417 if (strcmp(key, "recording") == 0) {
1418 lua_pushboolean(L, vis_macro_recording(vis));
1419 return 1;
1422 if (strcmp(key, "count") == 0) {
1423 int count = vis_count_get(vis);
1424 if (count == VIS_COUNT_UNKNOWN)
1425 lua_pushnil(L);
1426 else
1427 lua_pushunsigned(L, count);
1428 return 1;
1431 if (strcmp(key, "register") == 0) {
1432 char name = vis_register_to(vis, vis_register_used(vis));
1433 lua_pushlstring(L, &name, 1);
1434 return 1;
1437 if (strcmp(key, "registers") == 0) {
1438 obj_ref_new(L, vis->ui, VIS_LUA_TYPE_REGISTERS);
1439 return 1;
1442 if (strcmp(key, "mark") == 0) {
1443 char name = vis_mark_to(vis, vis_mark_used(vis));
1444 lua_pushlstring(L, &name, 1);
1445 return 1;
1448 if (strcmp(key, "ui") == 0) {
1449 obj_ref_new(L, vis->ui, VIS_LUA_TYPE_UI);
1450 return 1;
1454 return index_common(L);
1457 static int vis_newindex(lua_State *L) {
1458 Vis *vis = obj_ref_check(L, 1, "vis");
1459 if (lua_isstring(L, 2)) {
1460 const char *key = lua_tostring(L, 2);
1461 if (strcmp(key, "mode") == 0) {
1462 enum VisMode mode = luaL_checkunsigned(L, 3);
1463 vis_mode_switch(vis, mode);
1464 return 0;
1467 if (strcmp(key, "count") == 0) {
1468 int count;
1469 if (lua_isnil(L, 3))
1470 count = VIS_COUNT_UNKNOWN;
1471 else
1472 count = luaL_checkunsigned(L, 3);
1473 vis_count_set(vis, count);
1474 return 0;
1477 if (strcmp(key, "win") == 0) {
1478 vis_window_focus(obj_ref_check(L, 3, VIS_LUA_TYPE_WINDOW));
1479 return 0;
1482 if (strcmp(key, "register") == 0) {
1483 const char *name = luaL_checkstring(L, 3);
1484 if (strlen(name) == 1)
1485 vis_register(vis, vis_register_from(vis, name[0]));
1486 return 0;
1489 if (strcmp(key, "mark") == 0) {
1490 const char *name = luaL_checkstring(L, 3);
1491 if (strlen(name) == 1)
1492 vis_mark(vis, vis_mark_from(vis, name[0]));
1493 return 0;
1496 return newindex_common(L);
1499 static const struct luaL_Reg vis_lua[] = {
1500 { "files", files },
1501 { "windows", windows },
1502 { "mark_names", mark_names },
1503 { "register_names", register_names },
1504 { "command", command },
1505 { "info", info },
1506 { "message", message },
1507 { "map", map },
1508 { "unmap", unmap },
1509 { "mappings", mappings },
1510 { "operator", operator },
1511 { "operator_register", operator_register },
1512 { "motion", motion },
1513 { "motion_register", motion_register },
1514 { "textobject", textobject },
1515 { "textobject_register", textobject_register },
1516 { "option_register", option_register },
1517 { "option_unregister", option_unregister },
1518 { "command_register", command_register },
1519 { "feedkeys", feedkeys },
1520 { "insert", insert },
1521 { "replace", replace },
1522 { "action_register", action_register },
1523 { "exit", exit_func },
1524 { "pipe", pipe_func },
1525 { "redraw", redraw },
1526 { "__index", vis_index },
1527 { "__newindex", vis_newindex },
1528 { NULL, NULL },
1531 static const struct luaL_Reg ui_funcs[] = {
1532 { "__index", index_common },
1533 { NULL, NULL },
1536 static int registers_index(lua_State *L) {
1537 lua_newtable(L);
1538 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
1539 const char *symbol = luaL_checkstring(L, 2);
1540 if (strlen(symbol) != 1)
1541 return 1;
1542 enum VisRegister reg = vis_register_from(vis, symbol[0]);
1543 if (reg >= VIS_REG_INVALID)
1544 return 1;
1545 Array data = vis_register_get(vis, reg);
1546 for (size_t i = 0, len = array_length(&data); i < len; i++) {
1547 TextString *string = array_get(&data, i);
1548 lua_pushunsigned(L, i+1);
1549 lua_pushlstring(L, string->data, string->len);
1550 lua_settable(L, -3);
1552 array_release(&data);
1553 return 1;
1556 static int registers_newindex(lua_State *L) {
1557 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
1558 const char *symbol = luaL_checkstring(L, 2);
1559 if (strlen(symbol) != 1)
1560 return 0;
1561 enum VisRegister reg = vis_register_from(vis, symbol[0]);
1562 Array data;
1563 array_init_sized(&data, sizeof(TextString));
1565 if (lua_istable(L, 3)) {
1566 lua_pushnil(L);
1567 while (lua_next(L, 3)) {
1568 TextString string;
1569 string.data = luaL_checklstring(L, -1, &string.len);
1570 array_add(&data, &string);
1571 lua_pop(L, 1);
1575 vis_register_set(vis, reg, &data);
1576 array_release(&data);
1577 return 0;
1580 static int registers_len(lua_State *L) {
1581 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
1582 lua_pushunsigned(L, LENGTH(vis->registers));
1583 return 1;
1586 static const struct luaL_Reg registers_funcs[] = {
1587 { "__index", registers_index },
1588 { "__newindex", registers_newindex },
1589 { "__len", registers_len },
1590 { NULL, NULL },
1593 /***
1594 * A window object.
1595 * @type Window
1598 /***
1599 * Viewport currently being displayed.
1600 * @tfield Range viewport
1602 /***
1603 * The window width.
1604 * @tfield int width
1606 /***
1607 * The window height.
1608 * @tfield int height
1610 /***
1611 * The file being displayed in this window.
1612 * @tfield File file
1614 /***
1615 * The primary selection of this window.
1616 * @tfield Selection selection
1618 /***
1619 * The selections of this window.
1620 * @tfield Array(Selection) selections
1622 /***
1623 * Window marks.
1624 * Most of these marks are stored in the associated File object, meaning they
1625 * are the same in all windows displaying the same file.
1626 * @field marks array to access the marks of this window by single letter name
1627 * @see Vis:marks_names
1629 static int window_index(lua_State *L) {
1630 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1632 if (lua_isstring(L, 2)) {
1633 const char *key = lua_tostring(L, 2);
1635 if (strcmp(key, "viewport") == 0) {
1636 Filerange r = view_viewport_get(win->view);
1637 pushrange(L, &r);
1638 return 1;
1641 if (strcmp(key, "width") == 0) {
1642 lua_pushunsigned(L, vis_window_width_get(win));
1643 return 1;
1646 if (strcmp(key, "height") == 0) {
1647 lua_pushunsigned(L, vis_window_height_get(win));
1648 return 1;
1651 if (strcmp(key, "file") == 0) {
1652 obj_ref_new(L, win->file, VIS_LUA_TYPE_FILE);
1653 return 1;
1656 if (strcmp(key, "selection") == 0) {
1657 Selection *sel = view_selections_primary_get(win->view);
1658 obj_lightref_new(L, sel, VIS_LUA_TYPE_SELECTION);
1659 return 1;
1662 if (strcmp(key, "selections") == 0) {
1663 obj_ref_new(L, win->view, VIS_LUA_TYPE_SELECTIONS);
1664 return 1;
1667 if (strcmp(key, "marks") == 0) {
1668 obj_ref_new(L, &win->saved_selections, VIS_LUA_TYPE_MARKS);
1669 return 1;
1673 return index_common(L);
1676 static int window_selections_iterator_next(lua_State *L) {
1677 Selection **handle = lua_touserdata(L, lua_upvalueindex(1));
1678 if (!*handle)
1679 return 0;
1680 Selection *sel = obj_lightref_new(L, *handle, VIS_LUA_TYPE_SELECTION);
1681 if (!sel)
1682 return 0;
1683 *handle = view_selections_next(sel);
1684 return 1;
1687 /***
1688 * Create an iterator over all selections of this window.
1689 * @function selections_iterator
1690 * @return the new iterator
1692 static int window_selections_iterator(lua_State *L) {
1693 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1694 Selection **handle = lua_newuserdata(L, sizeof *handle);
1695 *handle = view_selections(win->view);
1696 lua_pushcclosure(L, window_selections_iterator_next, 1);
1697 return 1;
1700 /***
1701 * Set up a window local key mapping.
1702 * The function signatures are the same as for @{Vis:map}.
1703 * @function map
1704 * @param ...
1705 * @see Vis:map
1707 static int window_map(lua_State *L) {
1708 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1709 return keymap(L, win->vis, win);
1712 /***
1713 * Remove a window local key mapping.
1714 * The function signature is the same as for @{Vis:unmap}.
1715 * @function unmap
1716 * @param ...
1717 * @see Vis:unmap
1719 static int window_unmap(lua_State *L) {
1720 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1721 return keyunmap(L, win->vis, win);
1724 /***
1725 * Define a display style.
1726 * @function style_define
1727 * @tparam int id the style id to use
1728 * @tparam string style the style definition
1729 * @treturn bool whether the style definition has been successfully
1730 * associated with the given id
1731 * @see style
1732 * @usage
1733 * win:style_define(win.STYLE_DEFAULT, "fore:red")
1735 static int window_style_define(lua_State *L) {
1736 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1737 enum UiStyle id = luaL_checkunsigned(L, 2);
1738 const char *style = luaL_checkstring(L, 3);
1739 bool ret = view_style_define(win->view, id, style);
1740 lua_pushboolean(L, ret);
1741 return 1;
1744 /***
1745 * Style a window range.
1747 * The style will be cleared after every window redraw.
1748 * @function style
1749 * @tparam int id the display style as registered with @{style_define}
1750 * @tparam int start the absolute file position in bytes
1751 * @tparam int finish the end position
1752 * @see style_define
1753 * @usage
1754 * win:style(win.STYLE_DEFAULT, 0, 10)
1756 static int window_style(lua_State *L) {
1757 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1758 enum UiStyle style = luaL_checkunsigned(L, 2);
1759 size_t start = checkpos(L, 3);
1760 size_t end = checkpos(L, 4);
1761 view_style(win->view, style, start, end);
1762 return 0;
1765 /***
1766 * Set window status line.
1768 * @function status
1769 * @tparam string left the left aligned part of the status line
1770 * @tparam[opt] string right the right aligned part of the status line
1772 static int window_status(lua_State *L) {
1773 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1774 char status[1024] = "";
1775 int width = vis_window_width_get(win);
1776 const char *left = luaL_checkstring(L, 2);
1777 const char *right = luaL_optstring(L, 3, "");
1778 int left_width = text_string_width(left, strlen(left));
1779 int right_width = text_string_width(right, strlen(right));
1780 int spaces = width - left_width - right_width;
1781 if (spaces < 1)
1782 spaces = 1;
1783 snprintf(status, sizeof(status)-1, "%s%*s%s", left, spaces, " ", right);
1784 vis_window_status(win, status);
1785 return 0;
1788 /***
1789 * Redraw window content.
1791 * @function draw
1793 static int window_draw(lua_State *L) {
1794 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1795 view_draw(win->view);
1796 return 0;
1799 /***
1800 * Close window.
1802 * After a successful call the Window reference becomes invalid and
1803 * must no longer be used. Attempting to close the last window will
1804 * always fail.
1806 * @function close
1807 * @see exit
1808 * @tparam bool force whether unsaved changes should be discarded
1809 * @treturn bool whether the window was closed
1811 static int window_close(lua_State *L) {
1812 Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW);
1813 int count = 0;
1814 for (Win *w = win->vis->windows; w; w = w->next) {
1815 if (!w->file->internal)
1816 count++;
1818 bool force = lua_isboolean(L, 2) && lua_toboolean(L, 2);
1819 bool close = count > 1 && (force || vis_window_closable(win));
1820 if (close)
1821 vis_window_close(win);
1822 lua_pushboolean(L, close);
1823 return 1;
1826 static const struct luaL_Reg window_funcs[] = {
1827 { "__index", window_index },
1828 { "__newindex", newindex_common },
1829 { "selections_iterator", window_selections_iterator },
1830 { "map", window_map },
1831 { "unmap", window_unmap },
1832 { "style_define", window_style_define },
1833 { "style", window_style },
1834 { "status", window_status },
1835 { "draw", window_draw },
1836 { "close", window_close },
1837 { NULL, NULL },
1840 static int window_selections_index(lua_State *L) {
1841 View *view = obj_ref_check(L, 1, VIS_LUA_TYPE_SELECTIONS);
1842 size_t index = luaL_checkunsigned(L, 2);
1843 size_t count = view_selections_count(view);
1844 if (index == 0 || index > count)
1845 goto err;
1846 for (Selection *s = view_selections(view); s; s = view_selections_next(s)) {
1847 if (!--index) {
1848 obj_lightref_new(L, s, VIS_LUA_TYPE_SELECTION);
1849 return 1;
1852 err:
1853 lua_pushnil(L);
1854 return 1;
1857 static int window_selections_len(lua_State *L) {
1858 View *view = obj_ref_check(L, 1, VIS_LUA_TYPE_SELECTIONS);
1859 lua_pushunsigned(L, view_selections_count(view));
1860 return 1;
1863 static const struct luaL_Reg window_selections_funcs[] = {
1864 { "__index", window_selections_index },
1865 { "__len", window_selections_len },
1866 { NULL, NULL },
1869 /***
1870 * A selection object.
1872 * A selection is a non-empty, directed range with two endpoints called
1873 * *cursor* and *anchor*. A selection can be anchored in which case
1874 * the anchor remains fixed while only the position of the cursor is
1875 * adjusted. For non-anchored selections both endpoints are updated. A
1876 * singleton selection covers one character on which both cursor and
1877 * anchor reside. There always exists a primary selection which remains
1878 * visible (i.e. changes to its position will adjust the viewport).
1880 * The range covered by a selection is represented as an interval whose
1881 * endpoints are absolute byte offsets from the start of the file.
1882 * Valid addresses are within the closed interval `[0, file.size]`.
1884 * Selections are currently implemented using character marks into
1885 * the underlying persistent
1886 * [text management data structure](https://github.com/martanne/vis/wiki/Text-management-using-a-piece-chain).
1888 * This has a few consequences you should be aware of:
1890 * - A selection becomes invalid when the delimiting boundaries of the underlying
1891 * text it is referencing is deleted:
1893 * -- leaves selection in an invalid state
1894 * win.file:delete(win.selection.pos, 1)
1895 * assert(win.selection.pos == nil)
1897 * Like a regular mark it will become valid again when the text is reverted
1898 * to the state before the deletion.
1900 * - Inserts after the selection position (`> selection.pos`) will not affect the
1901 * selection postion.
1903 * local pos = win.selection.pos
1904 * win.file:insert(pos+1, "-")
1905 * assert(win.selection.pos == pos)
1907 * - Non-cached inserts before the selection position (`<= selection.pos`) will
1908 * affect the mark and adjust the selection postion by the number of bytes
1909 * which were inserted.
1911 * local pos = win.selection.pos
1912 * win.file:insert(pos, "-")
1913 * assert(win.selection.pos == pos+1)
1915 * - Cached inserts before the selection position (`<= selection.pos`) will
1916 * not affect the selection position because the underlying text is replaced
1917 * inplace.
1919 * For these reasons it is generally recommended to update the selection position
1920 * after a modification. The general procedure amounts to:
1922 * 1. Read out the current selection position
1923 * 2. Perform text modifications
1924 * 3. Update the selection postion
1926 * This is what @{Vis:insert} and @{Vis:replace} do internally.
1928 * @type Selection
1929 * @usage
1930 * local data = "new text"
1931 * local pos = win.selection.pos
1932 * win.file:insert(pos, data)
1933 * win.selection.pos = pos + #data
1936 /***
1937 * The zero based byte position in the file.
1939 * Might be `nil` if the selection is in an invalid state.
1940 * Setting this field will move the cursor endpoint of the
1941 * selection to the given position.
1942 * @tfield int pos
1944 /***
1945 * The 1-based line the cursor of this selection resides on.
1947 * @tfield int line
1948 * @see to
1950 /***
1951 * The 1-based column position the cursor of this selection resides on.
1952 * @tfield int col
1953 * @see to
1955 /***
1956 * The 1-based selection index.
1957 * @tfield int number
1959 /***
1960 * The range covered by this selection.
1961 * @tfield Range range
1963 /***
1964 * Whether this selection is anchored.
1965 * @tfield bool anchored
1967 static int window_selection_index(lua_State *L) {
1968 Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
1969 if (!sel) {
1970 lua_pushnil(L);
1971 return 1;
1974 if (lua_isstring(L, 2)) {
1975 const char *key = lua_tostring(L, 2);
1976 if (strcmp(key, "pos") == 0) {
1977 pushpos(L, view_cursors_pos(sel));
1978 return 1;
1981 if (strcmp(key, "line") == 0) {
1982 lua_pushunsigned(L, view_cursors_line(sel));
1983 return 1;
1986 if (strcmp(key, "col") == 0) {
1987 lua_pushunsigned(L, view_cursors_col(sel));
1988 return 1;
1991 if (strcmp(key, "number") == 0) {
1992 lua_pushunsigned(L, view_selections_number(sel)+1);
1993 return 1;
1996 if (strcmp(key, "range") == 0) {
1997 Filerange range = view_selections_get(sel);
1998 pushrange(L, &range);
1999 return 1;
2002 if (strcmp(key, "anchored") == 0) {
2003 lua_pushboolean(L, view_selections_anchored(sel));
2004 return 1;
2009 return index_common(L);
2012 static int window_selection_newindex(lua_State *L) {
2013 Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
2014 if (!sel)
2015 return 0;
2016 if (lua_isstring(L, 2)) {
2017 const char *key = lua_tostring(L, 2);
2018 if (strcmp(key, "pos") == 0) {
2019 size_t pos = checkpos(L, 3);
2020 view_cursors_to(sel, pos);
2021 return 0;
2024 if (strcmp(key, "range") == 0) {
2025 Filerange range = getrange(L, 3);
2026 if (text_range_valid(&range)) {
2027 view_selections_set(sel, &range);
2028 view_selections_anchor(sel, true);
2029 } else {
2030 view_selection_clear(sel);
2032 return 0;
2035 if (strcmp(key, "anchored") == 0) {
2036 view_selections_anchor(sel, lua_toboolean(L, 3));
2037 return 0;
2040 return newindex_common(L);
2043 /***
2044 * Move cursor of selection.
2045 * @function to
2046 * @tparam int line the 1-based line number
2047 * @tparam int col the 1-based column number
2049 static int window_selection_to(lua_State *L) {
2050 Selection *sel = obj_lightref_check(L, 1, VIS_LUA_TYPE_SELECTION);
2051 if (sel) {
2052 size_t line = checkpos(L, 2);
2053 size_t col = checkpos(L, 3);
2054 view_cursors_place(sel, line, col);
2056 return 0;
2059 static const struct luaL_Reg window_selection_funcs[] = {
2060 { "__index", window_selection_index },
2061 { "__newindex", window_selection_newindex },
2062 { "to", window_selection_to },
2063 { NULL, NULL },
2066 /***
2067 * A file object.
2068 * @type File
2070 /***
2071 * File name.
2072 * @tfield string name the file name relative to current working directory or `nil` if not yet named
2074 /***
2075 * File path.
2076 * @tfield string path the absolute file path or `nil` if not yet named
2078 /***
2079 * File content by logical lines.
2081 * Assigning to array element `0` (`#lines+1`) will insert a new line at
2082 * the beginning (end) of the file.
2083 * @tfield Array(string) lines the file content accessible as 1-based array
2084 * @see content
2085 * @usage
2086 * local lines = vis.win.file.lines
2087 * for i=1, #lines do
2088 * lines[i] = i .. ": " .. lines[i]
2089 * end
2091 /***
2092 * File size in bytes.
2093 * @tfield int size the current file size in bytes
2095 /***
2096 * File state.
2097 * @tfield bool modified whether the file contains unsaved changes
2099 static int file_index(lua_State *L) {
2100 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2102 if (lua_isstring(L, 2)) {
2103 const char *key = lua_tostring(L, 2);
2104 if (strcmp(key, "name") == 0) {
2105 lua_pushstring(L, file_name_get(file));
2106 return 1;
2109 if (strcmp(key, "path") == 0) {
2110 lua_pushstring(L, file->name);
2111 return 1;
2114 if (strcmp(key, "lines") == 0) {
2115 obj_ref_new(L, file->text, VIS_LUA_TYPE_TEXT);
2116 return 1;
2119 if (strcmp(key, "size") == 0) {
2120 lua_pushunsigned(L, text_size(file->text));
2121 return 1;
2124 if (strcmp(key, "modified") == 0) {
2125 lua_pushboolean(L, text_modified(file->text));
2126 return 1;
2130 return index_common(L);
2133 static int file_newindex(lua_State *L) {
2134 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2136 if (lua_isstring(L, 2)) {
2137 const char *key = lua_tostring(L, 2);
2139 if (strcmp(key, "modified") == 0) {
2140 bool modified = lua_isboolean(L, 3) && lua_toboolean(L, 3);
2141 if (modified) {
2142 text_insert(file->text, 0, " ", 1);
2143 text_delete(file->text, 0, 1);
2144 } else {
2145 text_save(file->text, NULL);
2147 return 0;
2151 return newindex_common(L);
2154 /***
2155 * Insert data at position.
2156 * @function insert
2157 * @tparam int pos the 0-based file position in bytes
2158 * @tparam string data the data to insert
2159 * @treturn bool whether the file content was successfully changed
2161 static int file_insert(lua_State *L) {
2162 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2163 size_t pos = checkpos(L, 2);
2164 size_t len;
2165 luaL_checkstring(L, 3);
2166 const char *data = lua_tolstring(L, 3, &len);
2167 lua_pushboolean(L, text_insert(file->text, pos, data, len));
2168 return 1;
2171 /***
2172 * Delete data at position.
2174 * @function delete
2175 * @tparam int pos the 0-based file position in bytes
2176 * @tparam int len the length in bytes to delete
2177 * @treturn bool whether the file content was successfully changed
2179 /***
2180 * Delete file range.
2182 * @function delete
2183 * @tparam Range range the range to delete
2184 * @treturn bool whether the file content was successfully changed
2186 static int file_delete(lua_State *L) {
2187 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2188 Filerange range = getrange(L, 2);
2189 lua_pushboolean(L, text_delete_range(file->text, &range));
2190 return 1;
2193 /***
2194 * Create an iterator over all lines of the file.
2196 * For large files this is probably faster than @{lines}.
2197 * @function lines_iterator
2198 * @return the new iterator
2199 * @see lines
2200 * @usage
2201 * for line in file:lines_iterator() do
2202 * -- do something with line
2203 * end
2205 static int file_lines_iterator_it(lua_State *L);
2206 static int file_lines_iterator(lua_State *L) {
2207 /* need to check second parameter first, because obj_ref_check_get
2208 * modifies the stack */
2209 size_t line = luaL_optunsigned(L, 2, 1);
2210 File *file = obj_ref_check_get(L, 1, VIS_LUA_TYPE_FILE);
2211 size_t *pos = lua_newuserdata(L, sizeof *pos);
2212 *pos = text_pos_by_lineno(file->text, line);
2213 lua_pushcclosure(L, file_lines_iterator_it, 2);
2214 return 1;
2217 static int file_lines_iterator_it(lua_State *L) {
2218 File *file = *(File**)lua_touserdata(L, lua_upvalueindex(1));
2219 size_t *start = lua_touserdata(L, lua_upvalueindex(2));
2220 if (*start == text_size(file->text))
2221 return 0;
2222 size_t end = text_line_end(file->text, *start);
2223 size_t len = end - *start;
2224 char *buf = lua_newuserdata(L, len);
2225 if (!buf && len)
2226 return 0;
2227 len = text_bytes_get(file->text, *start, len, buf);
2228 lua_pushlstring(L, buf, len);
2229 *start = text_line_next(file->text, end);
2230 return 1;
2233 /***
2234 * Get file content of position and length.
2236 * @function content
2237 * @tparam int pos the 0-based file position in bytes
2238 * @tparam int len the length in bytes to read
2239 * @treturn string the file content corresponding to the range
2240 * @see lines
2241 * @usage
2242 * local file = vis.win.file
2243 * local text = file:content(0, file.size)
2245 /***
2246 * Get file content of range.
2248 * @function content
2249 * @tparam Range range the range to read
2250 * @treturn string the file content corresponding to the range
2252 static int file_content(lua_State *L) {
2253 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2254 Filerange range = getrange(L, 2);
2255 if (!text_range_valid(&range))
2256 goto err;
2257 size_t len = text_range_size(&range);
2258 char *data = lua_newuserdata(L, len);
2259 if (!data)
2260 goto err;
2261 len = text_bytes_get(file->text, range.start, len, data);
2262 lua_pushlstring(L, data, len);
2263 return 1;
2264 err:
2265 lua_pushnil(L);
2266 return 1;
2269 /***
2270 * Set mark.
2271 * @function mark_set
2272 * @tparam int pos the position to set the mark to, must be in [0, file.size]
2273 * @treturn Mark mark the mark which can be looked up later
2275 static int file_mark_set(lua_State *L) {
2276 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2277 size_t pos = checkpos(L, 2);
2278 Mark mark = text_mark_set(file->text, pos);
2279 if (mark)
2280 obj_lightref_new(L, (void*)mark, VIS_LUA_TYPE_MARK);
2281 else
2282 lua_pushnil(L);
2283 return 1;
2286 /***
2287 * Get position of mark.
2288 * @function mark_get
2289 * @tparam Mark mark the mark to look up
2290 * @treturn int pos the position of the mark, or `nil` if invalid
2292 static int file_mark_get(lua_State *L) {
2293 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2294 Mark mark = (Mark)obj_lightref_check(L, 2, VIS_LUA_TYPE_MARK);
2295 size_t pos = text_mark_get(file->text, mark);
2296 if (pos == EPOS)
2297 lua_pushnil(L);
2298 else
2299 lua_pushunsigned(L, pos);
2300 return 1;
2303 /***
2304 * Word text object.
2306 * @function text_object_word
2307 * @tparam int pos the position which must be part of the word
2308 * @treturn Range range the range
2311 /***
2312 * WORD text object.
2314 * @function text_object_longword
2315 * @tparam int pos the position which must be part of the word
2316 * @treturn Range range the range
2319 static int file_text_object(lua_State *L) {
2320 Filerange range = text_range_empty();
2321 File *file = obj_ref_check(L, 1, VIS_LUA_TYPE_FILE);
2322 size_t pos = checkpos(L, 2);
2323 size_t idx = lua_tointeger(L, lua_upvalueindex(1));
2324 if (idx < LENGTH(vis_textobjects)) {
2325 const TextObject *txtobj = &vis_textobjects[idx];
2326 if (txtobj->txt)
2327 range = txtobj->txt(file->text, pos);
2329 pushrange(L, &range);
2330 return 1;
2333 static const struct luaL_Reg file_funcs[] = {
2334 { "__index", file_index },
2335 { "__newindex", file_newindex },
2336 { "insert", file_insert },
2337 { "delete", file_delete },
2338 { "lines_iterator", file_lines_iterator },
2339 { "content", file_content },
2340 { "mark_set", file_mark_set },
2341 { "mark_get", file_mark_get },
2342 { NULL, NULL },
2345 static int file_lines_index(lua_State *L) {
2346 Text *txt = obj_ref_check(L, 1, VIS_LUA_TYPE_TEXT);
2347 size_t line = luaL_checkunsigned(L, 2);
2348 size_t start = text_pos_by_lineno(txt, line);
2349 size_t end = text_line_end(txt, start);
2350 if (start != EPOS && end != EPOS) {
2351 size_t size = end - start;
2352 char *data = lua_newuserdata(L, size);
2353 if (!data && size)
2354 goto err;
2355 size = text_bytes_get(txt, start, size, data);
2356 lua_pushlstring(L, data, size);
2357 return 1;
2359 err:
2360 lua_pushnil(L);
2361 return 1;
2364 static int file_lines_newindex(lua_State *L) {
2365 Text *txt = obj_ref_check(L, 1, VIS_LUA_TYPE_TEXT);
2366 size_t line = luaL_checkunsigned(L, 2);
2367 size_t size;
2368 const char *data = luaL_checklstring(L, 3, &size);
2369 if (line == 0) {
2370 text_insert(txt, 0, data, size);
2371 text_insert(txt, size, "\n", 1);
2372 return 0;
2374 size_t start = text_pos_by_lineno(txt, line);
2375 size_t end = text_line_end(txt, start);
2376 if (start != EPOS && end != EPOS) {
2377 text_delete(txt, start, end - start);
2378 text_insert(txt, start, data, size);
2379 if (text_size(txt) == start + size)
2380 text_insert(txt, text_size(txt), "\n", 1);
2382 return 0;
2385 static int file_lines_len(lua_State *L) {
2386 Text *txt = obj_ref_check(L, 1, VIS_LUA_TYPE_TEXT);
2387 size_t lines = 0;
2388 char lastchar;
2389 size_t size = text_size(txt);
2390 if (size > 0)
2391 lines = text_lineno_by_pos(txt, size);
2392 if (lines > 1 && text_byte_get(txt, size-1, &lastchar) && lastchar == '\n')
2393 lines--;
2394 lua_pushunsigned(L, lines);
2395 return 1;
2398 static const struct luaL_Reg file_lines_funcs[] = {
2399 { "__index", file_lines_index },
2400 { "__newindex", file_lines_newindex },
2401 { "__len", file_lines_len },
2402 { NULL, NULL },
2405 static int window_marks_index(lua_State *L) {
2406 lua_newtable(L);
2407 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
2408 Win *win = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_MARKS, offsetof(Win, saved_selections));
2409 if (!win)
2410 return 1;
2411 const char *symbol = luaL_checkstring(L, 2);
2412 if (strlen(symbol) != 1)
2413 return 1;
2414 enum VisMark mark = vis_mark_from(vis, symbol[0]);
2415 if (mark == VIS_MARK_INVALID)
2416 return 1;
2418 Array arr = vis_mark_get(win, mark);
2419 for (size_t i = 0, len = array_length(&arr); i < len; i++) {
2420 Filerange *range = array_get(&arr, i);
2421 lua_pushunsigned(L, i+1);
2422 pushrange(L, range);
2423 lua_settable(L, -3);
2425 array_release(&arr);
2426 return 1;
2429 static int window_marks_newindex(lua_State *L) {
2430 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
2431 Win *win = obj_ref_check_containerof(L, 1, VIS_LUA_TYPE_MARKS, offsetof(Win, saved_selections));
2432 if (!win)
2433 return 0;
2434 const char *symbol = luaL_checkstring(L, 2);
2435 if (strlen(symbol) != 1)
2436 return 0;
2437 enum VisMark mark = vis_mark_from(vis, symbol[0]);
2438 if (mark == VIS_MARK_INVALID)
2439 return 0;
2441 Array ranges;
2442 array_init_sized(&ranges, sizeof(Filerange));
2444 if (lua_istable(L, 3)) {
2445 lua_pushnil(L);
2446 while (lua_next(L, 3)) {
2447 Filerange range = getrange(L, -1);
2448 if (text_range_valid(&range))
2449 array_add(&ranges, &range);
2450 lua_pop(L, 1);
2454 vis_mark_set(win, mark, &ranges);
2455 array_release(&ranges);
2456 return 0;
2459 static int window_marks_len(lua_State *L) {
2460 lua_pushunsigned(L, VIS_MARK_INVALID);
2461 return 1;
2464 static const struct luaL_Reg window_marks_funcs[] = {
2465 { "__index", window_marks_index },
2466 { "__newindex", window_marks_newindex },
2467 { "__len", window_marks_len },
2468 { NULL, NULL },
2471 /***
2472 * The user interface.
2474 * @type Ui
2476 /***
2477 * Number of available colors.
2478 * @tfield int colors
2481 /***
2482 * A file range.
2484 * For a valid range `start <= finish` holds.
2485 * An invalid range is represented as `nil`.
2486 * @type Range
2488 /***
2489 * The beginning of the range.
2490 * @tfield int start
2492 /***
2493 * The end of the range.
2494 * @tfield int finish
2497 /***
2498 * Modes.
2499 * @section Modes
2502 /***
2503 * Mode constants.
2504 * @table modes
2505 * @tfield int NORMAL
2506 * @tfield int OPERATOR_PENDING
2507 * @tfield int INSERT
2508 * @tfield int REPLACE
2509 * @tfield int VISUAL
2510 * @tfield int VISUAL_LINE
2511 * @see Vis:map
2512 * @see Window:map
2515 /***
2516 * Key Handling.
2518 * This section describes the contract between the editor core and Lua
2519 * key handling functions mapped to symbolic keys using either @{Vis:map}
2520 * or @{Window:map}.
2522 * @section Key_Handling
2525 /***
2526 * Example of a key handling function.
2528 * The keyhandler is invoked with the pending content of the input queue
2529 * given as argument. This might be the empty string if no further input
2530 * is available.
2532 * The function is expected to return the number of *bytes* it has
2533 * consumed from the passed input keys. A negative return value is
2534 * interpreted as an indication that not enough input was available. The
2535 * function will be called again once the user has provided more input. A
2536 * missing return value (i.e. `nil`) is interpreted as zero, meaning
2537 * no further input was consumed but the function completed successfully.
2539 * @function keyhandler
2540 * @tparam string keys the keys following the mapping
2541 * @treturn int the number of *bytes* being consumed by the function (see above)
2542 * @see Vis:action_register
2543 * @see Vis:map
2544 * @see Window:map
2545 * @usage
2546 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
2547 * if #keys < 2 then
2548 * return -1 -- need more input
2549 * end
2550 * local digraph = keys:sub(1, 2)
2551 * if digraph == "l*" then
2552 * vis:feedkeys('λ')
2553 * return 2 -- consume 2 bytes of input
2554 * end
2555 * end, "Insert digraph")
2558 /***
2559 * Core Events.
2561 * These events are invoked from the editor core.
2562 * The following functions are invoked if they are registered in the
2563 * `vis.events` table. Users scripts should generally use the [Events](#events)
2564 * mechanism instead which multiplexes these core events.
2566 * @section Core_Events
2569 static void vis_lua_event_get(lua_State *L, const char *name) {
2570 lua_getglobal(L, "vis");
2571 lua_getfield(L, -1, "events");
2572 if (lua_istable(L, -1)) {
2573 lua_getfield(L, -1, name);
2575 lua_remove(L, -2);
2578 static void vis_lua_event_call(Vis *vis, const char *name) {
2579 lua_State *L = vis->lua;
2580 vis_lua_event_get(L, name);
2581 if (lua_isfunction(L, -1))
2582 pcall(vis, L, 0, 0);
2583 lua_pop(L, 1);
2586 static bool vis_lua_path_strip(Vis *vis) {
2587 lua_State *L = vis->lua;
2588 lua_getglobal(L, "package");
2590 for (const char **var = (const char*[]){ "path", "cpath", NULL }; *var; var++) {
2592 lua_getfield(L, -1, *var);
2593 const char *path = lua_tostring(L, -1);
2594 lua_pop(L, 1);
2595 if (!path)
2596 return false;
2598 char *copy = strdup(path), *stripped = calloc(1, strlen(path)+2);
2599 if (!copy || !stripped) {
2600 free(copy);
2601 free(stripped);
2602 return false;
2605 for (char *elem = copy, *stripped_elem = stripped, *next; elem; elem = next) {
2606 if ((next = strstr(elem, ";")))
2607 *next++ = '\0';
2608 if (strstr(elem, "./"))
2609 continue; /* skip relative path entries */
2610 stripped_elem += sprintf(stripped_elem, "%s;", elem);
2613 lua_pushstring(L, stripped);
2614 lua_setfield(L, -2, *var);
2616 free(copy);
2617 free(stripped);
2620 lua_pop(L, 1); /* package */
2621 return true;
2624 bool vis_lua_path_add(Vis *vis, const char *path) {
2625 lua_State *L = vis->lua;
2626 if (!L || !path)
2627 return false;
2628 lua_getglobal(L, "package");
2629 lua_pushstring(L, path);
2630 lua_pushstring(L, "/?.lua;");
2631 lua_pushstring(L, path);
2632 lua_pushstring(L, "/?/init.lua;");
2633 lua_getfield(L, -5, "path");
2634 lua_concat(L, 5);
2635 lua_setfield(L, -2, "path");
2636 lua_pop(L, 1); /* package */
2637 return true;
2640 bool vis_lua_paths_get(Vis *vis, char **lpath, char **cpath) {
2641 lua_State *L = vis->lua;
2642 if (!L)
2643 return false;
2644 const char *s;
2645 lua_getglobal(L, "package");
2646 lua_getfield(L, -1, "path");
2647 s = lua_tostring(L, -1);
2648 *lpath = s ? strdup(s) : NULL;
2649 lua_getfield(L, -2, "cpath");
2650 s = lua_tostring(L, -1);
2651 *cpath = s ? strdup(s) : NULL;
2652 return true;
2655 static bool package_exist(Vis *vis, lua_State *L, const char *name) {
2656 const char lua[] =
2657 "local name = ...\n"
2658 "for _, searcher in ipairs(package.searchers or package.loaders) do\n"
2659 "local loader = searcher(name)\n"
2660 "if type(loader) == 'function' then\n"
2661 "return true\n"
2662 "end\n"
2663 "end\n"
2664 "return false\n";
2665 if (luaL_loadstring(L, lua) != LUA_OK)
2666 return false;
2667 lua_pushstring(L, name);
2668 /* an error indicates package exists */
2669 bool ret = lua_pcall(L, 1, 1, 0) != LUA_OK || lua_toboolean(L, -1);
2670 lua_pop(L, 1);
2671 return ret;
2674 static void *alloc_lua(void *ud, void *ptr, size_t osize, size_t nsize) {
2675 if (nsize == 0) {
2676 free(ptr);
2677 return NULL;
2678 } else {
2679 return realloc(ptr, nsize);
2683 /***
2684 * Editor initialization completed.
2685 * This event is emitted immediately after `visrc.lua` has been sourced, but
2686 * before any other events have occured, in particular the command line arguments
2687 * have not yet been processed.
2689 * Can be used to set *global* configuration options.
2690 * @function init
2692 void vis_lua_init(Vis *vis) {
2693 lua_State *L = lua_newstate(alloc_lua, vis);
2694 if (!L)
2695 return;
2696 vis->lua = L;
2697 lua_atpanic(L, &panic_handler);
2699 luaL_openlibs(L);
2701 #if CONFIG_LPEG
2702 extern int luaopen_lpeg(lua_State *L);
2703 lua_getglobal(L, "package");
2704 lua_getfield(L, -1, "preload");
2705 lua_pushcfunction(L, luaopen_lpeg);
2706 lua_setfield(L, -2, "lpeg");
2707 lua_pop(L, 2);
2708 #endif
2710 /* remove any relative paths from lua's default package.path */
2711 vis_lua_path_strip(vis);
2713 /* extends lua's package.path with:
2714 * - $VIS_PATH
2715 * - ./lua (relative path to the binary location)
2716 * - $XDG_CONFIG_HOME/vis (defaulting to $HOME/.config/vis)
2717 * - /etc/vis (for system-wide configuration provided by administrator)
2718 * - /usr/(local/)?share/vis (or whatever is specified during ./configure)
2719 * - package.path (standard lua search path)
2721 char path[PATH_MAX];
2723 vis_lua_path_add(vis, VIS_PATH);
2725 /* try to get users home directory */
2726 const char *home = getenv("HOME");
2727 if (!home || !*home) {
2728 struct passwd *pw = getpwuid(getuid());
2729 if (pw)
2730 home = pw->pw_dir;
2733 vis_lua_path_add(vis, "/etc/vis");
2735 const char *xdg_config = getenv("XDG_CONFIG_HOME");
2736 if (xdg_config) {
2737 snprintf(path, sizeof path, "%s/vis", xdg_config);
2738 vis_lua_path_add(vis, path);
2739 } else if (home && *home) {
2740 snprintf(path, sizeof path, "%s/.config/vis", home);
2741 vis_lua_path_add(vis, path);
2744 ssize_t len = readlink("/proc/self/exe", path, sizeof(path)-1);
2745 if (len > 0) {
2746 path[len] = '\0';
2747 /* some idotic dirname(3) implementations return pointers to statically
2748 * allocated memory, hence we use memmove to copy it back */
2749 char *dir = dirname(path);
2750 if (dir) {
2751 size_t len = strlen(dir)+1;
2752 if (len < sizeof(path) - sizeof("/lua")) {
2753 memmove(path, dir, len);
2754 strcat(path, "/lua");
2755 vis_lua_path_add(vis, path);
2760 vis_lua_path_add(vis, getenv("VIS_PATH"));
2762 /* table in registry to lookup object type, stores metatable -> type mapping */
2763 lua_newtable(L);
2764 lua_setfield(L, LUA_REGISTRYINDEX, "vis.types");
2765 /* table in registry to track lifetimes of C objects */
2766 lua_newtable(L);
2767 lua_setfield(L, LUA_REGISTRYINDEX, "vis.objects");
2768 /* table in registry to store references to Lua functions */
2769 lua_newtable(L);
2770 lua_setfield(L, LUA_REGISTRYINDEX, "vis.functions");
2771 /* metatable used to type check user data */
2772 obj_type_new(L, VIS_LUA_TYPE_VIS);
2773 luaL_setfuncs(L, vis_lua, 0);
2774 lua_newtable(L);
2775 lua_setfield(L, -2, "types");
2776 /* create reference to main vis object, such that the further
2777 * calls to obj_type_new can register the type meta tables in
2778 * vis.types[name] */
2779 obj_ref_new(L, vis, "vis");
2780 lua_setglobal(L, "vis");
2782 obj_type_new(L, VIS_LUA_TYPE_FILE);
2784 const struct {
2785 enum VisTextObject id;
2786 const char *name;
2787 } textobjects[] = {
2788 { VIS_TEXTOBJECT_INNER_WORD, "text_object_word" },
2789 { VIS_TEXTOBJECT_INNER_LONGWORD, "text_object_longword" },
2792 for (size_t i = 0; i < LENGTH(textobjects); i++) {
2793 lua_pushunsigned(L, textobjects[i].id);
2794 lua_pushcclosure(L, file_text_object, 1);
2795 lua_setfield(L, -2, textobjects[i].name);
2798 luaL_setfuncs(L, file_funcs, 0);
2800 obj_type_new(L, VIS_LUA_TYPE_TEXT);
2801 luaL_setfuncs(L, file_lines_funcs, 0);
2802 obj_type_new(L, VIS_LUA_TYPE_WINDOW);
2803 luaL_setfuncs(L, window_funcs, 0);
2805 const struct {
2806 enum UiStyle id;
2807 const char *name;
2808 } styles[] = {
2809 { UI_STYLE_DEFAULT, "STYLE_DEFAULT" },
2810 { UI_STYLE_CURSOR, "STYLE_CURSOR" },
2811 { UI_STYLE_CURSOR_PRIMARY, "STYLE_CURSOR_PRIMARY" },
2812 { UI_STYLE_CURSOR_LINE, "STYLE_CURSOR_LINE" },
2813 { UI_STYLE_SELECTION, "STYLE_SELECTION" },
2814 { UI_STYLE_LINENUMBER, "STYLE_LINENUMBER" },
2815 { UI_STYLE_LINENUMBER_CURSOR, "STYLE_LINENUMBER_CURSOR" },
2816 { UI_STYLE_COLOR_COLUMN, "STYLE_COLOR_COLUMN" },
2817 { UI_STYLE_STATUS, "STYLE_STATUS" },
2818 { UI_STYLE_STATUS_FOCUSED, "STYLE_STATUS_FOCUSED" },
2819 { UI_STYLE_SEPARATOR, "STYLE_SEPARATOR" },
2820 { UI_STYLE_INFO, "STYLE_INFO" },
2821 { UI_STYLE_EOF, "STYLE_EOF" },
2824 for (size_t i = 0; i < LENGTH(styles); i++) {
2825 lua_pushunsigned(L, styles[i].id);
2826 lua_setfield(L, -2, styles[i].name);
2829 obj_type_new(L, VIS_LUA_TYPE_MARK);
2830 obj_type_new(L, VIS_LUA_TYPE_MARKS);
2831 lua_pushlightuserdata(L, vis);
2832 luaL_setfuncs(L, window_marks_funcs, 1);
2834 obj_type_new(L, VIS_LUA_TYPE_SELECTION);
2835 luaL_setfuncs(L, window_selection_funcs, 0);
2836 obj_type_new(L, VIS_LUA_TYPE_SELECTIONS);
2837 luaL_setfuncs(L, window_selections_funcs, 0);
2839 obj_type_new(L, VIS_LUA_TYPE_UI);
2840 luaL_setfuncs(L, ui_funcs, 0);
2841 lua_pushunsigned(L, vis->ui->colors(vis->ui));
2842 lua_setfield(L, -2, "colors");
2844 obj_type_new(L, VIS_LUA_TYPE_REGISTERS);
2845 lua_pushlightuserdata(L, vis);
2846 luaL_setfuncs(L, registers_funcs, 1);
2848 obj_type_new(L, VIS_LUA_TYPE_KEYACTION);
2850 lua_getglobal(L, "vis");
2851 lua_getmetatable(L, -1);
2853 lua_pushstring(L, VERSION);
2854 lua_setfield(L, -2, "VERSION");
2856 lua_newtable(L);
2858 static const struct {
2859 enum VisMode id;
2860 const char *name;
2861 } modes[] = {
2862 { VIS_MODE_NORMAL, "NORMAL" },
2863 { VIS_MODE_OPERATOR_PENDING, "OPERATOR_PENDING" },
2864 { VIS_MODE_VISUAL, "VISUAL" },
2865 { VIS_MODE_VISUAL_LINE, "VISUAL_LINE" },
2866 { VIS_MODE_INSERT, "INSERT" },
2867 { VIS_MODE_REPLACE, "REPLACE" },
2870 for (size_t i = 0; i < LENGTH(modes); i++) {
2871 lua_pushunsigned(L, modes[i].id);
2872 lua_setfield(L, -2, modes[i].name);
2875 lua_setfield(L, -2, "modes");
2877 if (!package_exist(vis, L, "visrc")) {
2878 vis_info_show(vis, "WARNING: failed to load visrc.lua");
2879 } else {
2880 lua_getglobal(L, "require");
2881 lua_pushstring(L, "visrc");
2882 pcall(vis, L, 1, 0);
2883 vis_lua_event_call(vis, "init");
2887 /***
2888 * Editor startup completed.
2889 * This event is emitted immediately before the main loop starts.
2890 * At this point all files are loaded and corresponding windows are created.
2891 * We are about to process interactive keyboard input.
2892 * @function start
2894 void vis_lua_start(Vis *vis) {
2895 vis_lua_event_call(vis, "start");
2899 * Editor is about to terminate.
2900 * @function quit
2902 void vis_lua_quit(Vis *vis) {
2903 if (!vis->lua)
2904 return;
2905 vis_lua_event_call(vis, "quit");
2906 lua_close(vis->lua);
2907 vis->lua = NULL;
2910 /***
2911 * Input key event in either input or replace mode.
2912 * @function input
2913 * @tparam string key
2914 * @treturn bool whether the key was cosumed or not
2916 static bool vis_lua_input(Vis *vis, const char *key, size_t len) {
2917 lua_State *L = vis->lua;
2918 if (!L || !vis->win || vis->win->file->internal)
2919 return false;
2920 bool ret = false;
2921 vis_lua_event_get(L, "input");
2922 if (lua_isfunction(L, -1)) {
2923 lua_pushlstring(L, key, len);
2924 if (pcall(vis, L, 1, 1) == 0) {
2925 ret = lua_isboolean(L, -1) && lua_toboolean(L, -1);
2926 lua_pop(L, 1);
2929 lua_pop(L, 1);
2930 return ret;
2933 void vis_lua_mode_insert_input(Vis *vis, const char *key, size_t len) {
2934 if (!vis_lua_input(vis, key, len))
2935 vis_insert_key(vis, key, len);
2938 void vis_lua_mode_replace_input(Vis *vis, const char *key, size_t len) {
2939 if (!vis_lua_input(vis, key, len))
2940 vis_replace_key(vis, key, len);
2943 /***
2944 * File open.
2945 * @function file_open
2946 * @tparam File file the file to be opened
2948 void vis_lua_file_open(Vis *vis, File *file) {
2949 debug("event: file-open: %s %p %p\n", file->name ? file->name : "unnamed", (void*)file, (void*)file->text);
2950 lua_State *L = vis->lua;
2951 if (!L)
2952 return;
2953 vis_lua_event_get(L, "file_open");
2954 if (lua_isfunction(L, -1)) {
2955 obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
2956 pcall(vis, L, 1, 0);
2958 lua_pop(L, 1);
2961 /***
2962 * File pre save.
2963 * Triggered *before* the file is being written.
2964 * @function file_save_pre
2965 * @tparam File file the file being written
2966 * @tparam string path the absolute path to which the file will be written, `nil` if standard output
2967 * @treturn bool whether the write operation should be proceeded
2969 bool vis_lua_file_save_pre(Vis *vis, File *file, const char *path) {
2970 lua_State *L = vis->lua;
2971 if (!L)
2972 return true;
2973 vis_lua_event_get(L, "file_save_pre");
2974 if (lua_isfunction(L, -1)) {
2975 obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
2976 lua_pushstring(L, path);
2977 if (pcall(vis, L, 2, 1) != 0)
2978 return false;
2979 return !lua_isboolean(L, -1) || lua_toboolean(L, -1);
2981 lua_pop(L, 1);
2982 return true;
2985 /***
2986 * File post save.
2987 * Triggered *after* a successfull write operation.
2988 * @function file_save_post
2989 * @tparam File file the file which was written
2990 * @tparam string path the absolute path to which it was written, `nil` if standard output
2992 void vis_lua_file_save_post(Vis *vis, File *file, const char *path) {
2993 lua_State *L = vis->lua;
2994 if (!L)
2995 return;
2996 vis_lua_event_get(L, "file_save_post");
2997 if (lua_isfunction(L, -1)) {
2998 obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
2999 lua_pushstring(L, path);
3000 pcall(vis, L, 2, 0);
3002 lua_pop(L, 1);
3005 /***
3006 * File close.
3007 * The last window displaying the file has been closed.
3008 * @function file_close
3009 * @tparam File file the file being closed
3011 void vis_lua_file_close(Vis *vis, File *file) {
3012 debug("event: file-close: %s %p %p\n", file->name ? file->name : "unnamed", (void*)file, (void*)file->text);
3013 lua_State *L = vis->lua;
3014 if (!L)
3015 return;
3016 vis_lua_event_get(L, "file_close");
3017 if (lua_isfunction(L, -1)) {
3018 obj_ref_new(L, file, VIS_LUA_TYPE_FILE);
3019 pcall(vis, L, 1, 0);
3021 obj_ref_free(L, file->marks);
3022 obj_ref_free(L, file->text);
3023 obj_ref_free(L, file);
3024 lua_pop(L, 1);
3027 /***
3028 * Window open.
3029 * A new window has been created.
3030 * @function win_open
3031 * @tparam Window win the window being opened
3033 void vis_lua_win_open(Vis *vis, Win *win) {
3034 debug("event: win-open: %s %p %p\n", win->file->name ? win->file->name : "unnamed", (void*)win, (void*)win->view);
3035 lua_State *L = vis->lua;
3036 if (!L)
3037 return;
3038 vis_lua_event_get(L, "win_open");
3039 if (lua_isfunction(L, -1)) {
3040 obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
3041 pcall(vis, L, 1, 0);
3043 lua_pop(L, 1);
3046 /***
3047 * Window close.
3048 * An window is being closed.
3049 * @function win_close
3050 * @tparam Window win the window being closed
3052 void vis_lua_win_close(Vis *vis, Win *win) {
3053 debug("event: win-close: %s %p %p\n", win->file->name ? win->file->name : "unnamed", (void*)win, (void*)win->view);
3054 lua_State *L = vis->lua;
3055 if (!L)
3056 return;
3057 vis_lua_event_get(L, "win_close");
3058 if (lua_isfunction(L, -1)) {
3059 obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
3060 pcall(vis, L, 1, 0);
3062 obj_ref_free(L, win->view);
3063 obj_ref_free(L, win);
3064 lua_pop(L, 1);
3068 * Window highlight.
3069 * The window has been redrawn and the syntax highlighting needs to be performed.
3070 * @function win_highlight
3071 * @tparam Window win the window being redrawn
3072 * @see style
3074 void vis_lua_win_highlight(Vis *vis, Win *win) {
3075 lua_State *L = vis->lua;
3076 if (!L)
3077 return;
3078 vis_lua_event_get(L, "win_highlight");
3079 if (lua_isfunction(L, -1)) {
3080 obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
3081 pcall(vis, L, 1, 0);
3083 lua_pop(L, 1);
3086 /***
3087 * Window status bar redraw.
3088 * @function win_status
3089 * @tparam Window win the affected window
3090 * @see status
3092 void vis_lua_win_status(Vis *vis, Win *win) {
3093 lua_State *L = vis->lua;
3094 if (!L || win->file->internal) {
3095 window_status_update(vis, win);
3096 return;
3098 vis_lua_event_get(L, "win_status");
3099 if (lua_isfunction(L, -1)) {
3100 obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW);
3101 pcall(vis, L, 1, 0);
3102 } else {
3103 window_status_update(vis, win);
3105 lua_pop(L, 1);
3108 #endif