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.
10 * @author Marc André Tanner
21 #include <sys/types.h>
26 #include "text-motions.h"
30 #define VIS_PATH "/usr/local/share/vis"
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"
50 #define debug(...) do { printf(__VA_ARGS__); fflush(stdout); } while (0)
52 #define debug(...) do { } while (0)
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
;
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
);
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
);
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
);
100 double tmp
= ((double)pos
/(double)size
)*100;
101 percent
= (size_t)(tmp
+1);
103 snprintf(right_parts
[right_count
++], sizeof(right_parts
[0]),
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",
120 left_parts
[1][0] ? " » " : "",
122 left_parts
[2][0] ? " » " : "",
124 left_parts
[3][0] ? " » " : "",
127 int right_len
= snprintf(right
, sizeof(right
), "%s%s%s%s%s%s%s ",
129 right_parts
[1][0] ? " « " : "",
131 right_parts
[2][0] ? " « " : "",
133 right_parts
[3][0] ? " « " : "",
136 if (left_len
< 0 || right_len
< 0)
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
;
145 snprintf(status
, sizeof(status
), "%s%*s%s", left
, spaces
, " ", right
);
146 vis_window_status(win
, status
);
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
); }
164 void vis_lua_term_csi(Vis
*vis
, const long *csi
) { }
169 static void stack_dump_entry(lua_State
*L
, int i
) {
170 int t
= lua_type(L
, i
);
176 printf(lua_toboolean(L
, i
) ? "true" : "false");
178 case LUA_TLIGHTUSERDATA
:
179 printf("lightuserdata(%p)", lua_touserdata(L
, i
));
182 printf("%g", lua_tonumber(L
, i
));
185 printf("`%s'", lua_tostring(L
, i
));
189 lua_pushnil(L
); /* first key */
190 while (lua_next(L
, i
> 0 ? i
: i
- 1)) {
191 stack_dump_entry(L
, -2);
193 stack_dump_entry(L
, -1);
195 lua_pop(L
, 1); /* remove value, keep key */
200 printf("userdata(%p)", lua_touserdata(L
, i
));
202 default: /* other values */
203 printf("%s", lua_typename(L
, t
));
208 static void stack_dump(lua_State
*L
, const char *format
, ...) {
210 va_start(ap
, format
);
213 int top
= lua_gettop(L
);
214 for (int i
= 1; i
<= top
; i
++) {
216 stack_dump_entry(L
, i
);
225 static int panic_handler(lua_State
*L
) {
227 lua_getallocf(L
, &ud
);
231 const char *msg
= NULL
;
232 if (lua_type(L
, -1) == LUA_TSTRING
)
233 msg
= lua_tostring(L
, -1);
234 vis_info_show(vis
, "Fatal Lua error: %s", msg
? msg
: "unknown reason");
237 siglongjmp(vis
->sigbus_jmpbuf
, 1);
242 static int error_handler(lua_State
*L
) {
243 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
244 if (vis
->errorhandler
)
246 vis
->errorhandler
= true;
248 const char *msg
= lua_tostring(L
, 1);
250 luaL_traceback(L
, L
, msg
, 1);
251 msg
= lua_tolstring(L
, 1, &len
);
252 vis_message_show(vis
, msg
);
253 vis
->errorhandler
= false;
257 static int pcall(Vis
*vis
, lua_State
*L
, int nargs
, int nresults
) {
258 /* insert a custom error function below all arguments */
259 int msgh
= lua_gettop(L
) - nargs
;
260 lua_pushlightuserdata(L
, vis
);
261 lua_pushcclosure(L
, error_handler
, 1);
263 int ret
= lua_pcall(L
, nargs
, nresults
, msgh
);
268 /* expects a lua function at stack position `narg` and stores a
269 * reference to it in the registry. The return value can be used
272 * registry["vis.functions"][(void*)(function)] = function
274 static const void *func_ref_new(lua_State
*L
, int narg
) {
275 const void *addr
= lua_topointer(L
, narg
);
276 if (!lua_isfunction(L
, narg
) || !addr
)
277 luaL_argerror(L
, narg
, "function expected");
278 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.functions");
279 lua_pushlightuserdata(L
, (void*)addr
);
280 lua_pushvalue(L
, narg
);
286 /* retrieve function from registry and place it at the top of the stack */
287 static bool func_ref_get(lua_State
*L
, const void *addr
) {
290 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.functions");
291 lua_pushlightuserdata(L
, (void*)addr
);
294 if (!lua_isfunction(L
, -1)) {
301 /* creates a new metatable for a given type and stores a mapping:
303 * registry["vis.types"][metatable] = type
305 * leaves the metatable at the top of the stack.
307 static void obj_type_new(lua_State
*L
, const char *type
) {
308 luaL_newmetatable(L
, type
);
309 lua_getglobal(L
, "vis");
310 if (!lua_isnil(L
, -1)) {
311 lua_getfield(L
, -1, "types");
312 lua_pushvalue(L
, -3);
313 lua_setfield(L
, -2, type
);
317 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.types");
318 lua_pushvalue(L
, -2);
319 lua_pushstring(L
, type
);
324 /* get type of userdatum at the top of the stack:
326 * return registry["vis.types"][getmetatable(userdata)]
328 const char *obj_type_get(lua_State
*L
) {
329 if (lua_isnil(L
, -1))
331 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.types");
332 lua_getmetatable(L
, -2);
334 // XXX: in theory string might become invalid when poped from stack
335 const char *type
= lua_tostring(L
, -1);
340 static void *obj_new(lua_State
*L
, size_t size
, const char *type
) {
341 void *obj
= lua_newuserdata(L
, size
);
342 luaL_getmetatable(L
, type
);
343 lua_setmetatable(L
, -2);
345 lua_setuservalue(L
, -2);
349 /* returns registry["vis.objects"][addr] if it is of correct type */
350 static void *obj_ref_get(lua_State
*L
, void *addr
, const char *type
) {
351 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
352 lua_pushlightuserdata(L
, addr
);
355 if (lua_isnil(L
, -1)) {
356 debug("get: vis.objects[%p] = nil\n", addr
);
361 const char *actual_type
= obj_type_get(L
);
362 if (strcmp(type
, actual_type
) != 0)
363 debug("get: vis.objects[%p] = %s (BUG: expected %s)\n", addr
, actual_type
, type
);
364 void **handle
= luaL_checkudata(L
, -1, type
);
366 debug("get: vis.objects[%p] = %s (BUG: invalid handle)\n", addr
, type
);
367 else if (*handle
!= addr
)
368 debug("get: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr
, type
, *handle
);
370 return luaL_checkudata(L
, -1, type
);
373 /* expects a userdatum at the top of the stack and sets
375 * registry["vis.objects"][addr] = userdata
377 static void obj_ref_set(lua_State
*L
, void *addr
) {
378 //debug("set: vis.objects[%p] = %s\n", addr, obj_type_get(L));
379 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
380 lua_pushlightuserdata(L
, addr
);
381 lua_pushvalue(L
, -3);
386 /* invalidates an object reference
388 * registry["vis.objects"][addr] = nil
390 static void obj_ref_free(lua_State
*L
, void *addr
) {
392 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
393 lua_pushlightuserdata(L
, addr
);
396 if (lua_isnil(L
, -1))
397 debug("free-unused: %p\n", addr
);
399 debug("free: vis.objects[%p] = %s\n", addr
, obj_type_get(L
));
403 obj_ref_set(L
, addr
);
406 /* creates a new object reference of given type if it does not already exist in the registry:
408 * if (registry["vis.types"][metatable(registry["vis.objects"][addr])] != type) {
409 * // XXX: should not happen
410 * registry["vis.objects"][addr] = new_obj(addr, type)
412 * return registry["vis.objects"][addr];
414 static void *obj_ref_new(lua_State
*L
, void *addr
, const char *type
) {
419 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
420 lua_pushlightuserdata(L
, addr
);
423 const char *old_type
= obj_type_get(L
);
424 if (strcmp(type
, old_type
) == 0) {
425 debug("new: vis.objects[%p] = %s (returning existing object)\n", addr
, old_type
);
426 void **handle
= luaL_checkudata(L
, -1, type
);
428 debug("new: vis.objects[%p] = %s (BUG: invalid handle)\n", addr
, old_type
);
429 else if (*handle
!= addr
)
430 debug("new: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr
, old_type
, *handle
);
433 if (!lua_isnil(L
, -1))
434 debug("new: vis.objects[%p] = %s (WARNING: changing object type from %s)\n", addr
, type
, old_type
);
436 debug("new: vis.objects[%p] = %s (creating new object)\n", addr
, type
);
438 void **handle
= obj_new(L
, sizeof(addr
), type
);
439 obj_ref_set(L
, addr
);
444 /* retrieve object stored in reference at stack location `idx' */
445 static void *obj_ref_check_get(lua_State
*L
, int idx
, const char *type
) {
446 void **addr
= luaL_checkudata(L
, idx
, type
);
447 if (!obj_ref_get(L
, *addr
, type
))
452 /* (type) check validity of object reference at stack location `idx' */
453 static void *obj_ref_check(lua_State
*L
, int idx
, const char *type
) {
454 void *obj
= obj_ref_check_get(L
, idx
, type
);
458 luaL_argerror(L
, idx
, "invalid object reference");
462 static void *obj_ref_check_containerof(lua_State
*L
, int idx
, const char *type
, size_t offset
) {
463 void *obj
= obj_ref_check(L
, idx
, type
);
464 return obj
? ((char*)obj
-offset
) : obj
;
467 static void *obj_lightref_new(lua_State
*L
, void *addr
, const char *type
) {
470 void **handle
= obj_new(L
, sizeof(addr
), type
);
475 static void *obj_lightref_check(lua_State
*L
, int idx
, const char *type
) {
476 void **addr
= luaL_checkudata(L
, idx
, type
);
480 static int index_common(lua_State
*L
) {
481 lua_getmetatable(L
, 1);
484 if (lua_isnil(L
, -1)) {
485 lua_getuservalue(L
, 1);
492 static int newindex_common(lua_State
*L
) {
493 lua_getuservalue(L
, 1);
500 static size_t getpos(lua_State
*L
, int narg
) {
501 return lua_tounsigned(L
, narg
);
504 static size_t checkpos(lua_State
*L
, int narg
) {
505 lua_Number n
= luaL_checknumber(L
, narg
);
506 if (n
>= 0 && n
<= SIZE_MAX
&& n
== (size_t)n
)
508 return luaL_argerror(L
, narg
, "expected position, got number");
511 static void pushpos(lua_State
*L
, size_t pos
) {
515 lua_pushunsigned(L
, pos
);
518 static void pushrange(lua_State
*L
, Filerange
*r
) {
519 if (!r
|| !text_range_valid(r
)) {
523 lua_createtable(L
, 0, 2);
524 lua_pushstring(L
, "start");
525 lua_pushunsigned(L
, r
->start
);
527 lua_pushstring(L
, "finish");
528 lua_pushunsigned(L
, r
->end
);
532 static Filerange
getrange(lua_State
*L
, int index
) {
533 Filerange range
= text_range_empty();
534 if (lua_istable(L
, index
)) {
535 lua_getfield(L
, index
, "start");
536 range
.start
= checkpos(L
, -1);
538 lua_getfield(L
, index
, "finish");
539 range
.end
= checkpos(L
, -1);
542 range
.start
= checkpos(L
, index
);
543 range
.end
= range
.start
+ checkpos(L
, index
+1);
548 static const char *keymapping(Vis
*vis
, const char *keys
, const Arg
*arg
) {
549 lua_State
*L
= vis
->lua
;
550 if (!func_ref_get(L
, arg
->v
))
552 lua_pushstring(L
, keys
);
553 if (pcall(vis
, L
, 1, 1) != 0)
555 if (lua_type(L
, -1) != LUA_TNUMBER
)
556 return keys
; /* invalid or no return value, assume zero */
557 lua_Number number
= lua_tonumber(L
, -1);
558 lua_Integer integer
= lua_tointeger(L
, -1);
559 if (number
!= integer
)
562 return NULL
; /* need more input */
563 size_t len
= integer
;
564 size_t max
= strlen(keys
);
565 return (len
<= max
) ? keys
+len
: keys
;
569 * The main editor object.
574 * Version information.
575 * @tfield string VERSION
576 * version information in `git describe` format, same as reported by `vis -v`.
579 * Lua API object types
580 * @field types meta tables of userdata objects used for type checking
585 * @tfield Ui ui the user interface being used
589 * @tfield modes modes
593 * @tfield events events
597 * @field registers array to access the register by single letter name
600 * Scintillua lexer module.
601 * @field lexers might be `nil` if module is not found
605 * @field lpeg might be `nil` if module is not found
609 * @tfield int count the specified count for the current command or `nil` if none was given
613 * Create an iterator over all windows.
615 * @return the new iterator
618 * for win in vis:windows() do
619 * -- do something with win
622 static int windows_iter(lua_State
*L
);
623 static int windows(lua_State
*L
) {
624 Vis
*vis
= obj_ref_check(L
, 1, "vis");
625 Win
**handle
= lua_newuserdata(L
, sizeof *handle
), *next
;
626 for (next
= vis
->windows
; next
&& next
->file
->internal
; next
= next
->next
);
628 lua_pushcclosure(L
, windows_iter
, 1);
632 static int windows_iter(lua_State
*L
) {
633 Win
**handle
= lua_touserdata(L
, lua_upvalueindex(1));
636 Win
*win
= obj_ref_new(L
, *handle
, VIS_LUA_TYPE_WINDOW
), *next
;
638 for (next
= win
->next
; next
&& next
->file
->internal
; next
= next
->next
);
645 * Create an iterator over all files.
647 * @return the new iterator
649 * for file in vis:files() do
650 * -- do something with file
653 static int files_iter(lua_State
*L
);
654 static int files(lua_State
*L
) {
655 Vis
*vis
= obj_ref_check(L
, 1, "vis");
656 File
**handle
= lua_newuserdata(L
, sizeof *handle
);
657 *handle
= vis
->files
;
658 lua_pushcclosure(L
, files_iter
, 1);
662 static int files_iter(lua_State
*L
) {
663 File
**handle
= lua_touserdata(L
, lua_upvalueindex(1));
666 File
*file
= obj_ref_new(L
, *handle
, VIS_LUA_TYPE_FILE
);
668 *handle
= file
->next
;
673 * Create an iterator over all mark names.
674 * @function mark_names
675 * @return the new iterator
677 * local marks = vis.win.marks
678 * for name in vis:mark_names() do
679 * local mark = marks[name]
680 * for i = 1, #mark do
681 * -- do somthing with: name, mark[i].start, mark[i].finish
685 static int mark_names_iter(lua_State
*L
);
686 static int mark_names(lua_State
*L
) {
687 Vis
*vis
= obj_ref_check(L
, 1, "vis");
688 lua_pushlightuserdata(L
, vis
);
689 enum VisMark
*handle
= lua_newuserdata(L
, sizeof *handle
);
691 lua_pushcclosure(L
, mark_names_iter
, 2);
695 static int mark_names_iter(lua_State
*L
) {
696 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
697 enum VisMark
*handle
= lua_touserdata(L
, lua_upvalueindex(2));
698 char mark
= vis_mark_to(vis
, *handle
);
700 lua_pushlstring(L
, &mark
, 1);
708 * Create an iterator over all register names.
709 * @function register_names
710 * @return the new iterator
712 * for name in vis:register_names() do
713 * local reg = vis.registers[name]
715 * -- do something with register value reg[i]
719 static int register_names_iter(lua_State
*L
);
720 static int register_names(lua_State
*L
) {
721 Vis
*vis
= obj_ref_check(L
, 1, "vis");
722 lua_pushlightuserdata(L
, vis
);
723 enum VisRegister
*handle
= lua_newuserdata(L
, sizeof *handle
);
725 lua_pushcclosure(L
, register_names_iter
, 2);
729 static int register_names_iter(lua_State
*L
) {
730 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
731 enum VisRegister
*handle
= lua_touserdata(L
, lua_upvalueindex(2));
732 char reg
= vis_register_to(vis
, *handle
);
734 lua_pushlstring(L
, ®
, 1);
742 * Execute a `:`-command.
744 * @tparam string command the command to execute
745 * @treturn bool whether the command succeeded
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
);
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.
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
);
774 * Display a multi line message.
776 * Opens a new window and displays an arbitrarily long 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
);
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
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
});
806 if (!vis_action_register(vis
, action
))
808 obj_ref_new(L
, action
, VIS_LUA_TYPE_KEYACTION
);
811 vis_action_free(vis
, action
);
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
);
823 if (lua_isstring(L
, 4)) {
824 const char *alias
= luaL_checkstring(L
, 4);
825 if (!(binding
->alias
= strdup(alias
)))
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
})))
831 } else if (lua_isuserdata(L
, 4)) {
832 binding
->action
= obj_ref_check(L
, 4, VIS_LUA_TYPE_KEYACTION
);
836 if (!vis_window_mode_map(win
, mode
, true, key
, binding
))
839 if (!vis_mode_map(vis
, mode
, true, key
, binding
))
843 lua_pushboolean(L
, true);
846 vis_binding_free(vis
, binding
);
847 lua_pushboolean(L
, false);
852 * Map a key to a Lua function.
854 * Creates a new key mapping in a given mode.
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
864 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
866 * return -1 -- need more input
868 * local digraph = keys:sub(1, 2)
869 * if digraph == "l*" then
871 * return 2 -- consume 2 bytes of input
873 * end, "Insert digraph")
878 * This is equivalent to `vis:command('map! mode key alias')`.
880 * Mappings are always recursive!
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
888 * vis:map(vis.modes.NORMAL, "j", "k")
891 * Map a key to a key action.
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
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
);
912 * Unmap a global key binding.
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
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);
925 ret
= vis_mode_unmap(vis
, mode
, key
);
927 ret
= vis_window_mode_unmap(win
, mode
, key
);
928 lua_pushboolean(L
, ret
);
932 static int unmap(lua_State
*L
) {
933 Vis
*vis
= obj_ref_check(L
, 1, "vis");
934 return keyunmap(L
, vis
, NULL
);
938 * Get all currently active mappings of a mode.
941 * @tparam int mode the mode to query
942 * @treturn table the active mappings and their associated help texts
944 * local bindings = vis:mappings(vis.modes.NORMAL)
945 * for key, help in pairs(bindings) do
950 static bool binding_collect(const char *key
, void *value
, void *ctx
) {
952 KeyBinding
*binding
= value
;
953 lua_getfield(L
, -1, key
);
954 bool new = lua_isnil(L
, -1);
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
);
964 static int mappings(lua_State
*L
) {
965 Vis
*vis
= obj_ref_check(L
, 1, "vis");
967 for (Mode
*mode
= mode_get(vis
, luaL_checkint(L
, 2)); mode
; mode
= mode
->parent
) {
970 map_iterate(mode
->bindings
, binding_collect
, vis
->lua
);
979 * @tparam int id the id of the motion to execute
980 * @treturn bool whether the id was valid
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
));
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
))
996 lua_pushunsigned(L
, pos
);
997 if (pcall(vis
, L
, 2, 1) != 0)
999 return getpos(L
, -1);
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
1011 * -- custom motion advancing to the next byte
1012 * local id = vis:motion_register(function(win, pos)
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
);
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
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
));
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
))
1044 File
*file
= vis
->files
;
1045 while (file
&& (file
->internal
|| file
->text
!= text
))
1047 if (!file
|| !obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
))
1049 pushrange(L
, &c
->range
);
1051 if (pcall(vis
, L
, 3, 1) != 0)
1053 return getpos(L
, -1);
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
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
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
);
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
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
));
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));
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
1117 * -- custom text object covering the next byte
1118 * local id = vis:textobject_register(function(win, pos)
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
);
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
))
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
);
1143 lua_pushboolean(L
, toggle
);
1144 return pcall(vis
, L
, 2, 2) == 0 && (!lua_isboolean(L
, -1) || lua_toboolean(L
, -1));
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
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))
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
;
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
);
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
);
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
))
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
))
1212 sel
= view_selections_primary_get(win
->view
);
1213 if (!obj_lightref_new(L
, sel
, VIS_LUA_TYPE_SELECTION
))
1215 pushrange(L
, range
);
1216 if (pcall(vis
, L
, 5, 1) != 0)
1218 return lua_toboolean(L
, -1);
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
1230 * vis:command_register("foo", function(argv, force, win, selection, range)
1231 * for i,arg in ipairs(argv) do
1232 * print(i..": "..arg)
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")
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
);
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
);
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.
1274 * @tparam string keys the keys to insert
1277 static int insert(lua_State
*L
) {
1278 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1280 const char *keys
= luaL_checklstring(L
, 2, &len
);
1281 vis_insert_key(vis
, keys
, len
);
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.
1293 * @tparam string keys the keys to insert
1296 static int replace(lua_State
*L
) {
1297 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1299 const char *keys
= luaL_checklstring(L
, 2, &len
);
1300 vis_replace_key(vis
, keys
, len
);
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!
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
);
1325 * Pipe file range to external process and collect output.
1327 * The editor core will be blocked while the external process is running.
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
);
1346 lua_pushstring(L
, out
);
1351 lua_pushstring(L
, err
);
1359 * Redraw complete user interface.
1361 * Will trigger redraw events, make sure to avoid recursive events.
1365 static int redraw(lua_State
*L
) {
1366 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1371 * Currently active window.
1372 * @tfield Window win
1376 * Currently active mode.
1377 * @tfield modes mode
1380 * Whether a macro is being recorded.
1381 * @tfield bool recording
1384 * Currently unconsumed keys in the input queue.
1385 * @tfield string input_queue
1388 * Register name in use.
1389 * @tfield string register
1393 * @tfield string mark
1395 static int vis_index(lua_State
*L
) {
1396 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1398 if (lua_isstring(L
, 2)) {
1399 const char *key
= lua_tostring(L
, 2);
1400 if (strcmp(key
, "win") == 0) {
1402 obj_ref_new(L
, vis
->win
, VIS_LUA_TYPE_WINDOW
);
1408 if (strcmp(key
, "mode") == 0) {
1409 lua_pushunsigned(L
, vis
->mode
->id
);
1413 if (strcmp(key
, "input_queue") == 0) {
1414 lua_pushstring(L
, buffer_content0(&vis
->input_queue
));
1418 if (strcmp(key
, "recording") == 0) {
1419 lua_pushboolean(L
, vis_macro_recording(vis
));
1423 if (strcmp(key
, "count") == 0) {
1424 int count
= vis_count_get(vis
);
1425 if (count
== VIS_COUNT_UNKNOWN
)
1428 lua_pushunsigned(L
, count
);
1432 if (strcmp(key
, "register") == 0) {
1433 char name
= vis_register_to(vis
, vis_register_used(vis
));
1434 lua_pushlstring(L
, &name
, 1);
1438 if (strcmp(key
, "registers") == 0) {
1439 obj_ref_new(L
, vis
->ui
, VIS_LUA_TYPE_REGISTERS
);
1443 if (strcmp(key
, "mark") == 0) {
1444 char name
= vis_mark_to(vis
, vis_mark_used(vis
));
1445 lua_pushlstring(L
, &name
, 1);
1449 if (strcmp(key
, "ui") == 0) {
1450 obj_ref_new(L
, vis
->ui
, VIS_LUA_TYPE_UI
);
1455 return index_common(L
);
1458 static int vis_newindex(lua_State
*L
) {
1459 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1460 if (lua_isstring(L
, 2)) {
1461 const char *key
= lua_tostring(L
, 2);
1462 if (strcmp(key
, "mode") == 0) {
1463 enum VisMode mode
= luaL_checkunsigned(L
, 3);
1464 vis_mode_switch(vis
, mode
);
1468 if (strcmp(key
, "count") == 0) {
1470 if (lua_isnil(L
, 3))
1471 count
= VIS_COUNT_UNKNOWN
;
1473 count
= luaL_checkunsigned(L
, 3);
1474 vis_count_set(vis
, count
);
1478 if (strcmp(key
, "win") == 0) {
1479 vis_window_focus(obj_ref_check(L
, 3, VIS_LUA_TYPE_WINDOW
));
1483 if (strcmp(key
, "register") == 0) {
1484 const char *name
= luaL_checkstring(L
, 3);
1485 if (strlen(name
) == 1)
1486 vis_register(vis
, vis_register_from(vis
, name
[0]));
1490 if (strcmp(key
, "mark") == 0) {
1491 const char *name
= luaL_checkstring(L
, 3);
1492 if (strlen(name
) == 1)
1493 vis_mark(vis
, vis_mark_from(vis
, name
[0]));
1497 return newindex_common(L
);
1500 static const struct luaL_Reg vis_lua
[] = {
1502 { "windows", windows
},
1503 { "mark_names", mark_names
},
1504 { "register_names", register_names
},
1505 { "command", command
},
1507 { "message", message
},
1510 { "mappings", mappings
},
1511 { "operator", operator },
1512 { "operator_register", operator_register
},
1513 { "motion", motion
},
1514 { "motion_register", motion_register
},
1515 { "textobject", textobject
},
1516 { "textobject_register", textobject_register
},
1517 { "option_register", option_register
},
1518 { "option_unregister", option_unregister
},
1519 { "command_register", command_register
},
1520 { "feedkeys", feedkeys
},
1521 { "insert", insert
},
1522 { "replace", replace
},
1523 { "action_register", action_register
},
1524 { "exit", exit_func
},
1525 { "pipe", pipe_func
},
1526 { "redraw", redraw
},
1527 { "__index", vis_index
},
1528 { "__newindex", vis_newindex
},
1532 static const struct luaL_Reg ui_funcs
[] = {
1533 { "__index", index_common
},
1537 static int registers_index(lua_State
*L
) {
1539 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
1540 const char *symbol
= luaL_checkstring(L
, 2);
1541 if (strlen(symbol
) != 1)
1543 enum VisRegister reg
= vis_register_from(vis
, symbol
[0]);
1544 if (reg
>= VIS_REG_INVALID
)
1546 Array data
= vis_register_get(vis
, reg
);
1547 for (size_t i
= 0, len
= array_length(&data
); i
< len
; i
++) {
1548 TextString
*string
= array_get(&data
, i
);
1549 lua_pushunsigned(L
, i
+1);
1550 lua_pushlstring(L
, string
->data
, string
->len
);
1551 lua_settable(L
, -3);
1553 array_release(&data
);
1557 static int registers_newindex(lua_State
*L
) {
1558 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
1559 const char *symbol
= luaL_checkstring(L
, 2);
1560 if (strlen(symbol
) != 1)
1562 enum VisRegister reg
= vis_register_from(vis
, symbol
[0]);
1564 array_init_sized(&data
, sizeof(TextString
));
1566 if (lua_istable(L
, 3)) {
1568 while (lua_next(L
, 3)) {
1570 string
.data
= luaL_checklstring(L
, -1, &string
.len
);
1571 array_add(&data
, &string
);
1576 vis_register_set(vis
, reg
, &data
);
1577 array_release(&data
);
1581 static int registers_len(lua_State
*L
) {
1582 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
1583 lua_pushunsigned(L
, LENGTH(vis
->registers
));
1587 static const struct luaL_Reg registers_funcs
[] = {
1588 { "__index", registers_index
},
1589 { "__newindex", registers_newindex
},
1590 { "__len", registers_len
},
1600 * Viewport currently being displayed.
1601 * @tfield Range viewport
1608 * The window height.
1609 * @tfield int height
1612 * The file being displayed in this window.
1616 * The primary selection of this window.
1617 * @tfield Selection selection
1620 * The selections of this window.
1621 * @tfield Array(Selection) selections
1625 * Most of these marks are stored in the associated File object, meaning they
1626 * are the same in all windows displaying the same file.
1627 * @field marks array to access the marks of this window by single letter name
1628 * @see Vis:marks_names
1630 static int window_index(lua_State
*L
) {
1631 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1633 if (lua_isstring(L
, 2)) {
1634 const char *key
= lua_tostring(L
, 2);
1636 if (strcmp(key
, "viewport") == 0) {
1637 Filerange r
= view_viewport_get(win
->view
);
1642 if (strcmp(key
, "width") == 0) {
1643 lua_pushunsigned(L
, vis_window_width_get(win
));
1647 if (strcmp(key
, "height") == 0) {
1648 lua_pushunsigned(L
, vis_window_height_get(win
));
1652 if (strcmp(key
, "file") == 0) {
1653 obj_ref_new(L
, win
->file
, VIS_LUA_TYPE_FILE
);
1657 if (strcmp(key
, "selection") == 0) {
1658 Selection
*sel
= view_selections_primary_get(win
->view
);
1659 obj_lightref_new(L
, sel
, VIS_LUA_TYPE_SELECTION
);
1663 if (strcmp(key
, "selections") == 0) {
1664 obj_ref_new(L
, win
->view
, VIS_LUA_TYPE_SELECTIONS
);
1668 if (strcmp(key
, "marks") == 0) {
1669 obj_ref_new(L
, &win
->saved_selections
, VIS_LUA_TYPE_MARKS
);
1674 return index_common(L
);
1677 static int window_selections_iterator_next(lua_State
*L
) {
1678 Selection
**handle
= lua_touserdata(L
, lua_upvalueindex(1));
1681 Selection
*sel
= obj_lightref_new(L
, *handle
, VIS_LUA_TYPE_SELECTION
);
1684 *handle
= view_selections_next(sel
);
1689 * Create an iterator over all selections of this window.
1690 * @function selections_iterator
1691 * @return the new iterator
1693 static int window_selections_iterator(lua_State
*L
) {
1694 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1695 Selection
**handle
= lua_newuserdata(L
, sizeof *handle
);
1696 *handle
= view_selections(win
->view
);
1697 lua_pushcclosure(L
, window_selections_iterator_next
, 1);
1702 * Set up a window local key mapping.
1703 * The function signatures are the same as for @{Vis:map}.
1708 static int window_map(lua_State
*L
) {
1709 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1710 return keymap(L
, win
->vis
, win
);
1714 * Remove a window local key mapping.
1715 * The function signature is the same as for @{Vis:unmap}.
1720 static int window_unmap(lua_State
*L
) {
1721 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1722 return keyunmap(L
, win
->vis
, win
);
1726 * Define a display style.
1727 * @function style_define
1728 * @tparam int id the style id to use
1729 * @tparam string style the style definition
1730 * @treturn bool whether the style definition has been successfully
1731 * associated with the given id
1734 * win:style_define(win.STYLE_DEFAULT, "fore:red")
1736 static int window_style_define(lua_State
*L
) {
1737 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1738 enum UiStyle id
= luaL_checkunsigned(L
, 2);
1739 const char *style
= luaL_checkstring(L
, 3);
1740 bool ret
= view_style_define(win
->view
, id
, style
);
1741 lua_pushboolean(L
, ret
);
1746 * Style a window range.
1748 * The style will be cleared after every window redraw.
1750 * @tparam int id the display style as registered with @{style_define}
1751 * @tparam int start the absolute file position in bytes
1752 * @tparam int finish the end position
1755 * win:style(win.STYLE_DEFAULT, 0, 10)
1757 static int window_style(lua_State
*L
) {
1758 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1759 enum UiStyle style
= luaL_checkunsigned(L
, 2);
1760 size_t start
= checkpos(L
, 3);
1761 size_t end
= checkpos(L
, 4);
1762 view_style(win
->view
, style
, start
, end
);
1767 * Set window status line.
1770 * @tparam string left the left aligned part of the status line
1771 * @tparam[opt] string right the right aligned part of the status line
1773 static int window_status(lua_State
*L
) {
1774 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1775 char status
[1024] = "";
1776 int width
= vis_window_width_get(win
);
1777 const char *left
= luaL_checkstring(L
, 2);
1778 const char *right
= luaL_optstring(L
, 3, "");
1779 int left_width
= text_string_width(left
, strlen(left
));
1780 int right_width
= text_string_width(right
, strlen(right
));
1781 int spaces
= width
- left_width
- right_width
;
1784 snprintf(status
, sizeof(status
)-1, "%s%*s%s", left
, spaces
, " ", right
);
1785 vis_window_status(win
, status
);
1790 * Redraw window content.
1794 static int window_draw(lua_State
*L
) {
1795 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1796 view_draw(win
->view
);
1803 * After a successful call the Window reference becomes invalid and
1804 * must no longer be used. Attempting to close the last window will
1809 * @tparam bool force whether unsaved changes should be discarded
1810 * @treturn bool whether the window was closed
1812 static int window_close(lua_State
*L
) {
1813 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1815 for (Win
*w
= win
->vis
->windows
; w
; w
= w
->next
) {
1816 if (!w
->file
->internal
)
1819 bool force
= lua_isboolean(L
, 2) && lua_toboolean(L
, 2);
1820 bool close
= count
> 1 && (force
|| vis_window_closable(win
));
1822 vis_window_close(win
);
1823 lua_pushboolean(L
, close
);
1827 static const struct luaL_Reg window_funcs
[] = {
1828 { "__index", window_index
},
1829 { "__newindex", newindex_common
},
1830 { "selections_iterator", window_selections_iterator
},
1831 { "map", window_map
},
1832 { "unmap", window_unmap
},
1833 { "style_define", window_style_define
},
1834 { "style", window_style
},
1835 { "status", window_status
},
1836 { "draw", window_draw
},
1837 { "close", window_close
},
1841 static int window_selections_index(lua_State
*L
) {
1842 View
*view
= obj_ref_check(L
, 1, VIS_LUA_TYPE_SELECTIONS
);
1843 size_t index
= luaL_checkunsigned(L
, 2);
1844 size_t count
= view_selections_count(view
);
1845 if (index
== 0 || index
> count
)
1847 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
)) {
1849 obj_lightref_new(L
, s
, VIS_LUA_TYPE_SELECTION
);
1858 static int window_selections_len(lua_State
*L
) {
1859 View
*view
= obj_ref_check(L
, 1, VIS_LUA_TYPE_SELECTIONS
);
1860 lua_pushunsigned(L
, view_selections_count(view
));
1864 static const struct luaL_Reg window_selections_funcs
[] = {
1865 { "__index", window_selections_index
},
1866 { "__len", window_selections_len
},
1871 * A selection object.
1873 * A selection is a non-empty, directed range with two endpoints called
1874 * *cursor* and *anchor*. A selection can be anchored in which case
1875 * the anchor remains fixed while only the position of the cursor is
1876 * adjusted. For non-anchored selections both endpoints are updated. A
1877 * singleton selection covers one character on which both cursor and
1878 * anchor reside. There always exists a primary selection which remains
1879 * visible (i.e. changes to its position will adjust the viewport).
1881 * The range covered by a selection is represented as an interval whose
1882 * endpoints are absolute byte offsets from the start of the file.
1883 * Valid addresses are within the closed interval `[0, file.size]`.
1885 * Selections are currently implemented using character marks into
1886 * the underlying persistent
1887 * [text management data structure](https://github.com/martanne/vis/wiki/Text-management-using-a-piece-chain).
1889 * This has a few consequences you should be aware of:
1891 * - A selection becomes invalid when the delimiting boundaries of the underlying
1892 * text it is referencing is deleted:
1894 * -- leaves selection in an invalid state
1895 * win.file:delete(win.selection.pos, 1)
1896 * assert(win.selection.pos == nil)
1898 * Like a regular mark it will become valid again when the text is reverted
1899 * to the state before the deletion.
1901 * - Inserts after the selection position (`> selection.pos`) will not affect the
1902 * selection postion.
1904 * local pos = win.selection.pos
1905 * win.file:insert(pos+1, "-")
1906 * assert(win.selection.pos == pos)
1908 * - Non-cached inserts before the selection position (`<= selection.pos`) will
1909 * affect the mark and adjust the selection postion by the number of bytes
1910 * which were inserted.
1912 * local pos = win.selection.pos
1913 * win.file:insert(pos, "-")
1914 * assert(win.selection.pos == pos+1)
1916 * - Cached inserts before the selection position (`<= selection.pos`) will
1917 * not affect the selection position because the underlying text is replaced
1920 * For these reasons it is generally recommended to update the selection position
1921 * after a modification. The general procedure amounts to:
1923 * 1. Read out the current selection position
1924 * 2. Perform text modifications
1925 * 3. Update the selection postion
1927 * This is what @{Vis:insert} and @{Vis:replace} do internally.
1931 * local data = "new text"
1932 * local pos = win.selection.pos
1933 * win.file:insert(pos, data)
1934 * win.selection.pos = pos + #data
1938 * The zero based byte position in the file.
1940 * Might be `nil` if the selection is in an invalid state.
1941 * Setting this field will move the cursor endpoint of the
1942 * selection to the given position.
1946 * The 1-based line the cursor of this selection resides on.
1952 * The 1-based column position the cursor of this selection resides on.
1957 * The 1-based selection index.
1958 * @tfield int number
1961 * The range covered by this selection.
1962 * @tfield Range range
1965 * Whether this selection is anchored.
1966 * @tfield bool anchored
1968 static int window_selection_index(lua_State
*L
) {
1969 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_SELECTION
);
1975 if (lua_isstring(L
, 2)) {
1976 const char *key
= lua_tostring(L
, 2);
1977 if (strcmp(key
, "pos") == 0) {
1978 pushpos(L
, view_cursors_pos(sel
));
1982 if (strcmp(key
, "line") == 0) {
1983 lua_pushunsigned(L
, view_cursors_line(sel
));
1987 if (strcmp(key
, "col") == 0) {
1988 lua_pushunsigned(L
, view_cursors_col(sel
));
1992 if (strcmp(key
, "number") == 0) {
1993 lua_pushunsigned(L
, view_selections_number(sel
)+1);
1997 if (strcmp(key
, "range") == 0) {
1998 Filerange range
= view_selections_get(sel
);
1999 pushrange(L
, &range
);
2003 if (strcmp(key
, "anchored") == 0) {
2004 lua_pushboolean(L
, view_selections_anchored(sel
));
2010 return index_common(L
);
2013 static int window_selection_newindex(lua_State
*L
) {
2014 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_SELECTION
);
2017 if (lua_isstring(L
, 2)) {
2018 const char *key
= lua_tostring(L
, 2);
2019 if (strcmp(key
, "pos") == 0) {
2020 size_t pos
= checkpos(L
, 3);
2021 view_cursors_to(sel
, pos
);
2025 if (strcmp(key
, "range") == 0) {
2026 Filerange range
= getrange(L
, 3);
2027 if (text_range_valid(&range
)) {
2028 view_selections_set(sel
, &range
);
2029 view_selections_anchor(sel
, true);
2031 view_selection_clear(sel
);
2036 if (strcmp(key
, "anchored") == 0) {
2037 view_selections_anchor(sel
, lua_toboolean(L
, 3));
2041 return newindex_common(L
);
2045 * Move cursor of selection.
2047 * @tparam int line the 1-based line number
2048 * @tparam int col the 1-based column number
2050 static int window_selection_to(lua_State
*L
) {
2051 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_SELECTION
);
2053 size_t line
= checkpos(L
, 2);
2054 size_t col
= checkpos(L
, 3);
2055 view_cursors_place(sel
, line
, col
);
2060 static const struct luaL_Reg window_selection_funcs
[] = {
2061 { "__index", window_selection_index
},
2062 { "__newindex", window_selection_newindex
},
2063 { "to", window_selection_to
},
2073 * @tfield string name the file name relative to current working directory or `nil` if not yet named
2077 * @tfield string path the absolute file path or `nil` if not yet named
2080 * File content by logical lines.
2082 * Assigning to array element `0` (`#lines+1`) will insert a new line at
2083 * the beginning (end) of the file.
2084 * @tfield Array(string) lines the file content accessible as 1-based array
2087 * local lines = vis.win.file.lines
2088 * for i=1, #lines do
2089 * lines[i] = i .. ": " .. lines[i]
2093 * File size in bytes.
2094 * @tfield int size the current file size in bytes
2098 * @tfield bool modified whether the file contains unsaved changes
2100 static int file_index(lua_State
*L
) {
2101 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2103 if (lua_isstring(L
, 2)) {
2104 const char *key
= lua_tostring(L
, 2);
2105 if (strcmp(key
, "name") == 0) {
2106 lua_pushstring(L
, file_name_get(file
));
2110 if (strcmp(key
, "path") == 0) {
2111 lua_pushstring(L
, file
->name
);
2115 if (strcmp(key
, "lines") == 0) {
2116 obj_ref_new(L
, file
->text
, VIS_LUA_TYPE_TEXT
);
2120 if (strcmp(key
, "size") == 0) {
2121 lua_pushunsigned(L
, text_size(file
->text
));
2125 if (strcmp(key
, "modified") == 0) {
2126 lua_pushboolean(L
, text_modified(file
->text
));
2131 return index_common(L
);
2134 static int file_newindex(lua_State
*L
) {
2135 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2137 if (lua_isstring(L
, 2)) {
2138 const char *key
= lua_tostring(L
, 2);
2140 if (strcmp(key
, "modified") == 0) {
2141 bool modified
= lua_isboolean(L
, 3) && lua_toboolean(L
, 3);
2143 text_insert(file
->text
, 0, " ", 1);
2144 text_delete(file
->text
, 0, 1);
2146 text_save(file
->text
, NULL
);
2152 return newindex_common(L
);
2156 * Insert data at position.
2158 * @tparam int pos the 0-based file position in bytes
2159 * @tparam string data the data to insert
2160 * @treturn bool whether the file content was successfully changed
2162 static int file_insert(lua_State
*L
) {
2163 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2164 size_t pos
= checkpos(L
, 2);
2166 luaL_checkstring(L
, 3);
2167 const char *data
= lua_tolstring(L
, 3, &len
);
2168 lua_pushboolean(L
, text_insert(file
->text
, pos
, data
, len
));
2173 * Delete data at position.
2176 * @tparam int pos the 0-based file position in bytes
2177 * @tparam int len the length in bytes to delete
2178 * @treturn bool whether the file content was successfully changed
2181 * Delete file range.
2184 * @tparam Range range the range to delete
2185 * @treturn bool whether the file content was successfully changed
2187 static int file_delete(lua_State
*L
) {
2188 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2189 Filerange range
= getrange(L
, 2);
2190 lua_pushboolean(L
, text_delete_range(file
->text
, &range
));
2195 * Create an iterator over all lines of the file.
2197 * For large files this is probably faster than @{lines}.
2198 * @function lines_iterator
2199 * @return the new iterator
2202 * for line in file:lines_iterator() do
2203 * -- do something with line
2206 static int file_lines_iterator_it(lua_State
*L
);
2207 static int file_lines_iterator(lua_State
*L
) {
2208 /* need to check second parameter first, because obj_ref_check_get
2209 * modifies the stack */
2210 size_t line
= luaL_optunsigned(L
, 2, 1);
2211 File
*file
= obj_ref_check_get(L
, 1, VIS_LUA_TYPE_FILE
);
2212 size_t *pos
= lua_newuserdata(L
, sizeof *pos
);
2213 *pos
= text_pos_by_lineno(file
->text
, line
);
2214 lua_pushcclosure(L
, file_lines_iterator_it
, 2);
2218 static int file_lines_iterator_it(lua_State
*L
) {
2219 File
*file
= *(File
**)lua_touserdata(L
, lua_upvalueindex(1));
2220 size_t *start
= lua_touserdata(L
, lua_upvalueindex(2));
2221 if (*start
== text_size(file
->text
))
2223 size_t end
= text_line_end(file
->text
, *start
);
2224 size_t len
= end
- *start
;
2225 char *buf
= lua_newuserdata(L
, len
);
2228 len
= text_bytes_get(file
->text
, *start
, len
, buf
);
2229 lua_pushlstring(L
, buf
, len
);
2230 *start
= text_line_next(file
->text
, end
);
2235 * Get file content of position and length.
2238 * @tparam int pos the 0-based file position in bytes
2239 * @tparam int len the length in bytes to read
2240 * @treturn string the file content corresponding to the range
2243 * local file = vis.win.file
2244 * local text = file:content(0, file.size)
2247 * Get file content of range.
2250 * @tparam Range range the range to read
2251 * @treturn string the file content corresponding to the range
2253 static int file_content(lua_State
*L
) {
2254 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2255 Filerange range
= getrange(L
, 2);
2256 if (!text_range_valid(&range
))
2258 size_t len
= text_range_size(&range
);
2259 char *data
= lua_newuserdata(L
, len
);
2262 len
= text_bytes_get(file
->text
, range
.start
, len
, data
);
2263 lua_pushlstring(L
, data
, len
);
2272 * @function mark_set
2273 * @tparam int pos the position to set the mark to, must be in [0, file.size]
2274 * @treturn Mark mark the mark which can be looked up later
2276 static int file_mark_set(lua_State
*L
) {
2277 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2278 size_t pos
= checkpos(L
, 2);
2279 Mark mark
= text_mark_set(file
->text
, pos
);
2281 obj_lightref_new(L
, (void*)mark
, VIS_LUA_TYPE_MARK
);
2288 * Get position of mark.
2289 * @function mark_get
2290 * @tparam Mark mark the mark to look up
2291 * @treturn int pos the position of the mark, or `nil` if invalid
2293 static int file_mark_get(lua_State
*L
) {
2294 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2295 Mark mark
= (Mark
)obj_lightref_check(L
, 2, VIS_LUA_TYPE_MARK
);
2296 size_t pos
= text_mark_get(file
->text
, mark
);
2300 lua_pushunsigned(L
, pos
);
2307 * @function text_object_word
2308 * @tparam int pos the position which must be part of the word
2309 * @treturn Range range the range
2315 * @function text_object_longword
2316 * @tparam int pos the position which must be part of the word
2317 * @treturn Range range the range
2320 static int file_text_object(lua_State
*L
) {
2321 Filerange range
= text_range_empty();
2322 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2323 size_t pos
= checkpos(L
, 2);
2324 size_t idx
= lua_tointeger(L
, lua_upvalueindex(1));
2325 if (idx
< LENGTH(vis_textobjects
)) {
2326 const TextObject
*txtobj
= &vis_textobjects
[idx
];
2328 range
= txtobj
->txt(file
->text
, pos
);
2330 pushrange(L
, &range
);
2334 static const struct luaL_Reg file_funcs
[] = {
2335 { "__index", file_index
},
2336 { "__newindex", file_newindex
},
2337 { "insert", file_insert
},
2338 { "delete", file_delete
},
2339 { "lines_iterator", file_lines_iterator
},
2340 { "content", file_content
},
2341 { "mark_set", file_mark_set
},
2342 { "mark_get", file_mark_get
},
2346 static int file_lines_index(lua_State
*L
) {
2347 Text
*txt
= obj_ref_check(L
, 1, VIS_LUA_TYPE_TEXT
);
2348 size_t line
= luaL_checkunsigned(L
, 2);
2349 size_t start
= text_pos_by_lineno(txt
, line
);
2350 size_t end
= text_line_end(txt
, start
);
2351 if (start
!= EPOS
&& end
!= EPOS
) {
2352 size_t size
= end
- start
;
2353 char *data
= lua_newuserdata(L
, size
);
2356 size
= text_bytes_get(txt
, start
, size
, data
);
2357 lua_pushlstring(L
, data
, size
);
2365 static int file_lines_newindex(lua_State
*L
) {
2366 Text
*txt
= obj_ref_check(L
, 1, VIS_LUA_TYPE_TEXT
);
2367 size_t line
= luaL_checkunsigned(L
, 2);
2369 const char *data
= luaL_checklstring(L
, 3, &size
);
2371 text_insert(txt
, 0, data
, size
);
2372 text_insert(txt
, size
, "\n", 1);
2375 size_t start
= text_pos_by_lineno(txt
, line
);
2376 size_t end
= text_line_end(txt
, start
);
2377 if (start
!= EPOS
&& end
!= EPOS
) {
2378 text_delete(txt
, start
, end
- start
);
2379 text_insert(txt
, start
, data
, size
);
2380 if (text_size(txt
) == start
+ size
)
2381 text_insert(txt
, text_size(txt
), "\n", 1);
2386 static int file_lines_len(lua_State
*L
) {
2387 Text
*txt
= obj_ref_check(L
, 1, VIS_LUA_TYPE_TEXT
);
2390 size_t size
= text_size(txt
);
2392 lines
= text_lineno_by_pos(txt
, size
);
2393 if (lines
> 1 && text_byte_get(txt
, size
-1, &lastchar
) && lastchar
== '\n')
2395 lua_pushunsigned(L
, lines
);
2399 static const struct luaL_Reg file_lines_funcs
[] = {
2400 { "__index", file_lines_index
},
2401 { "__newindex", file_lines_newindex
},
2402 { "__len", file_lines_len
},
2406 static int window_marks_index(lua_State
*L
) {
2408 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
2409 Win
*win
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_MARKS
, offsetof(Win
, saved_selections
));
2412 const char *symbol
= luaL_checkstring(L
, 2);
2413 if (strlen(symbol
) != 1)
2415 enum VisMark mark
= vis_mark_from(vis
, symbol
[0]);
2416 if (mark
== VIS_MARK_INVALID
)
2419 Array arr
= vis_mark_get(win
, mark
);
2420 for (size_t i
= 0, len
= array_length(&arr
); i
< len
; i
++) {
2421 Filerange
*range
= array_get(&arr
, i
);
2422 lua_pushunsigned(L
, i
+1);
2423 pushrange(L
, range
);
2424 lua_settable(L
, -3);
2426 array_release(&arr
);
2430 static int window_marks_newindex(lua_State
*L
) {
2431 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
2432 Win
*win
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_MARKS
, offsetof(Win
, saved_selections
));
2435 const char *symbol
= luaL_checkstring(L
, 2);
2436 if (strlen(symbol
) != 1)
2438 enum VisMark mark
= vis_mark_from(vis
, symbol
[0]);
2439 if (mark
== VIS_MARK_INVALID
)
2443 array_init_sized(&ranges
, sizeof(Filerange
));
2445 if (lua_istable(L
, 3)) {
2447 while (lua_next(L
, 3)) {
2448 Filerange range
= getrange(L
, -1);
2449 if (text_range_valid(&range
))
2450 array_add(&ranges
, &range
);
2455 vis_mark_set(win
, mark
, &ranges
);
2456 array_release(&ranges
);
2460 static int window_marks_len(lua_State
*L
) {
2461 lua_pushunsigned(L
, VIS_MARK_INVALID
);
2465 static const struct luaL_Reg window_marks_funcs
[] = {
2466 { "__index", window_marks_index
},
2467 { "__newindex", window_marks_newindex
},
2468 { "__len", window_marks_len
},
2473 * The user interface.
2478 * Number of available colors.
2479 * @tfield int colors
2485 * For a valid range `start <= finish` holds.
2486 * An invalid range is represented as `nil`.
2490 * The beginning of the range.
2494 * The end of the range.
2495 * @tfield int finish
2506 * @tfield int NORMAL
2507 * @tfield int OPERATOR_PENDING
2508 * @tfield int INSERT
2509 * @tfield int REPLACE
2510 * @tfield int VISUAL
2511 * @tfield int VISUAL_LINE
2519 * This section describes the contract between the editor core and Lua
2520 * key handling functions mapped to symbolic keys using either @{Vis:map}
2523 * @section Key_Handling
2527 * Example of a key handling function.
2529 * The keyhandler is invoked with the pending content of the input queue
2530 * given as argument. This might be the empty string if no further input
2533 * The function is expected to return the number of *bytes* it has
2534 * consumed from the passed input keys. A negative return value is
2535 * interpreted as an indication that not enough input was available. The
2536 * function will be called again once the user has provided more input. A
2537 * missing return value (i.e. `nil`) is interpreted as zero, meaning
2538 * no further input was consumed but the function completed successfully.
2540 * @function keyhandler
2541 * @tparam string keys the keys following the mapping
2542 * @treturn int the number of *bytes* being consumed by the function (see above)
2543 * @see Vis:action_register
2547 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
2549 * return -1 -- need more input
2551 * local digraph = keys:sub(1, 2)
2552 * if digraph == "l*" then
2554 * return 2 -- consume 2 bytes of input
2556 * end, "Insert digraph")
2562 * These events are invoked from the editor core.
2563 * The following functions are invoked if they are registered in the
2564 * `vis.events` table. Users scripts should generally use the [Events](#events)
2565 * mechanism instead which multiplexes these core events.
2567 * @section Core_Events
2570 static void vis_lua_event_get(lua_State
*L
, const char *name
) {
2571 lua_getglobal(L
, "vis");
2572 lua_getfield(L
, -1, "events");
2573 if (lua_istable(L
, -1)) {
2574 lua_getfield(L
, -1, name
);
2579 static void vis_lua_event_call(Vis
*vis
, const char *name
) {
2580 lua_State
*L
= vis
->lua
;
2581 vis_lua_event_get(L
, name
);
2582 if (lua_isfunction(L
, -1))
2583 pcall(vis
, L
, 0, 0);
2587 static bool vis_lua_path_strip(Vis
*vis
) {
2588 lua_State
*L
= vis
->lua
;
2589 lua_getglobal(L
, "package");
2591 for (const char **var
= (const char*[]){ "path", "cpath", NULL
}; *var
; var
++) {
2593 lua_getfield(L
, -1, *var
);
2594 const char *path
= lua_tostring(L
, -1);
2599 char *copy
= strdup(path
), *stripped
= calloc(1, strlen(path
)+2);
2600 if (!copy
|| !stripped
) {
2606 for (char *elem
= copy
, *stripped_elem
= stripped
, *next
; elem
; elem
= next
) {
2607 if ((next
= strstr(elem
, ";")))
2609 if (strstr(elem
, "./"))
2610 continue; /* skip relative path entries */
2611 stripped_elem
+= sprintf(stripped_elem
, "%s;", elem
);
2614 lua_pushstring(L
, stripped
);
2615 lua_setfield(L
, -2, *var
);
2621 lua_pop(L
, 1); /* package */
2625 bool vis_lua_path_add(Vis
*vis
, const char *path
) {
2626 lua_State
*L
= vis
->lua
;
2629 lua_getglobal(L
, "package");
2630 lua_pushstring(L
, path
);
2631 lua_pushstring(L
, "/?.lua;");
2632 lua_pushstring(L
, path
);
2633 lua_pushstring(L
, "/?/init.lua;");
2634 lua_getfield(L
, -5, "path");
2636 lua_setfield(L
, -2, "path");
2637 lua_pop(L
, 1); /* package */
2641 bool vis_lua_paths_get(Vis
*vis
, char **lpath
, char **cpath
) {
2642 lua_State
*L
= vis
->lua
;
2646 lua_getglobal(L
, "package");
2647 lua_getfield(L
, -1, "path");
2648 s
= lua_tostring(L
, -1);
2649 *lpath
= s
? strdup(s
) : NULL
;
2650 lua_getfield(L
, -2, "cpath");
2651 s
= lua_tostring(L
, -1);
2652 *cpath
= s
? strdup(s
) : NULL
;
2656 static bool package_exist(Vis
*vis
, lua_State
*L
, const char *name
) {
2658 "local name = ...\n"
2659 "for _, searcher in ipairs(package.searchers or package.loaders) do\n"
2660 "local loader = searcher(name)\n"
2661 "if type(loader) == 'function' then\n"
2666 if (luaL_loadstring(L
, lua
) != LUA_OK
)
2668 lua_pushstring(L
, name
);
2669 /* an error indicates package exists */
2670 bool ret
= lua_pcall(L
, 1, 1, 0) != LUA_OK
|| lua_toboolean(L
, -1);
2675 static void *alloc_lua(void *ud
, void *ptr
, size_t osize
, size_t nsize
) {
2680 return realloc(ptr
, nsize
);
2685 * Editor initialization completed.
2686 * This event is emitted immediately after `visrc.lua` has been sourced, but
2687 * before any other events have occured, in particular the command line arguments
2688 * have not yet been processed.
2690 * Can be used to set *global* configuration options.
2693 void vis_lua_init(Vis
*vis
) {
2694 lua_State
*L
= lua_newstate(alloc_lua
, vis
);
2698 lua_atpanic(L
, &panic_handler
);
2703 extern int luaopen_lpeg(lua_State
*L
);
2704 lua_getglobal(L
, "package");
2705 lua_getfield(L
, -1, "preload");
2706 lua_pushcfunction(L
, luaopen_lpeg
);
2707 lua_setfield(L
, -2, "lpeg");
2711 /* remove any relative paths from lua's default package.path */
2712 vis_lua_path_strip(vis
);
2714 /* extends lua's package.path with:
2716 * - ./lua (relative path to the binary location)
2717 * - $XDG_CONFIG_HOME/vis (defaulting to $HOME/.config/vis)
2718 * - /etc/vis (for system-wide configuration provided by administrator)
2719 * - /usr/(local/)?share/vis (or whatever is specified during ./configure)
2720 * - package.path (standard lua search path)
2722 char path
[PATH_MAX
];
2724 vis_lua_path_add(vis
, VIS_PATH
);
2726 /* try to get users home directory */
2727 const char *home
= getenv("HOME");
2728 if (!home
|| !*home
) {
2729 struct passwd
*pw
= getpwuid(getuid());
2734 vis_lua_path_add(vis
, "/etc/vis");
2736 const char *xdg_config
= getenv("XDG_CONFIG_HOME");
2738 snprintf(path
, sizeof path
, "%s/vis", xdg_config
);
2739 vis_lua_path_add(vis
, path
);
2740 } else if (home
&& *home
) {
2741 snprintf(path
, sizeof path
, "%s/.config/vis", home
);
2742 vis_lua_path_add(vis
, path
);
2745 ssize_t len
= readlink("/proc/self/exe", path
, sizeof(path
)-1);
2748 /* some idotic dirname(3) implementations return pointers to statically
2749 * allocated memory, hence we use memmove to copy it back */
2750 char *dir
= dirname(path
);
2752 size_t len
= strlen(dir
)+1;
2753 if (len
< sizeof(path
) - sizeof("/lua")) {
2754 memmove(path
, dir
, len
);
2755 strcat(path
, "/lua");
2756 vis_lua_path_add(vis
, path
);
2761 vis_lua_path_add(vis
, getenv("VIS_PATH"));
2763 /* table in registry to lookup object type, stores metatable -> type mapping */
2765 lua_setfield(L
, LUA_REGISTRYINDEX
, "vis.types");
2766 /* table in registry to track lifetimes of C objects */
2768 lua_setfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
2769 /* table in registry to store references to Lua functions */
2771 lua_setfield(L
, LUA_REGISTRYINDEX
, "vis.functions");
2772 /* metatable used to type check user data */
2773 obj_type_new(L
, VIS_LUA_TYPE_VIS
);
2774 luaL_setfuncs(L
, vis_lua
, 0);
2776 lua_setfield(L
, -2, "types");
2777 /* create reference to main vis object, such that the further
2778 * calls to obj_type_new can register the type meta tables in
2779 * vis.types[name] */
2780 obj_ref_new(L
, vis
, "vis");
2781 lua_setglobal(L
, "vis");
2783 obj_type_new(L
, VIS_LUA_TYPE_FILE
);
2786 enum VisTextObject id
;
2789 { VIS_TEXTOBJECT_INNER_WORD
, "text_object_word" },
2790 { VIS_TEXTOBJECT_INNER_LONGWORD
, "text_object_longword" },
2793 for (size_t i
= 0; i
< LENGTH(textobjects
); i
++) {
2794 lua_pushunsigned(L
, textobjects
[i
].id
);
2795 lua_pushcclosure(L
, file_text_object
, 1);
2796 lua_setfield(L
, -2, textobjects
[i
].name
);
2799 luaL_setfuncs(L
, file_funcs
, 0);
2801 obj_type_new(L
, VIS_LUA_TYPE_TEXT
);
2802 luaL_setfuncs(L
, file_lines_funcs
, 0);
2803 obj_type_new(L
, VIS_LUA_TYPE_WINDOW
);
2804 luaL_setfuncs(L
, window_funcs
, 0);
2810 { UI_STYLE_DEFAULT
, "STYLE_DEFAULT" },
2811 { UI_STYLE_CURSOR
, "STYLE_CURSOR" },
2812 { UI_STYLE_CURSOR_PRIMARY
, "STYLE_CURSOR_PRIMARY" },
2813 { UI_STYLE_CURSOR_LINE
, "STYLE_CURSOR_LINE" },
2814 { UI_STYLE_SELECTION
, "STYLE_SELECTION" },
2815 { UI_STYLE_LINENUMBER
, "STYLE_LINENUMBER" },
2816 { UI_STYLE_LINENUMBER_CURSOR
, "STYLE_LINENUMBER_CURSOR" },
2817 { UI_STYLE_COLOR_COLUMN
, "STYLE_COLOR_COLUMN" },
2818 { UI_STYLE_STATUS
, "STYLE_STATUS" },
2819 { UI_STYLE_STATUS_FOCUSED
, "STYLE_STATUS_FOCUSED" },
2820 { UI_STYLE_SEPARATOR
, "STYLE_SEPARATOR" },
2821 { UI_STYLE_INFO
, "STYLE_INFO" },
2822 { UI_STYLE_EOF
, "STYLE_EOF" },
2825 for (size_t i
= 0; i
< LENGTH(styles
); i
++) {
2826 lua_pushunsigned(L
, styles
[i
].id
);
2827 lua_setfield(L
, -2, styles
[i
].name
);
2830 obj_type_new(L
, VIS_LUA_TYPE_MARK
);
2831 obj_type_new(L
, VIS_LUA_TYPE_MARKS
);
2832 lua_pushlightuserdata(L
, vis
);
2833 luaL_setfuncs(L
, window_marks_funcs
, 1);
2835 obj_type_new(L
, VIS_LUA_TYPE_SELECTION
);
2836 luaL_setfuncs(L
, window_selection_funcs
, 0);
2837 obj_type_new(L
, VIS_LUA_TYPE_SELECTIONS
);
2838 luaL_setfuncs(L
, window_selections_funcs
, 0);
2840 obj_type_new(L
, VIS_LUA_TYPE_UI
);
2841 luaL_setfuncs(L
, ui_funcs
, 0);
2842 lua_pushunsigned(L
, vis
->ui
->colors(vis
->ui
));
2843 lua_setfield(L
, -2, "colors");
2845 obj_type_new(L
, VIS_LUA_TYPE_REGISTERS
);
2846 lua_pushlightuserdata(L
, vis
);
2847 luaL_setfuncs(L
, registers_funcs
, 1);
2849 obj_type_new(L
, VIS_LUA_TYPE_KEYACTION
);
2851 lua_getglobal(L
, "vis");
2852 lua_getmetatable(L
, -1);
2854 lua_pushstring(L
, VERSION
);
2855 lua_setfield(L
, -2, "VERSION");
2859 static const struct {
2863 { VIS_MODE_NORMAL
, "NORMAL" },
2864 { VIS_MODE_OPERATOR_PENDING
, "OPERATOR_PENDING" },
2865 { VIS_MODE_VISUAL
, "VISUAL" },
2866 { VIS_MODE_VISUAL_LINE
, "VISUAL_LINE" },
2867 { VIS_MODE_INSERT
, "INSERT" },
2868 { VIS_MODE_REPLACE
, "REPLACE" },
2871 for (size_t i
= 0; i
< LENGTH(modes
); i
++) {
2872 lua_pushunsigned(L
, modes
[i
].id
);
2873 lua_setfield(L
, -2, modes
[i
].name
);
2876 lua_setfield(L
, -2, "modes");
2878 if (!package_exist(vis
, L
, "visrc")) {
2879 vis_info_show(vis
, "WARNING: failed to load visrc.lua");
2881 lua_getglobal(L
, "require");
2882 lua_pushstring(L
, "visrc");
2883 pcall(vis
, L
, 1, 0);
2884 vis_lua_event_call(vis
, "init");
2889 * Editor startup completed.
2890 * This event is emitted immediately before the main loop starts.
2891 * At this point all files are loaded and corresponding windows are created.
2892 * We are about to process interactive keyboard input.
2895 void vis_lua_start(Vis
*vis
) {
2896 vis_lua_event_call(vis
, "start");
2900 * Editor is about to terminate.
2903 void vis_lua_quit(Vis
*vis
) {
2906 vis_lua_event_call(vis
, "quit");
2907 lua_close(vis
->lua
);
2912 * Input key event in either input or replace mode.
2914 * @tparam string key
2915 * @treturn bool whether the key was cosumed or not
2917 static bool vis_lua_input(Vis
*vis
, const char *key
, size_t len
) {
2918 lua_State
*L
= vis
->lua
;
2919 if (!L
|| !vis
->win
|| vis
->win
->file
->internal
)
2922 vis_lua_event_get(L
, "input");
2923 if (lua_isfunction(L
, -1)) {
2924 lua_pushlstring(L
, key
, len
);
2925 if (pcall(vis
, L
, 1, 1) == 0) {
2926 ret
= lua_isboolean(L
, -1) && lua_toboolean(L
, -1);
2934 void vis_lua_mode_insert_input(Vis
*vis
, const char *key
, size_t len
) {
2935 if (!vis_lua_input(vis
, key
, len
))
2936 vis_insert_key(vis
, key
, len
);
2939 void vis_lua_mode_replace_input(Vis
*vis
, const char *key
, size_t len
) {
2940 if (!vis_lua_input(vis
, key
, len
))
2941 vis_replace_key(vis
, key
, len
);
2946 * @function file_open
2947 * @tparam File file the file to be opened
2949 void vis_lua_file_open(Vis
*vis
, File
*file
) {
2950 debug("event: file-open: %s %p %p\n", file
->name
? file
->name
: "unnamed", (void*)file
, (void*)file
->text
);
2951 lua_State
*L
= vis
->lua
;
2954 vis_lua_event_get(L
, "file_open");
2955 if (lua_isfunction(L
, -1)) {
2956 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
2957 pcall(vis
, L
, 1, 0);
2964 * Triggered *before* the file is being written.
2965 * @function file_save_pre
2966 * @tparam File file the file being written
2967 * @tparam string path the absolute path to which the file will be written, `nil` if standard output
2968 * @treturn bool whether the write operation should be proceeded
2970 bool vis_lua_file_save_pre(Vis
*vis
, File
*file
, const char *path
) {
2971 lua_State
*L
= vis
->lua
;
2974 vis_lua_event_get(L
, "file_save_pre");
2975 if (lua_isfunction(L
, -1)) {
2976 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
2977 lua_pushstring(L
, path
);
2978 if (pcall(vis
, L
, 2, 1) != 0)
2980 return !lua_isboolean(L
, -1) || lua_toboolean(L
, -1);
2988 * Triggered *after* a successfull write operation.
2989 * @function file_save_post
2990 * @tparam File file the file which was written
2991 * @tparam string path the absolute path to which it was written, `nil` if standard output
2993 void vis_lua_file_save_post(Vis
*vis
, File
*file
, const char *path
) {
2994 lua_State
*L
= vis
->lua
;
2997 vis_lua_event_get(L
, "file_save_post");
2998 if (lua_isfunction(L
, -1)) {
2999 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
3000 lua_pushstring(L
, path
);
3001 pcall(vis
, L
, 2, 0);
3008 * The last window displaying the file has been closed.
3009 * @function file_close
3010 * @tparam File file the file being closed
3012 void vis_lua_file_close(Vis
*vis
, File
*file
) {
3013 debug("event: file-close: %s %p %p\n", file
->name
? file
->name
: "unnamed", (void*)file
, (void*)file
->text
);
3014 lua_State
*L
= vis
->lua
;
3017 vis_lua_event_get(L
, "file_close");
3018 if (lua_isfunction(L
, -1)) {
3019 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
3020 pcall(vis
, L
, 1, 0);
3022 obj_ref_free(L
, file
->marks
);
3023 obj_ref_free(L
, file
->text
);
3024 obj_ref_free(L
, file
);
3030 * A new window has been created.
3031 * @function win_open
3032 * @tparam Window win the window being opened
3034 void vis_lua_win_open(Vis
*vis
, Win
*win
) {
3035 debug("event: win-open: %s %p %p\n", win
->file
->name
? win
->file
->name
: "unnamed", (void*)win
, (void*)win
->view
);
3036 lua_State
*L
= vis
->lua
;
3039 vis_lua_event_get(L
, "win_open");
3040 if (lua_isfunction(L
, -1)) {
3041 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
3042 pcall(vis
, L
, 1, 0);
3049 * An window is being closed.
3050 * @function win_close
3051 * @tparam Window win the window being closed
3053 void vis_lua_win_close(Vis
*vis
, Win
*win
) {
3054 debug("event: win-close: %s %p %p\n", win
->file
->name
? win
->file
->name
: "unnamed", (void*)win
, (void*)win
->view
);
3055 lua_State
*L
= vis
->lua
;
3058 vis_lua_event_get(L
, "win_close");
3059 if (lua_isfunction(L
, -1)) {
3060 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
3061 pcall(vis
, L
, 1, 0);
3063 obj_ref_free(L
, win
->view
);
3064 obj_ref_free(L
, win
);
3070 * The window has been redrawn and the syntax highlighting needs to be performed.
3071 * @function win_highlight
3072 * @tparam Window win the window being redrawn
3075 void vis_lua_win_highlight(Vis
*vis
, Win
*win
) {
3076 lua_State
*L
= vis
->lua
;
3079 vis_lua_event_get(L
, "win_highlight");
3080 if (lua_isfunction(L
, -1)) {
3081 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
3082 pcall(vis
, L
, 1, 0);
3088 * Window status bar redraw.
3089 * @function win_status
3090 * @tparam Window win the affected window
3093 void vis_lua_win_status(Vis
*vis
, Win
*win
) {
3094 lua_State
*L
= vis
->lua
;
3095 if (!L
|| win
->file
->internal
) {
3096 window_status_update(vis
, win
);
3099 vis_lua_event_get(L
, "win_status");
3100 if (lua_isfunction(L
, -1)) {
3101 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
3102 pcall(vis
, L
, 1, 0);
3104 window_status_update(vis
, win
);
3110 * CSI command received from terminal.
3111 * @function term_csi
3112 * @param List of CSI parameters
3114 void vis_lua_term_csi(Vis
*vis
, const long *csi
) {
3115 lua_State
*L
= vis
->lua
;
3118 vis_lua_event_get(L
, "term_csi");
3119 if (lua_isfunction(L
, -1)) {
3121 lua_pushinteger(L
, csi
[0]);
3122 for (int i
= 0; i
< nargs
; i
++)
3123 lua_pushinteger(L
, csi
[2 + i
]);
3124 pcall(vis
, L
, 1 + nargs
, 0);