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_CURSOR "cursor"
40 #define VIS_LUA_TYPE_CURSORS "cursors"
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
[left_count
])-1, "%s%s%s",
77 filename
? filename
: "[No Name]",
78 text_modified(txt
) ? " [+]" : "",
79 vis_macro_recording(vis
) ? " @": "");
82 int cursor_count
= view_selections_count(view
);
83 if (cursor_count
> 1) {
84 Selection
*s
= view_selections_primary_get(view
);
85 int cursor_number
= view_selections_number(s
) + 1;
86 snprintf(right_parts
[right_count
], sizeof(right_parts
[right_count
])-1,
87 "%d/%d", cursor_number
, cursor_count
);
91 size_t size
= text_size(txt
);
92 size_t pos
= view_cursor_get(view
);
95 double tmp
= ((double)pos
/(double)size
)*100;
96 percent
= (size_t)(tmp
+1);
98 snprintf(right_parts
[right_count
], sizeof(right_parts
[right_count
])-1,
102 if (!(options
& UI_OPTION_LARGE_FILE
)) {
103 Selection
*sel
= view_selections_primary_get(win
->view
);
104 size_t line
= view_cursors_line(sel
);
105 size_t col
= view_cursors_col(sel
);
106 if (col
> UI_LARGE_FILE_LINE_SIZE
) {
107 options
|= UI_OPTION_LARGE_FILE
;
108 view_options_set(win
->view
, options
);
110 snprintf(right_parts
[right_count
], sizeof(right_parts
[right_count
])-1,
111 "%zu, %zu", line
, col
);
115 int left_len
= snprintf(left
, sizeof(left
)-1, " %s%s%s%s%s%s%s",
117 left_parts
[1][0] ? " » " : "",
119 left_parts
[2][0] ? " » " : "",
121 left_parts
[3][0] ? " » " : "",
124 int right_len
= snprintf(right
, sizeof(right
)-1, "%s%s%s%s%s%s%s ",
126 right_parts
[1][0] ? " « " : "",
128 right_parts
[2][0] ? " « " : "",
130 right_parts
[3][0] ? " « " : "",
133 if (left_len
< 0 || right_len
< 0)
135 int left_width
= text_string_width(left
, left_len
);
136 int right_width
= text_string_width(right
, right_len
);
138 int spaces
= width
- left_width
- right_width
;
142 snprintf(status
, sizeof(status
)-1, "%s%*s%s", left
, spaces
, " ", right
);
143 vis_window_status(win
, status
);
148 bool vis_lua_path_add(Vis
*vis
, const char *path
) { return true; }
149 bool vis_lua_paths_get(Vis
*vis
, char **lpath
, char **cpath
) { return false; }
150 void vis_lua_init(Vis
*vis
) { }
151 void vis_lua_start(Vis
*vis
) { }
152 void vis_lua_quit(Vis
*vis
) { }
153 void vis_lua_file_open(Vis
*vis
, File
*file
) { }
154 bool vis_lua_file_save_pre(Vis
*vis
, File
*file
, const char *path
) { return true; }
155 void vis_lua_file_save_post(Vis
*vis
, File
*file
, const char *path
) { }
156 void vis_lua_file_close(Vis
*vis
, File
*file
) { }
157 void vis_lua_win_open(Vis
*vis
, Win
*win
) { }
158 void vis_lua_win_close(Vis
*vis
, Win
*win
) { }
159 void vis_lua_win_highlight(Vis
*vis
, Win
*win
) { }
160 void vis_lua_win_status(Vis
*vis
, Win
*win
) { window_status_update(vis
, win
); }
165 static void stack_dump_entry(lua_State
*L
, int i
) {
166 int t
= lua_type(L
, i
);
172 printf(lua_toboolean(L
, i
) ? "true" : "false");
174 case LUA_TLIGHTUSERDATA
:
175 printf("lightuserdata(%p)", lua_touserdata(L
, i
));
178 printf("%g", lua_tonumber(L
, i
));
181 printf("`%s'", lua_tostring(L
, i
));
185 lua_pushnil(L
); /* first key */
186 while (lua_next(L
, i
> 0 ? i
: i
- 1)) {
187 stack_dump_entry(L
, -2);
189 stack_dump_entry(L
, -1);
191 lua_pop(L
, 1); /* remove value, keep key */
196 printf("userdata(%p)", lua_touserdata(L
, i
));
198 default: /* other values */
199 printf("%s", lua_typename(L
, t
));
204 static void stack_dump(lua_State
*L
, const char *format
, ...) {
206 va_start(ap
, format
);
209 int top
= lua_gettop(L
);
210 for (int i
= 1; i
<= top
; i
++) {
212 stack_dump_entry(L
, i
);
221 static int panic_handler(lua_State
*L
) {
223 lua_getallocf(L
, &ud
);
227 const char *msg
= NULL
;
228 if (lua_type(L
, -1) == LUA_TSTRING
)
229 msg
= lua_tostring(L
, -1);
230 vis_info_show(vis
, "Fatal Lua error: %s", msg
? msg
: "unknown reason");
233 siglongjmp(vis
->sigbus_jmpbuf
, 1);
238 static int error_handler(lua_State
*L
) {
239 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
240 if (vis
->errorhandler
)
242 vis
->errorhandler
= true;
244 const char *msg
= lua_tostring(L
, 1);
246 luaL_traceback(L
, L
, msg
, 1);
247 msg
= lua_tolstring(L
, 1, &len
);
248 vis_message_show(vis
, msg
);
249 vis
->errorhandler
= false;
253 static int pcall(Vis
*vis
, lua_State
*L
, int nargs
, int nresults
) {
254 /* insert a custom error function below all arguments */
255 int msgh
= lua_gettop(L
) - nargs
;
256 lua_pushlightuserdata(L
, vis
);
257 lua_pushcclosure(L
, error_handler
, 1);
259 int ret
= lua_pcall(L
, nargs
, nresults
, msgh
);
264 /* expects a lua function at stack position `narg` and stores a
265 * reference to it in the registry. The return value can be used
268 * registry["vis.functions"][(void*)(function)] = function
270 static const void *func_ref_new(lua_State
*L
, int narg
) {
271 const void *addr
= lua_topointer(L
, narg
);
272 if (!lua_isfunction(L
, narg
) || !addr
)
273 luaL_argerror(L
, narg
, "function expected");
274 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.functions");
275 lua_pushlightuserdata(L
, (void*)addr
);
276 lua_pushvalue(L
, narg
);
282 /* retrieve function from registry and place it at the top of the stack */
283 static bool func_ref_get(lua_State
*L
, const void *addr
) {
286 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.functions");
287 lua_pushlightuserdata(L
, (void*)addr
);
290 if (!lua_isfunction(L
, -1)) {
297 /* creates a new metatable for a given type and stores a mapping:
299 * registry["vis.types"][metatable] = type
301 * leaves the metatable at the top of the stack.
303 static void obj_type_new(lua_State
*L
, const char *type
) {
304 luaL_newmetatable(L
, type
);
305 lua_getglobal(L
, "vis");
306 if (!lua_isnil(L
, -1)) {
307 lua_getfield(L
, -1, "types");
308 lua_pushvalue(L
, -3);
309 lua_setfield(L
, -2, type
);
313 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.types");
314 lua_pushvalue(L
, -2);
315 lua_pushstring(L
, type
);
320 /* get type of userdatum at the top of the stack:
322 * return registry["vis.types"][getmetatable(userdata)]
324 const char *obj_type_get(lua_State
*L
) {
325 if (lua_isnil(L
, -1))
327 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.types");
328 lua_getmetatable(L
, -2);
330 // XXX: in theory string might become invalid when poped from stack
331 const char *type
= lua_tostring(L
, -1);
336 static void *obj_new(lua_State
*L
, size_t size
, const char *type
) {
337 void *obj
= lua_newuserdata(L
, size
);
338 luaL_getmetatable(L
, type
);
339 lua_setmetatable(L
, -2);
341 lua_setuservalue(L
, -2);
345 /* returns registry["vis.objects"][addr] if it is of correct type */
346 static void *obj_ref_get(lua_State
*L
, void *addr
, const char *type
) {
347 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
348 lua_pushlightuserdata(L
, addr
);
351 if (lua_isnil(L
, -1)) {
352 debug("get: vis.objects[%p] = nil\n", addr
);
357 const char *actual_type
= obj_type_get(L
);
358 if (strcmp(type
, actual_type
) != 0)
359 debug("get: vis.objects[%p] = %s (BUG: expected %s)\n", addr
, actual_type
, type
);
360 void **handle
= luaL_checkudata(L
, -1, type
);
362 debug("get: vis.objects[%p] = %s (BUG: invalid handle)\n", addr
, type
);
363 else if (*handle
!= addr
)
364 debug("get: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr
, type
, *handle
);
366 return luaL_checkudata(L
, -1, type
);
369 /* expects a userdatum at the top of the stack and sets
371 * registry["vis.objects"][addr] = userdata
373 static void obj_ref_set(lua_State
*L
, void *addr
) {
374 //debug("set: vis.objects[%p] = %s\n", addr, obj_type_get(L));
375 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
376 lua_pushlightuserdata(L
, addr
);
377 lua_pushvalue(L
, -3);
382 /* invalidates an object reference
384 * registry["vis.objects"][addr] = nil
386 static void obj_ref_free(lua_State
*L
, void *addr
) {
388 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
389 lua_pushlightuserdata(L
, addr
);
392 if (lua_isnil(L
, -1))
393 debug("free-unused: %p\n", addr
);
395 debug("free: vis.objects[%p] = %s\n", addr
, obj_type_get(L
));
399 obj_ref_set(L
, addr
);
402 /* creates a new object reference of given type if it does not already exist in the registry:
404 * if (registry["vis.types"][metatable(registry["vis.objects"][addr])] != type) {
405 * // XXX: should not happen
406 * registry["vis.objects"][addr] = new_obj(addr, type)
408 * return registry["vis.objects"][addr];
410 static void *obj_ref_new(lua_State
*L
, void *addr
, const char *type
) {
415 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
416 lua_pushlightuserdata(L
, addr
);
419 const char *old_type
= obj_type_get(L
);
420 if (strcmp(type
, old_type
) == 0) {
421 debug("new: vis.objects[%p] = %s (returning existing object)\n", addr
, old_type
);
422 void **handle
= luaL_checkudata(L
, -1, type
);
424 debug("new: vis.objects[%p] = %s (BUG: invalid handle)\n", addr
, old_type
);
425 else if (*handle
!= addr
)
426 debug("new: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr
, old_type
, *handle
);
429 if (!lua_isnil(L
, -1))
430 debug("new: vis.objects[%p] = %s (WARNING: changing object type from %s)\n", addr
, type
, old_type
);
432 debug("new: vis.objects[%p] = %s (creating new object)\n", addr
, type
);
434 void **handle
= obj_new(L
, sizeof(addr
), type
);
435 obj_ref_set(L
, addr
);
440 /* retrieve object stored in reference at stack location `idx' */
441 static void *obj_ref_check_get(lua_State
*L
, int idx
, const char *type
) {
442 void **addr
= luaL_checkudata(L
, idx
, type
);
443 if (!obj_ref_get(L
, *addr
, type
))
448 /* (type) check validity of object reference at stack location `idx' */
449 static void *obj_ref_check(lua_State
*L
, int idx
, const char *type
) {
450 void *obj
= obj_ref_check_get(L
, idx
, type
);
454 luaL_argerror(L
, idx
, "invalid object reference");
458 static void *obj_ref_check_containerof(lua_State
*L
, int idx
, const char *type
, size_t offset
) {
459 void *obj
= obj_ref_check(L
, idx
, type
);
460 return obj
? ((char*)obj
-offset
) : obj
;
463 static void *obj_lightref_new(lua_State
*L
, void *addr
, const char *type
) {
466 void **handle
= obj_new(L
, sizeof(addr
), type
);
471 static void *obj_lightref_check(lua_State
*L
, int idx
, const char *type
) {
472 void **addr
= luaL_checkudata(L
, idx
, type
);
476 static int index_common(lua_State
*L
) {
477 lua_getmetatable(L
, 1);
480 if (lua_isnil(L
, -1)) {
481 lua_getuservalue(L
, 1);
488 static int newindex_common(lua_State
*L
) {
489 lua_getuservalue(L
, 1);
496 static size_t getpos(lua_State
*L
, int narg
) {
497 return lua_tounsigned(L
, narg
);
500 static size_t checkpos(lua_State
*L
, int narg
) {
501 lua_Number n
= luaL_checknumber(L
, narg
);
502 if (n
>= 0 && n
<= SIZE_MAX
&& n
== (size_t)n
)
504 return luaL_argerror(L
, narg
, "expected position, got number");
507 static void pushpos(lua_State
*L
, size_t pos
) {
511 lua_pushunsigned(L
, pos
);
514 static void pushrange(lua_State
*L
, Filerange
*r
) {
515 if (!r
|| !text_range_valid(r
)) {
519 lua_createtable(L
, 0, 2);
520 lua_pushstring(L
, "start");
521 lua_pushunsigned(L
, r
->start
);
523 lua_pushstring(L
, "finish");
524 lua_pushunsigned(L
, r
->end
);
528 static Filerange
getrange(lua_State
*L
, int index
) {
529 Filerange range
= text_range_empty();
530 if (lua_istable(L
, index
)) {
531 lua_getfield(L
, index
, "start");
532 range
.start
= checkpos(L
, -1);
534 lua_getfield(L
, index
, "finish");
535 range
.end
= checkpos(L
, -1);
538 range
.start
= checkpos(L
, index
);
539 range
.end
= range
.start
+ checkpos(L
, index
+1);
544 static const char *keymapping(Vis
*vis
, const char *keys
, const Arg
*arg
) {
545 lua_State
*L
= vis
->lua
;
546 if (!func_ref_get(L
, arg
->v
))
548 lua_pushstring(L
, keys
);
549 if (pcall(vis
, L
, 1, 1) != 0)
551 if (lua_type(L
, -1) != LUA_TNUMBER
)
552 return keys
; /* invalid or no return value, assume zero */
553 lua_Number number
= lua_tonumber(L
, -1);
554 lua_Integer integer
= lua_tointeger(L
, -1);
555 if (number
!= integer
)
558 return NULL
; /* need more input */
559 size_t len
= integer
;
560 size_t max
= strlen(keys
);
561 return (len
<= max
) ? keys
+len
: keys
;
565 * The main editor object.
570 * Version information.
571 * @tfield string VERSION
572 * version information in `git describe` format, same as reported by `vis -v`.
575 * Lua API object types
576 * @field types meta tables of userdata objects used for type checking
581 * @tfield Ui ui the user interface being used
585 * @tfield modes modes
589 * @tfield events events
593 * @field registers array to access the register by single letter name
596 * Scintillua lexer module.
597 * @field lexers might be `nil` if module is not found
601 * @field lpeg might be `nil` if module is not found
605 * @tfield int count the specified count for the current command or `nil` if none was given
609 * Create an iterator over all windows.
611 * @return the new iterator
614 * for win in vis:windows() do
615 * -- do something with win
618 static int windows_iter(lua_State
*L
);
619 static int windows(lua_State
*L
) {
620 Vis
*vis
= obj_ref_check(L
, 1, "vis");
621 Win
**handle
= lua_newuserdata(L
, sizeof *handle
);
622 *handle
= vis
->windows
;
623 lua_pushcclosure(L
, windows_iter
, 1);
627 static int windows_iter(lua_State
*L
) {
628 Win
**handle
= lua_touserdata(L
, lua_upvalueindex(1));
631 Win
*win
= obj_ref_new(L
, *handle
, VIS_LUA_TYPE_WINDOW
);
638 * Create an iterator over all files.
640 * @return the new iterator
642 * for file in vis:files() do
643 * -- do something with file
646 static int files_iter(lua_State
*L
);
647 static int files(lua_State
*L
) {
648 Vis
*vis
= obj_ref_check(L
, 1, "vis");
649 File
**handle
= lua_newuserdata(L
, sizeof *handle
);
650 *handle
= vis
->files
;
651 lua_pushcclosure(L
, files_iter
, 1);
655 static int files_iter(lua_State
*L
) {
656 File
**handle
= lua_touserdata(L
, lua_upvalueindex(1));
659 File
*file
= obj_ref_new(L
, *handle
, VIS_LUA_TYPE_FILE
);
661 *handle
= file
->next
;
666 * Create an iterator over all mark names.
667 * @function mark_names
668 * @return the new iterator
670 * local marks = vis.win.file.marks
671 * for name in vis:mark_names() do
672 * local mark = marks[name]
673 * for i = 1, #mark do
674 * -- do somthing with: name, mark[i].start, mark[i].finish
678 static int mark_names_iter(lua_State
*L
);
679 static int mark_names(lua_State
*L
) {
680 enum VisMark
*handle
= lua_newuserdata(L
, sizeof *handle
);
682 lua_pushcclosure(L
, mark_names_iter
, 1);
686 static int mark_names_iter(lua_State
*L
) {
688 enum VisMark
*handle
= lua_touserdata(L
, lua_upvalueindex(1));
689 if (*handle
< LENGTH(vis_marks
))
690 mark
= vis_marks
[*handle
].name
;
691 else if (VIS_MARK_a
<= *handle
&& *handle
<= VIS_MARK_z
)
692 mark
= 'a' + *handle
- VIS_MARK_a
;
694 char name
[2] = { mark
, '\0' };
695 lua_pushstring(L
, name
);
703 * Create an iterator over all register names.
704 * @function register_names
705 * @return the new iterator
707 * for name in vis:register_names() do
708 * local reg = vis.registers[name]
710 * -- do something with register value reg[i]
714 static int register_names_iter(lua_State
*L
);
715 static int register_names(lua_State
*L
) {
716 enum VisRegister
*handle
= lua_newuserdata(L
, sizeof *handle
);
718 lua_pushcclosure(L
, register_names_iter
, 1);
722 static int register_names_iter(lua_State
*L
) {
724 enum VisRegister
*handle
= lua_touserdata(L
, lua_upvalueindex(1));
725 if (*handle
< LENGTH(vis_registers
))
726 reg
= vis_registers
[*handle
].name
;
727 else if (VIS_REG_a
<= *handle
&& *handle
<= VIS_REG_z
)
728 reg
= 'a' + *handle
- VIS_REG_a
;
730 char name
[2] = { reg
, '\0' };
731 lua_pushstring(L
, name
);
739 * Execute a `:`-command.
741 * @tparam string command the command to execute
742 * @treturn bool whether the command succeeded
744 * vis:command("set number")
746 static int command(lua_State
*L
) {
747 Vis
*vis
= obj_ref_check(L
, 1, "vis");
748 const char *cmd
= luaL_checkstring(L
, 2);
749 bool ret
= vis_cmd(vis
, cmd
);
750 lua_pushboolean(L
, ret
);
755 * Display a short message.
757 * The single line message will be displayed at the bottom of
758 * the scren and automatically hidden once a key is pressed.
761 * @tparam string message the message to display
763 static int info(lua_State
*L
) {
764 Vis
*vis
= obj_ref_check(L
, 1, "vis");
765 const char *msg
= luaL_checkstring(L
, 2);
766 vis_info_show(vis
, "%s", msg
);
771 * Display a multi line message.
773 * Opens a new window and displays an arbitrarily long message.
776 * @tparam string message the message to display
778 static int message(lua_State
*L
) {
779 Vis
*vis
= obj_ref_check(L
, 1, "vis");
780 const char *msg
= luaL_checkstring(L
, 2);
781 vis_message_show(vis
, msg
);
786 * Register a Lua function as key action.
787 * @function action_register
788 * @tparam string name the name of the action, can be referred to in key bindings as `<name>` pseudo key
789 * @tparam Function func the lua function implementing the key action (see @{keyhandler})
790 * @tparam[opt] string help the single line help text as displayed in `:help`
791 * @treturn KeyAction action the registered key action
795 static int action_register(lua_State
*L
) {
796 Vis
*vis
= obj_ref_check(L
, 1, "vis");
797 const char *name
= luaL_checkstring(L
, 2);
798 const void *func
= func_ref_new(L
, 3);
799 const char *help
= luaL_optstring(L
, 4, NULL
);
800 KeyAction
*action
= vis_action_new(vis
, name
, help
, keymapping
, (Arg
){ .v
= func
});
803 if (!vis_action_register(vis
, action
))
805 obj_ref_new(L
, action
, VIS_LUA_TYPE_KEYACTION
);
808 vis_action_free(vis
, action
);
813 static int keymap(lua_State
*L
, Vis
*vis
, Win
*win
) {
814 int mode
= luaL_checkint(L
, 2);
815 const char *key
= luaL_checkstring(L
, 3);
816 const char *help
= luaL_optstring(L
, 5, NULL
);
817 KeyBinding
*binding
= vis_binding_new(vis
);
820 if (lua_isstring(L
, 4)) {
821 const char *alias
= luaL_checkstring(L
, 4);
822 if (!(binding
->alias
= strdup(alias
)))
824 } else if (lua_isfunction(L
, 4)) {
825 const void *func
= func_ref_new(L
, 4);
826 if (!(binding
->action
= vis_action_new(vis
, NULL
, help
, keymapping
, (Arg
){ .v
= func
})))
828 } else if (lua_isuserdata(L
, 4)) {
829 binding
->action
= obj_ref_check(L
, 4, VIS_LUA_TYPE_KEYACTION
);
833 if (!vis_window_mode_map(win
, mode
, true, key
, binding
))
836 if (!vis_mode_map(vis
, mode
, true, key
, binding
))
840 lua_pushboolean(L
, true);
843 vis_binding_free(vis
, binding
);
844 lua_pushboolean(L
, false);
849 * Map a key to a Lua function.
851 * Creates a new key mapping in a given mode.
854 * @tparam int mode the mode to which the mapping should be added
855 * @tparam string key the key to map
856 * @tparam function func the Lua function to handle the key mapping (see @{keyhandler})
857 * @tparam[opt] string help the single line help text as displayed in `:help`
858 * @treturn bool whether the mapping was successfully established
861 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
863 * return -1 -- need more input
865 * local digraph = keys:sub(1, 2)
866 * if digraph == "l*" then
868 * return 2 -- consume 2 bytes of input
870 * end, "Insert digraph")
875 * This is equivalent to `vis:command('map! mode key alias')`.
877 * Mappings are always recursive!
879 * @tparam int mode the mode to which the mapping should be added
880 * @tparam string key the key to map
881 * @tparam string alias the key to map to
882 * @treturn bool whether the mapping was successfully established
885 * vis:map(vis.modes.NORMAL, "j", "k")
888 * Map a key to a key action.
891 * @tparam int mode the mode to which the mapping should be added
892 * @tparam string key the key to map
893 * @param action the action to map
894 * @treturn bool whether the mapping was successfully established
897 * local action = vis:action_register("info", function()
898 * vis:info("Mapping works!")
899 * end, "Info message help text")
900 * vis:map(vis.modes.NORMAL, "gh", action)
901 * vis:map(vis.modes.NORMAL, "gl", action)
903 static int map(lua_State
*L
) {
904 Vis
*vis
= obj_ref_check(L
, 1, "vis");
905 return keymap(L
, vis
, NULL
);
909 * Unmap a global key binding.
912 * @tparam int mode the mode from which the mapping should be removed
913 * @tparam string key the mapping to remove
914 * @treturn bool whether the mapping was successfully removed
917 static int keyunmap(lua_State
*L
, Vis
*vis
, Win
*win
) {
918 enum VisMode mode
= luaL_checkint(L
, 2);
919 const char *key
= luaL_checkstring(L
, 3);
922 ret
= vis_mode_unmap(vis
, mode
, key
);
924 ret
= vis_window_mode_unmap(win
, mode
, key
);
925 lua_pushboolean(L
, ret
);
929 static int unmap(lua_State
*L
) {
930 Vis
*vis
= obj_ref_check(L
, 1, "vis");
931 return keyunmap(L
, vis
, NULL
);
935 * Get all currently active mappings of a mode.
938 * @tparam int mode the mode to query
939 * @treturn table the active mappings and their associated help texts
941 * local bindings = vis:mappings(vis.modes.NORMAL)
942 * for key, help in pairs(bindings) do
947 static bool binding_collect(const char *key
, void *value
, void *ctx
) {
949 KeyBinding
*binding
= value
;
950 lua_getfield(L
, -1, key
);
951 bool new = lua_isnil(L
, -1);
954 const char *help
= binding
->alias
? binding
->alias
: VIS_HELP_USE(binding
->action
->help
);
955 lua_pushstring(L
, help
? help
: "");
956 lua_setfield(L
, -2, key
);
961 static int mappings(lua_State
*L
) {
962 Vis
*vis
= obj_ref_check(L
, 1, "vis");
964 for (Mode
*mode
= mode_get(vis
, luaL_checkint(L
, 2)); mode
; mode
= mode
->parent
) {
967 map_iterate(mode
->bindings
, binding_collect
, vis
->lua
);
976 * @tparam int id the id of the motion to execute
977 * @treturn bool whether the id was valid
980 static int motion(lua_State
*L
) {
981 Vis
*vis
= obj_ref_check(L
, 1, "vis");
982 enum VisMotion id
= luaL_checkunsigned(L
, 2);
983 // TODO handle var args?
984 lua_pushboolean(L
, vis
&& vis_motion(vis
, id
));
988 static size_t motion_lua(Vis
*vis
, Win
*win
, void *data
, size_t pos
) {
989 lua_State
*L
= vis
->lua
;
990 if (!L
|| !func_ref_get(L
, data
) || !obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
))
993 lua_pushunsigned(L
, pos
);
994 if (pcall(vis
, L
, 2, 1) != 0)
996 return getpos(L
, -1);
1000 * Register a custom motion.
1002 * @function motion_register
1003 * @tparam function motion the Lua function implementing the motion
1004 * @treturn int the associated motion id, or `-1` on failure
1005 * @see motion, motion_new
1008 * -- custom motion advancing to the next byte
1009 * local id = vis:motion_register(function(win, pos)
1013 static int motion_register(lua_State
*L
) {
1014 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1015 const void *func
= func_ref_new(L
, 2);
1016 int id
= vis_motion_register(vis
, 0, (void*)func
, motion_lua
);
1017 lua_pushinteger(L
, id
);
1022 * Execute an operator.
1024 * @function operator
1025 * @tparam int id the id of the operator to execute
1026 * @treturn bool whether the id was valid
1029 static int operator(lua_State
*L
) {
1030 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1031 enum VisOperator id
= luaL_checkunsigned(L
, 2);
1032 // TODO handle var args?
1033 lua_pushboolean(L
, vis
&& vis_operator(vis
, id
));
1037 static size_t operator_lua(Vis
*vis
, Text
*text
, OperatorContext
*c
) {
1038 lua_State
*L
= vis
->lua
;
1039 if (!L
|| !func_ref_get(L
, c
->context
))
1041 File
*file
= vis
->files
;
1042 while (file
&& (file
->internal
|| file
->text
!= text
))
1044 if (!file
|| !obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
))
1046 pushrange(L
, &c
->range
);
1048 if (pcall(vis
, L
, 3, 1) != 0)
1050 return getpos(L
, -1);
1054 * Register a custom operator.
1056 * @function operator_register
1057 * @tparam function operator the Lua function implementing the operator
1058 * @treturn int the associated operator id, or `-1` on failure
1059 * @see operator, operator_new
1062 * -- custom operator replacing every 'a' with 'b'
1063 * local id = vis:operator_register(function(file, range, pos)
1064 * local data = file:content(range)
1065 * data = data:gsub("a", "b")
1066 * file:delete(range)
1067 * file:insert(range.start, data)
1068 * return range.start -- new cursor location
1071 static int operator_register(lua_State
*L
) {
1072 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1073 const void *func
= func_ref_new(L
, 2);
1074 int id
= vis_operator_register(vis
, operator_lua
, (void*)func
);
1075 lua_pushinteger(L
, id
);
1080 * Execute a text object.
1082 * @function textobject
1083 * @tparam int id the id of the text object to execute
1084 * @treturn bool whether the id was valid
1085 * @see textobject_register, textobject_new
1088 static int textobject(lua_State
*L
) {
1089 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1090 enum VisTextObject id
= luaL_checkunsigned(L
, 2);
1091 lua_pushboolean(L
, vis_textobject(vis
, id
));
1095 static Filerange
textobject_lua(Vis
*vis
, Win
*win
, void *data
, size_t pos
) {
1096 lua_State
*L
= vis
->lua
;
1097 if (!L
|| !func_ref_get(L
, data
) || !obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
))
1098 return text_range_empty();
1099 lua_pushunsigned(L
, pos
);
1100 if (pcall(vis
, L
, 2, 2) != 0 || lua_isnil(L
, -1))
1101 return text_range_empty();
1102 return text_range_new(getpos(L
, -2), getpos(L
, -1));
1106 * Register a custom text object.
1108 * @function textobject_register
1109 * @tparam function textobject the Lua function implementing the text object
1110 * @treturn int the associated text object id, or `-1` on failure
1111 * @see textobject, textobject_new
1114 * -- custom text object covering the next byte
1115 * local id = vis:textobject_register(function(win, pos)
1119 static int textobject_register(lua_State
*L
) {
1120 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1121 const void *func
= func_ref_new(L
, 2);
1122 int id
= vis_textobject_register(vis
, 0, (void*)func
, textobject_lua
);
1123 lua_pushinteger(L
, id
);
1127 static bool option_lua(Vis
*vis
, Win
*win
, void *context
, bool toggle
,
1128 enum VisOption flags
, const char *name
, Arg
*value
) {
1129 lua_State
*L
= vis
->lua
;
1130 if (!L
|| !func_ref_get(L
, context
))
1132 if (flags
& VIS_OPTION_TYPE_BOOL
)
1133 lua_pushboolean(L
, value
->b
);
1134 else if (flags
& VIS_OPTION_TYPE_STRING
)
1135 lua_pushstring(L
, value
->s
);
1136 else if (flags
& VIS_OPTION_TYPE_NUMBER
)
1137 lua_pushnumber(L
, value
->i
);
1140 lua_pushboolean(L
, toggle
);
1141 return pcall(vis
, L
, 2, 2) == 0 && (!lua_isboolean(L
, -1) || lua_toboolean(L
, -1));
1145 * Register a custom `:set` option.
1147 * @function option_register
1148 * @tparam string name the option name
1149 * @tparam string type the option type (`bool`, `string` or `number`)
1150 * @tparam function handler the Lua function being called when the option is changed
1151 * @tparam[opt] string help the single line help text as displayed in `:help`
1152 * @treturn bool whether the option was successfully registered
1154 * vis:option_register("foo", "bool", function(value, toogle)
1155 * if not vis.win then return false end
1156 * vis.win.foo = toogle and not vis.win.foo or value
1157 * vis:info("Option foo = " .. tostring(vis.win.foo))
1159 * end, "Foo enables superpowers")
1161 static int option_register(lua_State
*L
) {
1162 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1163 const char *name
= luaL_checkstring(L
, 2);
1164 const char *type
= luaL_checkstring(L
, 3);
1165 const void *func
= func_ref_new(L
, 4);
1166 const char *help
= luaL_optstring(L
, 5, NULL
);
1167 const char *names
[] = { name
, NULL
};
1168 enum VisOption flags
= 0;
1169 if (strcmp(type
, "string") == 0)
1170 flags
|= VIS_OPTION_TYPE_STRING
;
1171 else if (strcmp(type
, "number") == 0)
1172 flags
|= VIS_OPTION_TYPE_NUMBER
;
1174 flags
|= VIS_OPTION_TYPE_BOOL
;
1175 bool ret
= vis_option_register(vis
, names
, flags
, option_lua
, (void*)func
, help
);
1176 lua_pushboolean(L
, ret
);
1181 * Unregister a `:set` option.
1183 * @function option_unregister
1184 * @tparam string name the option name
1185 * @treturn bool whether the option was successfully unregistered
1187 static int option_unregister(lua_State
*L
) {
1188 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1189 const char *name
= luaL_checkstring(L
, 2);
1190 bool ret
= vis_option_unregister(vis
, name
);
1191 lua_pushboolean(L
, ret
);
1195 static bool command_lua(Vis
*vis
, Win
*win
, void *data
, bool force
, const char *argv
[], Selection
*sel
, Filerange
*range
) {
1196 lua_State
*L
= vis
->lua
;
1197 if (!L
|| !func_ref_get(L
, data
))
1200 for (size_t i
= 0; argv
[i
]; i
++) {
1201 lua_pushunsigned(L
, i
);
1202 lua_pushstring(L
, argv
[i
]);
1203 lua_settable(L
, -3);
1205 lua_pushboolean(L
, force
);
1206 if (!obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
))
1209 sel
= view_selections_primary_get(win
->view
);
1210 if (!obj_lightref_new(L
, sel
, VIS_LUA_TYPE_CURSOR
))
1212 pushrange(L
, range
);
1213 if (pcall(vis
, L
, 5, 1) != 0)
1215 return lua_toboolean(L
, -1);
1219 * Register a custom `:`-command.
1221 * @function command_register
1222 * @tparam string name the command name
1223 * @tparam function command the Lua function implementing the command
1224 * @tparam[opt] string help the single line help text as displayed in `:help`
1225 * @treturn bool whether the command has been successfully registered
1227 * vis:command_register("foo", function(argv, force, win, cursor, range)
1228 * for i,arg in ipairs(argv) do
1229 * print(i..": "..arg)
1231 * print("was command forced with ! "..(force and "yes" or "no"))
1232 * print(win.file.name)
1234 * print(range ~= nil and ('['..range.start..', '..range.finish..']') or "invalid range")
1238 static int command_register(lua_State
*L
) {
1239 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1240 const char *name
= luaL_checkstring(L
, 2);
1241 const void *func
= func_ref_new(L
, 3);
1242 const char *help
= luaL_optstring(L
, 4, "");
1243 bool ret
= vis_cmd_register(vis
, name
, help
, (void*)func
, command_lua
);
1244 lua_pushboolean(L
, ret
);
1249 * Push keys to input queue and interpret them.
1251 * The keys are processed as if they were read from the keyboard.
1253 * @function feedkeys
1254 * @tparam string keys the keys to interpret
1256 static int feedkeys(lua_State
*L
) {
1257 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1258 const char *keys
= luaL_checkstring(L
, 2);
1259 vis_keys_feed(vis
, keys
);
1264 * Insert keys at all cursor positions of active window.
1266 * This function behaves as if the keys were entered in insert mode,
1267 * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
1268 * meaning mappings do not apply and the keys will not be recorded in macros.
1271 * @tparam string keys the keys to insert
1274 static int insert(lua_State
*L
) {
1275 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1277 const char *keys
= luaL_checklstring(L
, 2, &len
);
1278 vis_insert_key(vis
, keys
, len
);
1283 * Replace keys at all cursor positions of active window.
1285 * This function behaves as if the keys were entered in replace mode,
1286 * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
1287 * meaning mappings do not apply and the keys will not be recorded in macros.
1290 * @tparam string keys the keys to insert
1293 static int replace(lua_State
*L
) {
1294 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1296 const char *keys
= luaL_checklstring(L
, 2, &len
);
1297 vis_replace_key(vis
, keys
, len
);
1302 * Terminate editor process.
1304 * Termination happens upon the next iteration of the main event loop.
1305 * This means the calling Lua code will be executed further until it
1306 * eventually hands over control to the editor core. The exit status
1307 * of the most recent call is used.
1309 * All unsaved chanes will be lost!
1312 * @tparam int code the exit status returned to the operating system
1314 static int exit_func(lua_State
*L
) {
1315 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1316 int code
= luaL_checkint(L
, 2);
1317 vis_exit(vis
, code
);
1322 * Pipe file range to external process and collect output.
1324 * The editor core will be blocked while the external process is running.
1327 * @tparam File file the file to which the range applies
1328 * @tparam Range range the range to pipe
1329 * @tparam string command the command to execute
1330 * @treturn int code the exit status of the executed command
1331 * @treturn string stdout the data written to stdout
1332 * @treturn string stderr the data written to stderr
1334 static int pipe_func(lua_State
*L
) {
1335 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1336 File
*file
= obj_ref_check(L
, 2, VIS_LUA_TYPE_FILE
);
1337 Filerange range
= getrange(L
, 3);
1338 const char *cmd
= luaL_checkstring(L
, 4);
1339 char *out
= NULL
, *err
= NULL
;
1340 int status
= vis_pipe_collect(vis
, file
, &range
, (const char*[]){ cmd
, NULL
}, &out
, &err
);
1341 lua_pushinteger(L
, status
);
1343 lua_pushstring(L
, out
);
1348 lua_pushstring(L
, err
);
1356 * Currently active window.
1357 * @tfield Window win
1361 * Currently active mode.
1362 * @tfield modes mode
1365 * Whether a macro is being recorded.
1366 * @tfield bool recording
1368 static int vis_index(lua_State
*L
) {
1369 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1371 if (lua_isstring(L
, 2)) {
1372 const char *key
= lua_tostring(L
, 2);
1373 if (strcmp(key
, "win") == 0) {
1375 obj_ref_new(L
, vis
->win
, VIS_LUA_TYPE_WINDOW
);
1381 if (strcmp(key
, "mode") == 0) {
1382 lua_pushunsigned(L
, vis
->mode
->id
);
1386 if (strcmp(key
, "recording") == 0) {
1387 lua_pushboolean(L
, vis_macro_recording(vis
));
1391 if (strcmp(key
, "count") == 0) {
1392 int count
= vis_count_get(vis
);
1393 if (count
== VIS_COUNT_UNKNOWN
)
1396 lua_pushunsigned(L
, count
);
1400 if (strcmp(key
, "registers") == 0) {
1401 obj_ref_new(L
, vis
->ui
, VIS_LUA_TYPE_REGISTERS
);
1405 if (strcmp(key
, "ui") == 0) {
1406 obj_ref_new(L
, vis
->ui
, VIS_LUA_TYPE_UI
);
1411 return index_common(L
);
1414 static int vis_newindex(lua_State
*L
) {
1415 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1416 if (lua_isstring(L
, 2)) {
1417 const char *key
= lua_tostring(L
, 2);
1418 if (strcmp(key
, "mode") == 0) {
1419 enum VisMode mode
= luaL_checkunsigned(L
, 3);
1420 vis_mode_switch(vis
, mode
);
1424 if (strcmp(key
, "count") == 0) {
1426 if (lua_isnil(L
, 3))
1427 count
= VIS_COUNT_UNKNOWN
;
1429 count
= luaL_checkunsigned(L
, 3);
1430 vis_count_set(vis
, count
);
1434 if (strcmp(key
, "win") == 0) {
1435 vis_window_focus(obj_ref_check(L
, 3, VIS_LUA_TYPE_WINDOW
));
1439 return newindex_common(L
);
1442 static const struct luaL_Reg vis_lua
[] = {
1444 { "windows", windows
},
1445 { "mark_names", mark_names
},
1446 { "register_names", register_names
},
1447 { "command", command
},
1449 { "message", message
},
1452 { "mappings", mappings
},
1453 { "operator", operator },
1454 { "operator_register", operator_register
},
1455 { "motion", motion
},
1456 { "motion_register", motion_register
},
1457 { "textobject", textobject
},
1458 { "textobject_register", textobject_register
},
1459 { "option_register", option_register
},
1460 { "option_unregister", option_unregister
},
1461 { "command_register", command_register
},
1462 { "feedkeys", feedkeys
},
1463 { "insert", insert
},
1464 { "replace", replace
},
1465 { "action_register", action_register
},
1466 { "exit", exit_func
},
1467 { "pipe", pipe_func
},
1468 { "__index", vis_index
},
1469 { "__newindex", vis_newindex
},
1473 static const struct luaL_Reg ui_funcs
[] = {
1474 { "__index", index_common
},
1478 static int registers_index(lua_State
*L
) {
1480 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
1481 const char *symbol
= luaL_checkstring(L
, 2);
1482 if (strlen(symbol
) != 1)
1484 enum VisRegister reg
= vis_register_from(vis
, symbol
[0]);
1485 if (reg
>= VIS_REG_INVALID
)
1487 Array data
= vis_register_get(vis
, reg
);
1488 for (size_t i
= 0, len
= array_length(&data
); i
< len
; i
++) {
1489 TextString
*string
= array_get(&data
, i
);
1490 lua_pushunsigned(L
, i
+1);
1491 lua_pushlstring(L
, string
->data
, string
->len
);
1492 lua_settable(L
, -3);
1494 array_release(&data
);
1498 static int registers_newindex(lua_State
*L
) {
1499 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
1500 const char *symbol
= luaL_checkstring(L
, 2);
1501 if (strlen(symbol
) != 1)
1503 enum VisRegister reg
= vis_register_from(vis
, symbol
[0]);
1505 array_init_sized(&data
, sizeof(TextString
));
1507 if (lua_istable(L
, 3)) {
1509 while (lua_next(L
, 3)) {
1511 string
.data
= luaL_checklstring(L
, -1, &string
.len
);
1512 array_add(&data
, &string
);
1517 vis_register_set(vis
, reg
, &data
);
1518 array_release(&data
);
1522 static int registers_len(lua_State
*L
) {
1523 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
1524 lua_pushunsigned(L
, LENGTH(vis
->registers
));
1528 static const struct luaL_Reg registers_funcs
[] = {
1529 { "__index", registers_index
},
1530 { "__newindex", registers_newindex
},
1531 { "__len", registers_len
},
1541 * Viewport currently being displayed.
1542 * @tfield Range viewport
1549 * The window height.
1550 * @tfield int height
1553 * The file being displayed in this window.
1557 * The primary cursor of this window.
1558 * @tfield Cursor cursor
1561 * The cursors of this window.
1562 * @tfield Array(Cursor) cursors
1564 static int window_index(lua_State
*L
) {
1565 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1567 if (lua_isstring(L
, 2)) {
1568 const char *key
= lua_tostring(L
, 2);
1570 if (strcmp(key
, "viewport") == 0) {
1571 Filerange r
= view_viewport_get(win
->view
);
1576 if (strcmp(key
, "width") == 0) {
1577 lua_pushunsigned(L
, vis_window_width_get(win
));
1581 if (strcmp(key
, "height") == 0) {
1582 lua_pushunsigned(L
, vis_window_height_get(win
));
1586 if (strcmp(key
, "file") == 0) {
1587 obj_ref_new(L
, win
->file
, VIS_LUA_TYPE_FILE
);
1591 if (strcmp(key
, "cursor") == 0) {
1592 Selection
*sel
= view_selections_primary_get(win
->view
);
1593 obj_lightref_new(L
, sel
, VIS_LUA_TYPE_CURSOR
);
1597 if (strcmp(key
, "cursors") == 0) {
1598 obj_ref_new(L
, win
->view
, VIS_LUA_TYPE_CURSORS
);
1603 return index_common(L
);
1606 static int window_cursors_iterator_next(lua_State
*L
) {
1607 Selection
**handle
= lua_touserdata(L
, lua_upvalueindex(1));
1610 Selection
*sel
= obj_lightref_new(L
, *handle
, VIS_LUA_TYPE_CURSOR
);
1613 *handle
= view_selections_next(sel
);
1618 * Create an iterator over all cursors of this window.
1619 * @function cursors_iterator
1620 * @return the new iterator
1622 static int window_cursors_iterator(lua_State
*L
) {
1623 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1624 Selection
**handle
= lua_newuserdata(L
, sizeof *handle
);
1625 *handle
= view_selections(win
->view
);
1626 lua_pushcclosure(L
, window_cursors_iterator_next
, 1);
1631 * Set up a window local key mapping.
1632 * The function signatures are the same as for @{Vis:map}.
1637 static int window_map(lua_State
*L
) {
1638 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1639 return keymap(L
, win
->vis
, win
);
1643 * Remove a window local key mapping.
1644 * The function signature is the same as for @{Vis:unmap}.
1649 static int window_unmap(lua_State
*L
) {
1650 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1651 return keyunmap(L
, win
->vis
, win
);
1655 * Define a display style.
1656 * @function style_define
1657 * @tparam int id the style id to use
1658 * @tparam string style the style definition
1659 * @treturn bool whether the style definition has been successfully
1660 * associated with the given id
1663 * win:style_define(win.STYLE_DEFAULT, "fore:red")
1665 static int window_style_define(lua_State
*L
) {
1666 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1667 enum UiStyle id
= luaL_checkunsigned(L
, 2);
1668 const char *style
= luaL_checkstring(L
, 3);
1669 bool ret
= view_style_define(win
->view
, id
, style
);
1670 lua_pushboolean(L
, ret
);
1675 * Style a window range.
1677 * The style will be cleared after every window redraw.
1679 * @tparam int id the display style as registered with @{style_define}
1680 * @tparam int start the absolute file position in bytes
1681 * @tparam int len the length in bytes to style
1684 * win:style(win.STYLE_DEFAULT, 0, 10)
1686 static int window_style(lua_State
*L
) {
1687 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1688 enum UiStyle style
= luaL_checkunsigned(L
, 2);
1689 size_t start
= checkpos(L
, 3);
1690 size_t end
= checkpos(L
, 4);
1691 view_style(win
->view
, style
, start
, end
);
1696 * Set window status line.
1699 * @tparam string left the left aligned part of the status line
1700 * @tparam[opt] string right the right aligned part of the status line
1702 static int window_status(lua_State
*L
) {
1703 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1704 char status
[1024] = "";
1705 int width
= vis_window_width_get(win
);
1706 const char *left
= luaL_checkstring(L
, 2);
1707 const char *right
= luaL_optstring(L
, 3, "");
1708 int left_width
= text_string_width(left
, strlen(left
));
1709 int right_width
= text_string_width(right
, strlen(right
));
1710 int spaces
= width
- left_width
- right_width
;
1713 snprintf(status
, sizeof(status
)-1, "%s%*s%s", left
, spaces
, " ", right
);
1714 vis_window_status(win
, status
);
1719 * Redraw window content.
1723 static int window_draw(lua_State
*L
) {
1724 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1725 view_draw(win
->view
);
1729 static const struct luaL_Reg window_funcs
[] = {
1730 { "__index", window_index
},
1731 { "__newindex", newindex_common
},
1732 { "cursors_iterator", window_cursors_iterator
},
1733 { "map", window_map
},
1734 { "unmap", window_unmap
},
1735 { "style_define", window_style_define
},
1736 { "style", window_style
},
1737 { "status", window_status
},
1738 { "draw", window_draw
},
1742 static int window_cursors_index(lua_State
*L
) {
1743 View
*view
= obj_ref_check(L
, 1, VIS_LUA_TYPE_CURSORS
);
1744 size_t index
= luaL_checkunsigned(L
, 2);
1745 size_t count
= view_selections_count(view
);
1746 if (index
== 0 || index
> count
)
1748 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
)) {
1750 obj_lightref_new(L
, s
, VIS_LUA_TYPE_CURSOR
);
1759 static int window_cursors_len(lua_State
*L
) {
1760 View
*view
= obj_ref_check(L
, 1, VIS_LUA_TYPE_CURSORS
);
1761 lua_pushunsigned(L
, view_selections_count(view
));
1765 static const struct luaL_Reg window_cursors_funcs
[] = {
1766 { "__index", window_cursors_index
},
1767 { "__len", window_cursors_len
},
1774 * Cursors are represented as absolute byte offsets from the start of the file.
1775 * Valid cursor placements are within the closed interval `[0, file.size]`.
1776 * Cursors are currently implemented using character marks into the underlying
1777 * persistent [text management data structure](https://github.com/martanne/vis/wiki/Text-management-using-a-piece-chain).
1778 * This has a few consequences you should be aware of:
1780 * - A cursor becomes invalid when the underlying text range it is referencing
1783 * -- leaves cursor in an invalid state
1784 * win.file:delete(win.cursor.pos, 1)
1785 * assert(win.cursor.pos == nil)
1787 * Like a regular mark it will become valid again when the text is reverted
1788 * to the state before the deletion.
1790 * - Inserts after the cursor position (`> cursor.pos`) will not affect the
1793 * local pos = win.cursor.pos
1794 * win.file:insert(pos+1, "-")
1795 * assert(win.cursor.pos == pos)
1797 * - Non-cached inserts before the cursor position (`<= cursor.pos`) will
1798 * affect the mark and adjust the cursor postion by the number of bytes
1799 * which were inserted.
1801 * local pos = win.cursor.pos
1802 * win.file:insert(pos, "-")
1803 * assert(win.cursor.pos == pos+1)
1805 * - Cached inserts before the cursor position (`<= cursor.pos`) will
1806 * not affect the cursor position because the underlying text is replaced
1809 * For these reasons it is generally recommended to update the cursor position
1810 * after a modification. The general procedure amounts to:
1812 * 1. Read out the current cursor position
1813 * 2. Perform text modifications
1814 * 3. Update the cursor postion
1816 * This is what @{Vis:insert} and @{Vis:replace} do internally.
1820 * local data = "new text"
1821 * local pos = win.cursor.pos
1822 * win.file:insert(pos, data)
1823 * win.cursor.pos = pos + #data
1827 * The zero based byte position in the file.
1829 * Might be `nil` if the cursor is in an invalid state.
1830 * Setting this field will move the cursor to the given position.
1834 * The 1-based line the cursor resides on.
1840 * The 1-based column position the cursor resides on.
1845 * The 1-based cursor index.
1846 * @tfield int number
1849 * The selection associated with this cursor.
1850 * @tfield Range selection the selection or `nil` if not in visual mode
1852 static int window_cursor_index(lua_State
*L
) {
1853 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_CURSOR
);
1859 if (lua_isstring(L
, 2)) {
1860 const char *key
= lua_tostring(L
, 2);
1861 if (strcmp(key
, "pos") == 0) {
1862 pushpos(L
, view_cursors_pos(sel
));
1866 if (strcmp(key
, "line") == 0) {
1867 lua_pushunsigned(L
, view_cursors_line(sel
));
1871 if (strcmp(key
, "col") == 0) {
1872 lua_pushunsigned(L
, view_cursors_col(sel
));
1876 if (strcmp(key
, "number") == 0) {
1877 lua_pushunsigned(L
, view_selections_number(sel
)+1);
1881 if (strcmp(key
, "selection") == 0) {
1882 Filerange range
= view_selections_get(sel
);
1883 pushrange(L
, &range
);
1888 return index_common(L
);
1891 static int window_cursor_newindex(lua_State
*L
) {
1892 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_CURSOR
);
1895 if (lua_isstring(L
, 2)) {
1896 const char *key
= lua_tostring(L
, 2);
1897 if (strcmp(key
, "pos") == 0) {
1898 size_t pos
= checkpos(L
, 3);
1899 view_cursors_to(sel
, pos
);
1903 if (strcmp(key
, "selection") == 0) {
1904 Filerange range
= getrange(L
, 3);
1905 if (text_range_valid(&range
)) {
1906 view_selections_set(sel
, &range
);
1907 view_selections_anchor(sel
);
1909 view_selection_clear(sel
);
1914 return newindex_common(L
);
1920 * @tparam int line the 1-based line number
1921 * @tparam int col the 1-based column number
1923 static int window_cursor_to(lua_State
*L
) {
1924 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_CURSOR
);
1926 size_t line
= checkpos(L
, 2);
1927 size_t col
= checkpos(L
, 3);
1928 view_cursors_place(sel
, line
, col
);
1933 static const struct luaL_Reg window_cursor_funcs
[] = {
1934 { "__index", window_cursor_index
},
1935 { "__newindex", window_cursor_newindex
},
1936 { "to", window_cursor_to
},
1946 * @tfield string name the file name relative to current working directory or `nil` if not yet named
1950 * @tfield string path the absolute file path or `nil` if not yet named
1953 * File content by logical lines.
1955 * Assigning to array element `0` (`#lines+1`) will insert a new line at
1956 * the beginning (end) of the file.
1957 * @tfield Array(string) lines the file content accessible as 1-based array
1960 * local lines = vis.win.file.lines
1961 * for i=1, #lines do
1962 * lines[i] = i .. ": " .. lines[i]
1966 * File size in bytes.
1967 * @tfield int size the current file size in bytes
1971 * @tfield bool modified whether the file contains unsaved changes
1975 * @field marks array to access the marks of this file by single letter name
1977 static int file_index(lua_State
*L
) {
1978 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
1980 if (lua_isstring(L
, 2)) {
1981 const char *key
= lua_tostring(L
, 2);
1982 if (strcmp(key
, "name") == 0) {
1983 lua_pushstring(L
, file_name_get(file
));
1987 if (strcmp(key
, "path") == 0) {
1988 lua_pushstring(L
, file
->name
);
1992 if (strcmp(key
, "lines") == 0) {
1993 obj_ref_new(L
, file
->text
, VIS_LUA_TYPE_TEXT
);
1997 if (strcmp(key
, "size") == 0) {
1998 lua_pushunsigned(L
, text_size(file
->text
));
2002 if (strcmp(key
, "modified") == 0) {
2003 lua_pushboolean(L
, text_modified(file
->text
));
2007 if (strcmp(key
, "marks") == 0) {
2008 obj_ref_new(L
, file
->marks
, VIS_LUA_TYPE_MARKS
);
2013 return index_common(L
);
2017 * Insert data at position.
2019 * @tparam int pos the 0-based file position in bytes
2020 * @tparam string data the data to insert
2021 * @treturn bool whether the file content was successfully changed
2023 static int file_insert(lua_State
*L
) {
2024 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2025 size_t pos
= checkpos(L
, 2);
2027 luaL_checkstring(L
, 3);
2028 const char *data
= lua_tolstring(L
, 3, &len
);
2029 lua_pushboolean(L
, text_insert(file
->text
, pos
, data
, len
));
2034 * Delete data at position.
2037 * @tparam int pos the 0-based file position in bytes
2038 * @tparam int len the length in bytes to delete
2039 * @treturn bool whether the file content was successfully changed
2042 * Delete file range.
2045 * @tparam Range range the range to delete
2046 * @treturn bool whether the file content was successfully changed
2048 static int file_delete(lua_State
*L
) {
2049 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2050 Filerange range
= getrange(L
, 2);
2051 lua_pushboolean(L
, text_delete_range(file
->text
, &range
));
2056 * Create an iterator over all lines of the file.
2058 * For large files this is probably faster than @{lines}.
2059 * @function lines_iterator
2060 * @return the new iterator
2063 * for line in file:lines_iterator() do
2064 * -- do something with line
2067 static int file_lines_iterator_it(lua_State
*L
);
2068 static int file_lines_iterator(lua_State
*L
) {
2069 /* need to check second parameter first, because obj_ref_check_get
2070 * modifies the stack */
2071 size_t line
= luaL_optunsigned(L
, 2, 1);
2072 File
*file
= obj_ref_check_get(L
, 1, VIS_LUA_TYPE_FILE
);
2073 size_t *pos
= lua_newuserdata(L
, sizeof *pos
);
2074 *pos
= text_pos_by_lineno(file
->text
, line
);
2075 lua_pushcclosure(L
, file_lines_iterator_it
, 2);
2079 static int file_lines_iterator_it(lua_State
*L
) {
2080 File
*file
= *(File
**)lua_touserdata(L
, lua_upvalueindex(1));
2081 size_t *start
= lua_touserdata(L
, lua_upvalueindex(2));
2082 if (*start
== text_size(file
->text
))
2084 size_t end
= text_line_end(file
->text
, *start
);
2085 size_t len
= end
- *start
;
2086 char *buf
= malloc(len
);
2089 len
= text_bytes_get(file
->text
, *start
, len
, buf
);
2090 lua_pushlstring(L
, buf
, len
);
2092 *start
= text_line_next(file
->text
, end
);
2097 * Get file content of position and length.
2100 * @tparam int pos the 0-based file position in bytes
2101 * @tparam int len the length in bytes to read
2102 * @treturn string the file content corresponding to the range
2105 * local file = vis.win.file
2106 * local text = file:content(0, file.size)
2109 * Get file content of range.
2112 * @tparam Range range the range to read
2113 * @treturn string the file content corresponding to the range
2115 static int file_content(lua_State
*L
) {
2116 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2117 Filerange range
= getrange(L
, 2);
2118 if (!text_range_valid(&range
))
2120 size_t len
= text_range_size(&range
);
2121 char *data
= malloc(len
);
2124 len
= text_bytes_get(file
->text
, range
.start
, len
, data
);
2125 lua_pushlstring(L
, data
, len
);
2135 * @function mark_set
2136 * @tparam int pos the position to set the mark to, must be in [0, file.size]
2137 * @treturn Mark mark the mark which can be looked up later
2139 static int file_mark_set(lua_State
*L
) {
2140 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2141 size_t pos
= checkpos(L
, 2);
2142 Mark mark
= text_mark_set(file
->text
, pos
);
2144 obj_lightref_new(L
, (void*)mark
, VIS_LUA_TYPE_MARK
);
2151 * Get position of mark.
2152 * @function mark_get
2153 * @tparam Mark mark the mark to look up
2154 * @treturn int pos the position of the mark, or `nil` if invalid
2156 static int file_mark_get(lua_State
*L
) {
2157 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2158 Mark mark
= (Mark
)obj_lightref_check(L
, 2, VIS_LUA_TYPE_MARK
);
2159 size_t pos
= text_mark_get(file
->text
, mark
);
2163 lua_pushunsigned(L
, pos
);
2170 * @function text_object_word
2171 * @tparam int pos the position which must be part of the word
2172 * @treturn Range range the range
2175 static int file_text_object(lua_State
*L
) {
2176 Filerange range
= text_range_empty();
2177 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2178 size_t pos
= checkpos(L
, 2);
2179 size_t idx
= lua_tointeger(L
, lua_upvalueindex(1));
2180 if (idx
< LENGTH(vis_textobjects
)) {
2181 const TextObject
*txtobj
= &vis_textobjects
[idx
];
2183 range
= txtobj
->txt(file
->text
, pos
);
2185 pushrange(L
, &range
);
2189 static const struct luaL_Reg file_funcs
[] = {
2190 { "__index", file_index
},
2191 { "__newindex", newindex_common
},
2192 { "insert", file_insert
},
2193 { "delete", file_delete
},
2194 { "lines_iterator", file_lines_iterator
},
2195 { "content", file_content
},
2196 { "mark_set", file_mark_set
},
2197 { "mark_get", file_mark_get
},
2201 static int file_lines_index(lua_State
*L
) {
2202 Text
*txt
= obj_ref_check(L
, 1, VIS_LUA_TYPE_TEXT
);
2203 size_t line
= luaL_checkunsigned(L
, 2);
2204 size_t start
= text_pos_by_lineno(txt
, line
);
2205 size_t end
= text_line_end(txt
, start
);
2206 if (start
!= EPOS
&& end
!= EPOS
) {
2207 size_t size
= end
- start
;
2208 char *data
= malloc(size
);
2211 size
= text_bytes_get(txt
, start
, size
, data
);
2212 lua_pushlstring(L
, data
, size
);
2221 static int file_lines_newindex(lua_State
*L
) {
2222 Text
*txt
= obj_ref_check(L
, 1, VIS_LUA_TYPE_TEXT
);
2223 size_t line
= luaL_checkunsigned(L
, 2);
2225 const char *data
= luaL_checklstring(L
, 3, &size
);
2227 text_insert(txt
, 0, data
, size
);
2228 text_insert(txt
, size
, "\n", 1);
2231 size_t start
= text_pos_by_lineno(txt
, line
);
2232 size_t end
= text_line_end(txt
, start
);
2233 if (start
!= EPOS
&& end
!= EPOS
) {
2234 text_delete(txt
, start
, end
- start
);
2235 text_insert(txt
, start
, data
, size
);
2236 if (text_size(txt
) == start
+ size
)
2237 text_insert(txt
, text_size(txt
), "\n", 1);
2242 static int file_lines_len(lua_State
*L
) {
2243 Text
*txt
= obj_ref_check(L
, 1, VIS_LUA_TYPE_TEXT
);
2246 size_t size
= text_size(txt
);
2248 lines
= text_lineno_by_pos(txt
, size
);
2249 if (lines
> 1 && text_byte_get(txt
, size
-1, &lastchar
) && lastchar
== '\n')
2251 lua_pushunsigned(L
, lines
);
2255 static const struct luaL_Reg file_lines_funcs
[] = {
2256 { "__index", file_lines_index
},
2257 { "__newindex", file_lines_newindex
},
2258 { "__len", file_lines_len
},
2262 static int file_marks_index(lua_State
*L
) {
2264 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
2265 File
*file
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_MARKS
, offsetof(File
, marks
));
2268 const char *symbol
= luaL_checkstring(L
, 2);
2269 if (strlen(symbol
) != 1)
2271 enum VisMark mark
= vis_mark_from(vis
, symbol
[0]);
2272 if (mark
== VIS_MARK_INVALID
)
2275 Array arr
= vis_mark_get(vis
, mark
);
2276 for (size_t i
= 0, len
= array_length(&arr
); i
< len
; i
++) {
2277 Filerange
*range
= array_get(&arr
, i
);
2278 lua_pushunsigned(L
, i
+1);
2279 pushrange(L
, range
);
2280 lua_settable(L
, -3);
2282 array_release(&arr
);
2286 static int file_marks_newindex(lua_State
*L
) {
2287 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
2288 File
*file
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_MARKS
, offsetof(File
, marks
));
2291 const char *symbol
= luaL_checkstring(L
, 2);
2292 if (strlen(symbol
) != 1)
2294 enum VisMark mark
= vis_mark_from(vis
, symbol
[0]);
2295 if (mark
>= LENGTH(file
->marks
))
2299 array_init_sized(&ranges
, sizeof(Filerange
));
2301 if (lua_istable(L
, 3)) {
2303 while (lua_next(L
, 3)) {
2304 Filerange range
= getrange(L
, -1);
2305 if (text_range_valid(&range
))
2306 array_add(&ranges
, &range
);
2311 vis_mark_set(vis
, mark
, &ranges
);
2312 array_release(&ranges
);
2316 static int file_marks_len(lua_State
*L
) {
2317 File
*file
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_MARKS
, offsetof(File
, marks
));
2318 lua_pushunsigned(L
, file
? LENGTH(file
->marks
) : 0);
2322 static const struct luaL_Reg file_marks_funcs
[] = {
2323 { "__index", file_marks_index
},
2324 { "__newindex", file_marks_newindex
},
2325 { "__len", file_marks_len
},
2330 * The user interface.
2335 * Number of available colors.
2336 * @tfield int colors
2342 * For a valid range `start <= finish` holds.
2343 * An invalid range is represented as `nil`.
2347 * The being of the range.
2351 * The end of the range.
2352 * @tfield int finish
2363 * @tfield int NORMAL
2364 * @tfield int OPERATOR_PENDING
2365 * @tfield int INSERT
2366 * @tfield int REPLACE
2367 * @tfield int VISUAL
2368 * @tfield int VISUAL_LINE
2376 * This section describes the contract between the editor core and Lua
2377 * key handling functions mapped to symbolic keys using either @{Vis:map}
2380 * @section Key_Handling
2384 * Example of a key handling function.
2386 * The keyhandler is invoked with the pending content of the input queue
2387 * given as argument. This might be the empty string if no further input
2390 * The function is expected to return the number of *bytes* it has
2391 * consumed from the passed input keys. A negative return value is
2392 * interpreted as an indication that not enough input was available. The
2393 * function will be called again once the user has provided more input. A
2394 * missing return value (i.e. `nil`) is interpreted as zero, meaning
2395 * no further input was consumed but the function completed successfully.
2397 * @function keyhandler
2398 * @tparam string keys the keys following the mapping
2399 * @treturn int the number of *bytes* being consumed by the function (see above)
2400 * @see Vis:action_register
2404 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
2406 * return -1 -- need more input
2408 * local digraph = keys:sub(1, 2)
2409 * if digraph == "l*" then
2411 * return 2 -- consume 2 bytes of input
2413 * end, "Insert digraph")
2419 * These events are invoked from the editor core.
2420 * The following functions are invoked if they are registered in the
2421 * `vis.events` table. Users scripts should generally use the [Events](#events)
2422 * mechanism instead which multiplexes these core events.
2424 * @section Core_Events
2427 static void vis_lua_event_get(lua_State
*L
, const char *name
) {
2428 lua_getglobal(L
, "vis");
2429 lua_getfield(L
, -1, "events");
2430 if (lua_istable(L
, -1)) {
2431 lua_getfield(L
, -1, name
);
2436 static void vis_lua_event_call(Vis
*vis
, const char *name
) {
2437 lua_State
*L
= vis
->lua
;
2438 vis_lua_event_get(L
, name
);
2439 if (lua_isfunction(L
, -1))
2440 pcall(vis
, L
, 0, 0);
2444 static bool vis_lua_path_strip(Vis
*vis
) {
2445 lua_State
*L
= vis
->lua
;
2446 lua_getglobal(L
, "package");
2448 for (const char **var
= (const char*[]){ "path", "cpath", NULL
}; *var
; var
++) {
2450 lua_getfield(L
, -1, *var
);
2451 const char *path
= lua_tostring(L
, -1);
2456 char *copy
= strdup(path
), *stripped
= calloc(1, strlen(path
)+2);
2457 if (!copy
|| !stripped
) {
2463 for (char *elem
= copy
, *stripped_elem
= stripped
, *next
; elem
; elem
= next
) {
2464 if ((next
= strstr(elem
, ";")))
2466 if (strstr(elem
, "./"))
2467 continue; /* skip relative path entries */
2468 stripped_elem
+= sprintf(stripped_elem
, "%s;", elem
);
2471 lua_pushstring(L
, stripped
);
2472 lua_setfield(L
, -2, *var
);
2478 lua_pop(L
, 1); /* package */
2482 bool vis_lua_path_add(Vis
*vis
, const char *path
) {
2483 lua_State
*L
= vis
->lua
;
2486 lua_getglobal(L
, "package");
2487 lua_pushstring(L
, path
);
2488 lua_pushstring(L
, "/?.lua;");
2489 lua_getfield(L
, -3, "path");
2491 lua_setfield(L
, -2, "path");
2492 lua_pop(L
, 1); /* package */
2496 bool vis_lua_paths_get(Vis
*vis
, char **lpath
, char **cpath
) {
2497 lua_State
*L
= vis
->lua
;
2501 lua_getglobal(L
, "package");
2502 lua_getfield(L
, -1, "path");
2503 s
= lua_tostring(L
, -1);
2504 *lpath
= s
? strdup(s
) : NULL
;
2505 lua_getfield(L
, -2, "cpath");
2506 s
= lua_tostring(L
, -1);
2507 *cpath
= s
? strdup(s
) : NULL
;
2511 static bool package_exist(Vis
*vis
, lua_State
*L
, const char *name
) {
2513 "local name = ...\n"
2514 "for _, searcher in ipairs(package.searchers or package.loaders) do\n"
2515 "local loader = searcher(name)\n"
2516 "if type(loader) == 'function' then\n"
2521 if (luaL_loadstring(L
, lua
) != LUA_OK
)
2523 lua_pushstring(L
, name
);
2524 /* an error indicates package exists */
2525 bool ret
= lua_pcall(L
, 1, 1, 0) != LUA_OK
|| lua_toboolean(L
, -1);
2530 static void *alloc_lua(void *ud
, void *ptr
, size_t osize
, size_t nsize
) {
2535 return realloc(ptr
, nsize
);
2540 * Editor initialization completed.
2541 * This event is emitted immediately after `visrc.lua` has been sourced, but
2542 * before any other events have occured, in particular the command line arguments
2543 * have not yet been processed.
2545 * Can be used to set *global* configuration options.
2548 void vis_lua_init(Vis
*vis
) {
2549 lua_State
*L
= lua_newstate(alloc_lua
, vis
);
2553 lua_atpanic(L
, &panic_handler
);
2558 extern int luaopen_lpeg(lua_State
*L
);
2559 lua_getglobal(L
, "package");
2560 lua_getfield(L
, -1, "preload");
2561 lua_pushcfunction(L
, luaopen_lpeg
);
2562 lua_setfield(L
, -2, "lpeg");
2566 /* remove any relative paths from lua's default package.path */
2567 vis_lua_path_strip(vis
);
2569 /* extends lua's package.path with:
2571 * - ./lua (relative path to the binary location)
2572 * - $XDG_CONFIG_HOME/vis (defaulting to $HOME/.config/vis)
2573 * - /etc/vis (for system-wide configuration provided by administrator)
2574 * - /usr/(local/)?share/vis (or whatever is specified during ./configure)
2575 * - package.path (standard lua search path)
2577 char path
[PATH_MAX
];
2579 vis_lua_path_add(vis
, VIS_PATH
);
2581 /* try to get users home directory */
2582 const char *home
= getenv("HOME");
2583 if (!home
|| !*home
) {
2584 struct passwd
*pw
= getpwuid(getuid());
2589 vis_lua_path_add(vis
, "/etc/vis");
2591 const char *xdg_config
= getenv("XDG_CONFIG_HOME");
2593 snprintf(path
, sizeof path
, "%s/vis", xdg_config
);
2594 vis_lua_path_add(vis
, path
);
2595 } else if (home
&& *home
) {
2596 snprintf(path
, sizeof path
, "%s/.config/vis", home
);
2597 vis_lua_path_add(vis
, path
);
2600 ssize_t len
= readlink("/proc/self/exe", path
, sizeof(path
)-1);
2603 /* some idotic dirname(3) implementations return pointers to statically
2604 * allocated memory, hence we use memmove to copy it back */
2605 char *dir
= dirname(path
);
2607 size_t len
= strlen(dir
)+1;
2608 if (len
< sizeof(path
) - sizeof("/lua")) {
2609 memmove(path
, dir
, len
);
2610 strcat(path
, "/lua");
2611 vis_lua_path_add(vis
, path
);
2616 vis_lua_path_add(vis
, getenv("VIS_PATH"));
2618 /* table in registry to lookup object type, stores metatable -> type mapping */
2620 lua_setfield(L
, LUA_REGISTRYINDEX
, "vis.types");
2621 /* table in registry to track lifetimes of C objects */
2623 lua_setfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
2624 /* table in registry to store references to Lua functions */
2626 lua_setfield(L
, LUA_REGISTRYINDEX
, "vis.functions");
2627 /* metatable used to type check user data */
2628 obj_type_new(L
, VIS_LUA_TYPE_VIS
);
2629 luaL_setfuncs(L
, vis_lua
, 0);
2631 lua_setfield(L
, -2, "types");
2632 /* create reference to main vis object, such that the further
2633 * calls to obj_type_new can register the type meta tables in
2634 * vis.types[name] */
2635 obj_ref_new(L
, vis
, "vis");
2636 lua_setglobal(L
, "vis");
2638 obj_type_new(L
, VIS_LUA_TYPE_FILE
);
2641 enum VisTextObject id
;
2644 { VIS_TEXTOBJECT_INNER_WORD
, "text_object_word" },
2647 for (size_t i
= 0; i
< LENGTH(textobjects
); i
++) {
2648 lua_pushunsigned(L
, textobjects
[i
].id
);
2649 lua_pushcclosure(L
, file_text_object
, 1);
2650 lua_setfield(L
, -2, textobjects
[i
].name
);
2653 luaL_setfuncs(L
, file_funcs
, 0);
2655 obj_type_new(L
, VIS_LUA_TYPE_TEXT
);
2656 luaL_setfuncs(L
, file_lines_funcs
, 0);
2657 obj_type_new(L
, VIS_LUA_TYPE_WINDOW
);
2658 luaL_setfuncs(L
, window_funcs
, 0);
2664 { UI_STYLE_DEFAULT
, "STYLE_DEFAULT" },
2665 { UI_STYLE_CURSOR
, "STYLE_CURSOR" },
2666 { UI_STYLE_CURSOR_PRIMARY
, "STYLE_CURSOR_PRIMARY" },
2667 { UI_STYLE_CURSOR_LINE
, "STYLE_CURSOR_LINE" },
2668 { UI_STYLE_SELECTION
, "STYLE_SELECTION" },
2669 { UI_STYLE_LINENUMBER
, "STYLE_LINENUMBER" },
2670 { UI_STYLE_LINENUMBER_CURSOR
, "STYLE_LINENUMBER_CURSOR" },
2671 { UI_STYLE_COLOR_COLUMN
, "STYLE_COLOR_COLUMN" },
2672 { UI_STYLE_STATUS
, "STYLE_STATUS" },
2673 { UI_STYLE_STATUS_FOCUSED
, "STYLE_STATUS_FOCUSED" },
2674 { UI_STYLE_SEPARATOR
, "STYLE_SEPARATOR" },
2675 { UI_STYLE_INFO
, "STYLE_INFO" },
2676 { UI_STYLE_EOF
, "STYLE_EOF" },
2679 for (size_t i
= 0; i
< LENGTH(styles
); i
++) {
2680 lua_pushunsigned(L
, styles
[i
].id
);
2681 lua_setfield(L
, -2, styles
[i
].name
);
2684 obj_type_new(L
, VIS_LUA_TYPE_MARK
);
2685 obj_type_new(L
, VIS_LUA_TYPE_MARKS
);
2686 lua_pushlightuserdata(L
, vis
);
2687 luaL_setfuncs(L
, file_marks_funcs
, 1);
2689 obj_type_new(L
, VIS_LUA_TYPE_CURSOR
);
2690 luaL_setfuncs(L
, window_cursor_funcs
, 0);
2691 obj_type_new(L
, VIS_LUA_TYPE_CURSORS
);
2692 luaL_setfuncs(L
, window_cursors_funcs
, 0);
2694 obj_type_new(L
, VIS_LUA_TYPE_UI
);
2695 luaL_setfuncs(L
, ui_funcs
, 0);
2696 lua_pushunsigned(L
, vis
->ui
->colors(vis
->ui
));
2697 lua_setfield(L
, -2, "colors");
2699 obj_type_new(L
, VIS_LUA_TYPE_REGISTERS
);
2700 lua_pushlightuserdata(L
, vis
);
2701 luaL_setfuncs(L
, registers_funcs
, 1);
2703 obj_type_new(L
, VIS_LUA_TYPE_KEYACTION
);
2705 lua_getglobal(L
, "vis");
2706 lua_getmetatable(L
, -1);
2708 lua_pushstring(L
, VERSION
);
2709 lua_setfield(L
, -2, "VERSION");
2713 static const struct {
2717 { VIS_MODE_NORMAL
, "NORMAL" },
2718 { VIS_MODE_OPERATOR_PENDING
, "OPERATOR_PENDING" },
2719 { VIS_MODE_VISUAL
, "VISUAL" },
2720 { VIS_MODE_VISUAL_LINE
, "VISUAL_LINE" },
2721 { VIS_MODE_INSERT
, "INSERT" },
2722 { VIS_MODE_REPLACE
, "REPLACE" },
2725 for (size_t i
= 0; i
< LENGTH(modes
); i
++) {
2726 lua_pushunsigned(L
, modes
[i
].id
);
2727 lua_setfield(L
, -2, modes
[i
].name
);
2730 lua_setfield(L
, -2, "modes");
2732 if (!package_exist(vis
, L
, "visrc")) {
2733 vis_info_show(vis
, "WARNING: failed to load visrc.lua");
2735 lua_getglobal(L
, "require");
2736 lua_pushstring(L
, "visrc");
2737 pcall(vis
, L
, 1, 0);
2738 vis_lua_event_call(vis
, "init");
2743 * Editor startup completed.
2744 * This event is emitted immediately before the main loop starts.
2745 * At this point all files are loaded and corresponding windows are created.
2746 * We are about to process interactive keyboard input.
2749 void vis_lua_start(Vis
*vis
) {
2750 vis_lua_event_call(vis
, "start");
2754 * Editor is about to terminate.
2757 void vis_lua_quit(Vis
*vis
) {
2760 vis_lua_event_call(vis
, "quit");
2761 lua_close(vis
->lua
);
2766 * Input key event in either input or replace mode.
2768 * @tparam string key
2769 * @treturn bool whether the key was cosumed or not
2771 static bool vis_lua_input(Vis
*vis
, const char *key
, size_t len
) {
2772 lua_State
*L
= vis
->lua
;
2773 if (!L
|| vis
->win
->file
->internal
)
2776 vis_lua_event_get(L
, "input");
2777 if (lua_isfunction(L
, -1)) {
2778 lua_pushlstring(L
, key
, len
);
2779 if (pcall(vis
, L
, 1, 1) == 0) {
2780 ret
= lua_isboolean(L
, -1) && lua_toboolean(L
, -1);
2788 void vis_lua_mode_insert_input(Vis
*vis
, const char *key
, size_t len
) {
2789 if (!vis_lua_input(vis
, key
, len
))
2790 vis_insert_key(vis
, key
, len
);
2793 void vis_lua_mode_replace_input(Vis
*vis
, const char *key
, size_t len
) {
2794 if (!vis_lua_input(vis
, key
, len
))
2795 vis_replace_key(vis
, key
, len
);
2800 * @function file_open
2801 * @tparam File file the file to be opened
2803 void vis_lua_file_open(Vis
*vis
, File
*file
) {
2804 debug("event: file-open: %s %p %p\n", file
->name
? file
->name
: "unnamed", (void*)file
, (void*)file
->text
);
2805 lua_State
*L
= vis
->lua
;
2808 vis_lua_event_get(L
, "file_open");
2809 if (lua_isfunction(L
, -1)) {
2810 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
2811 pcall(vis
, L
, 1, 0);
2818 * Triggered *before* the file is being written.
2819 * @function file_save_pre
2820 * @tparam File file the file being written
2821 * @tparam string path the absolute path to which the file will be written, `nil` if standard output
2822 * @treturn bool whether the write operation should be proceeded
2824 bool vis_lua_file_save_pre(Vis
*vis
, File
*file
, const char *path
) {
2825 lua_State
*L
= vis
->lua
;
2828 vis_lua_event_get(L
, "file_save_pre");
2829 if (lua_isfunction(L
, -1)) {
2830 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
2831 lua_pushstring(L
, path
);
2832 if (pcall(vis
, L
, 2, 1) != 0)
2834 return !lua_isboolean(L
, -1) || lua_toboolean(L
, -1);
2842 * Triggered *after* a successfull write operation.
2843 * @function file_save_post
2844 * @tparam File file the file which was written
2845 * @tparam string path the absolute path to which it was written, `nil` if standard output
2847 void vis_lua_file_save_post(Vis
*vis
, File
*file
, const char *path
) {
2848 lua_State
*L
= vis
->lua
;
2851 vis_lua_event_get(L
, "file_save_post");
2852 if (lua_isfunction(L
, -1)) {
2853 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
2854 lua_pushstring(L
, path
);
2855 pcall(vis
, L
, 2, 0);
2862 * The last window displaying the file has been closed.
2863 * @function file_close
2864 * @tparam File file the file being closed
2866 void vis_lua_file_close(Vis
*vis
, File
*file
) {
2867 debug("event: file-close: %s %p %p\n", file
->name
? file
->name
: "unnamed", (void*)file
, (void*)file
->text
);
2868 lua_State
*L
= vis
->lua
;
2871 vis_lua_event_get(L
, "file_close");
2872 if (lua_isfunction(L
, -1)) {
2873 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
2874 pcall(vis
, L
, 1, 0);
2876 obj_ref_free(L
, file
->marks
);
2877 obj_ref_free(L
, file
->text
);
2878 obj_ref_free(L
, file
);
2884 * A new window has been created.
2885 * @function win_open
2886 * @tparam Window win the window being opened
2888 void vis_lua_win_open(Vis
*vis
, Win
*win
) {
2889 debug("event: win-open: %s %p %p\n", win
->file
->name
? win
->file
->name
: "unnamed", (void*)win
, (void*)win
->view
);
2890 lua_State
*L
= vis
->lua
;
2893 vis_lua_event_get(L
, "win_open");
2894 if (lua_isfunction(L
, -1)) {
2895 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
2896 pcall(vis
, L
, 1, 0);
2903 * An window is being closed.
2904 * @function win_close
2905 * @tparam Window win the window being closed
2907 void vis_lua_win_close(Vis
*vis
, Win
*win
) {
2908 debug("event: win-close: %s %p %p\n", win
->file
->name
? win
->file
->name
: "unnamed", (void*)win
, (void*)win
->view
);
2909 lua_State
*L
= vis
->lua
;
2912 vis_lua_event_get(L
, "win_close");
2913 if (lua_isfunction(L
, -1)) {
2914 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
2915 pcall(vis
, L
, 1, 0);
2917 obj_ref_free(L
, win
->view
);
2918 obj_ref_free(L
, win
);
2924 * The window has been redrawn and the syntax highlighting needs to be performed.
2925 * @function win_highlight
2926 * @tparam Window win the window being redrawn
2929 void vis_lua_win_highlight(Vis
*vis
, Win
*win
) {
2930 lua_State
*L
= vis
->lua
;
2933 vis_lua_event_get(L
, "win_highlight");
2934 if (lua_isfunction(L
, -1)) {
2935 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
2936 pcall(vis
, L
, 1, 0);
2942 * Window status bar redraw.
2943 * @function win_status
2944 * @tparam Window win the affected window
2947 void vis_lua_win_status(Vis
*vis
, Win
*win
) {
2948 lua_State
*L
= vis
->lua
;
2949 if (!L
|| win
->file
->internal
) {
2950 window_status_update(vis
, win
);
2953 vis_lua_event_get(L
, "win_status");
2954 if (lua_isfunction(L
, -1)) {
2955 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
2956 pcall(vis
, L
, 1, 0);
2958 window_status_update(vis
, win
);