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_WIN_OPTS "winoptions"
35 #define VIS_LUA_TYPE_VIS_OPTS "visoptions"
36 #define VIS_LUA_TYPE_FILE "file"
37 #define VIS_LUA_TYPE_TEXT "text"
38 #define VIS_LUA_TYPE_MARK "mark"
39 #define VIS_LUA_TYPE_MARKS "marks"
40 #define VIS_LUA_TYPE_WINDOW "window"
41 #define VIS_LUA_TYPE_SELECTION "selection"
42 #define VIS_LUA_TYPE_SELECTIONS "selections"
43 #define VIS_LUA_TYPE_UI "ui"
44 #define VIS_LUA_TYPE_REGISTERS "registers"
45 #define VIS_LUA_TYPE_KEYACTION "keyaction"
52 #define debug(...) do { printf(__VA_ARGS__); fflush(stdout); } while (0)
54 #define debug(...) do { } while (0)
57 static void window_status_update(Vis
*vis
, Win
*win
) {
58 char left_parts
[4][255] = { "", "", "", "" };
59 char right_parts
[4][32] = { "", "", "", "" };
60 char left
[sizeof(left_parts
)+LENGTH(left_parts
)*8];
61 char right
[sizeof(right_parts
)+LENGTH(right_parts
)*8];
62 char status
[sizeof(left
)+sizeof(right
)+1];
63 size_t left_count
= 0;
64 size_t right_count
= 0;
66 View
*view
= win
->view
;
67 File
*file
= win
->file
;
68 Text
*txt
= file
->text
;
69 int width
= vis_window_width_get(win
);
70 enum UiOption options
= view_options_get(view
);
71 bool focused
= vis
->win
== win
;
72 const char *filename
= file_name_get(file
);
73 const char *mode
= vis
->mode
->status
;
76 strcpy(left_parts
[left_count
++], mode
);
78 snprintf(left_parts
[left_count
++], sizeof(left_parts
[0]), "%s%s%s",
79 filename
? filename
: "[No Name]",
80 text_modified(txt
) ? " [+]" : "",
81 vis_macro_recording(vis
) ? " @": "");
83 int count
= vis_count_get(vis
);
84 const char *keys
= buffer_content0(&vis
->input_queue
);
86 snprintf(right_parts
[right_count
++], sizeof(right_parts
[0]), "%s", keys
);
87 else if (count
!= VIS_COUNT_UNKNOWN
)
88 snprintf(right_parts
[right_count
++], sizeof(right_parts
[0]), "%d", count
);
90 int sel_count
= view_selections_count(view
);
92 Selection
*s
= view_selections_primary_get(view
);
93 int sel_number
= view_selections_number(s
) + 1;
94 snprintf(right_parts
[right_count
++], sizeof(right_parts
[0]),
95 "%d/%d", sel_number
, sel_count
);
98 size_t size
= text_size(txt
);
99 size_t pos
= view_cursor_get(view
);
102 double tmp
= ((double)pos
/(double)size
)*100;
103 percent
= (size_t)(tmp
+1);
105 snprintf(right_parts
[right_count
++], sizeof(right_parts
[0]),
108 if (!(options
& UI_OPTION_LARGE_FILE
)) {
109 Selection
*sel
= view_selections_primary_get(win
->view
);
110 size_t line
= view_cursors_line(sel
);
111 size_t col
= view_cursors_col(sel
);
112 if (col
> UI_LARGE_FILE_LINE_SIZE
) {
113 options
|= UI_OPTION_LARGE_FILE
;
114 view_options_set(win
->view
, options
);
116 snprintf(right_parts
[right_count
++], sizeof(right_parts
[0]),
117 "%zu, %zu", line
, col
);
120 int left_len
= snprintf(left
, sizeof(left
), " %s%s%s%s%s%s%s",
122 left_parts
[1][0] ? " » " : "",
124 left_parts
[2][0] ? " » " : "",
126 left_parts
[3][0] ? " » " : "",
129 int right_len
= snprintf(right
, sizeof(right
), "%s%s%s%s%s%s%s ",
131 right_parts
[1][0] ? " « " : "",
133 right_parts
[2][0] ? " « " : "",
135 right_parts
[3][0] ? " « " : "",
138 if (left_len
< 0 || right_len
< 0)
140 int left_width
= text_string_width(left
, left_len
);
141 int right_width
= text_string_width(right
, right_len
);
143 int spaces
= width
- left_width
- right_width
;
147 snprintf(status
, sizeof(status
), "%s%*s%s", left
, spaces
, " ", right
);
148 vis_window_status(win
, status
);
153 bool vis_lua_path_add(Vis
*vis
, const char *path
) { return true; }
154 bool vis_lua_paths_get(Vis
*vis
, char **lpath
, char **cpath
) { return false; }
155 void vis_lua_init(Vis
*vis
) { }
156 void vis_lua_start(Vis
*vis
) { }
157 void vis_lua_quit(Vis
*vis
) { }
158 void vis_lua_file_open(Vis
*vis
, File
*file
) { }
159 bool vis_lua_file_save_pre(Vis
*vis
, File
*file
, const char *path
) { return true; }
160 void vis_lua_file_save_post(Vis
*vis
, File
*file
, const char *path
) { }
161 void vis_lua_file_close(Vis
*vis
, File
*file
) { }
162 void vis_lua_win_open(Vis
*vis
, Win
*win
) { }
163 void vis_lua_win_close(Vis
*vis
, Win
*win
) { }
164 void vis_lua_win_highlight(Vis
*vis
, Win
*win
) { }
165 void vis_lua_win_status(Vis
*vis
, Win
*win
) { window_status_update(vis
, win
); }
166 void vis_lua_term_csi(Vis
*vis
, const long *csi
) { }
167 void vis_lua_process_response(Vis
*vis
, const char *name
,
168 char *buffer
, size_t len
, ResponseType rtype
) { }
169 void vis_lua_ui_draw(Vis
*vis
) { }
174 static void stack_dump_entry(lua_State
*L
, int i
) {
175 int t
= lua_type(L
, i
);
181 printf(lua_toboolean(L
, i
) ? "true" : "false");
183 case LUA_TLIGHTUSERDATA
:
184 printf("lightuserdata(%p)", lua_touserdata(L
, i
));
187 printf("%g", lua_tonumber(L
, i
));
190 printf("`%s'", lua_tostring(L
, i
));
194 lua_pushnil(L
); /* first key */
195 while (lua_next(L
, i
> 0 ? i
: i
- 1)) {
196 stack_dump_entry(L
, -2);
198 stack_dump_entry(L
, -1);
200 lua_pop(L
, 1); /* remove value, keep key */
205 printf("userdata(%p)", lua_touserdata(L
, i
));
207 default: /* other values */
208 printf("%s", lua_typename(L
, t
));
213 static void stack_dump(lua_State
*L
, const char *format
, ...) {
215 va_start(ap
, format
);
218 int top
= lua_gettop(L
);
219 for (int i
= 1; i
<= top
; i
++) {
221 stack_dump_entry(L
, i
);
230 static int panic_handler(lua_State
*L
) {
232 lua_getallocf(L
, &ud
);
236 const char *msg
= NULL
;
237 if (lua_type(L
, -1) == LUA_TSTRING
)
238 msg
= lua_tostring(L
, -1);
239 vis_info_show(vis
, "Fatal Lua error: %s", msg
? msg
: "unknown reason");
242 siglongjmp(vis
->sigbus_jmpbuf
, 1);
247 static int error_handler(lua_State
*L
) {
248 const char *msg
= lua_tostring(L
, 1);
249 luaL_traceback(L
, L
, msg
? msg
: NULL
, 1);
253 static int pcall(Vis
*vis
, lua_State
*L
, int nargs
, int nresults
) {
254 /* insert a custom error function below all arguments */
255 int msgh
= lua_gettop(L
) - nargs
;
256 lua_pushcclosure(L
, error_handler
, 0);
258 int ret
= lua_pcall(L
, nargs
, nresults
, msgh
);
261 const char *msg
= lua_tostring(L
, -1);
263 if (strstr(msg
, "C stack overflow")) {
264 vis
->ui
->terminal_save(vis
->ui
, false);
265 fprintf(stderr
, "%s", msg
);
266 vis
->ui
->terminal_restore(vis
->ui
);
268 vis_message_show(vis
, msg
);
275 /* expects a lua function at stack position `narg` and stores a
276 * reference to it in the registry. The return value can be used
279 * registry["vis.functions"][(void*)(function)] = function
281 static const void *func_ref_new(lua_State
*L
, int narg
) {
282 const void *addr
= lua_topointer(L
, narg
);
283 if (!lua_isfunction(L
, narg
) || !addr
)
284 luaL_argerror(L
, narg
, "function expected");
285 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.functions");
286 lua_pushlightuserdata(L
, (void*)addr
);
287 lua_pushvalue(L
, narg
);
293 /* retrieve function from registry and place it at the top of the stack */
294 static bool func_ref_get(lua_State
*L
, const void *addr
) {
297 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.functions");
298 lua_pushlightuserdata(L
, (void*)addr
);
301 if (!lua_isfunction(L
, -1)) {
308 /* creates a new metatable for a given type and stores a mapping:
310 * registry["vis.types"][metatable] = type
312 * leaves the metatable at the top of the stack.
314 static void obj_type_new(lua_State
*L
, const char *type
) {
315 luaL_newmetatable(L
, type
);
316 lua_getglobal(L
, "vis");
317 if (!lua_isnil(L
, -1)) {
318 lua_getfield(L
, -1, "types");
319 lua_pushvalue(L
, -3);
320 lua_setfield(L
, -2, type
);
324 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.types");
325 lua_pushvalue(L
, -2);
326 lua_pushstring(L
, type
);
331 /* get type of userdatum at the top of the stack:
333 * return registry["vis.types"][getmetatable(userdata)]
335 const char *obj_type_get(lua_State
*L
) {
336 if (lua_isnil(L
, -1))
338 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.types");
339 lua_getmetatable(L
, -2);
341 // XXX: in theory string might become invalid when popped from stack
342 const char *type
= lua_tostring(L
, -1);
347 static void *obj_new(lua_State
*L
, size_t size
, const char *type
) {
348 void *obj
= lua_newuserdata(L
, size
);
349 luaL_getmetatable(L
, type
);
350 lua_setmetatable(L
, -2);
352 lua_setuservalue(L
, -2);
356 /* returns registry["vis.objects"][addr] if it is of correct type */
357 static void *obj_ref_get(lua_State
*L
, void *addr
, const char *type
) {
358 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
359 lua_pushlightuserdata(L
, addr
);
362 if (lua_isnil(L
, -1)) {
363 debug("get: vis.objects[%p] = nil\n", addr
);
368 const char *actual_type
= obj_type_get(L
);
369 if (strcmp(type
, actual_type
) != 0)
370 debug("get: vis.objects[%p] = %s (BUG: expected %s)\n", addr
, actual_type
, type
);
371 void **handle
= luaL_checkudata(L
, -1, type
);
373 debug("get: vis.objects[%p] = %s (BUG: invalid handle)\n", addr
, type
);
374 else if (*handle
!= addr
)
375 debug("get: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr
, type
, *handle
);
377 /* verify that obj is correct type then unmodify the stack */
378 luaL_checkudata(L
, -1, type
);
383 /* expects a userdatum at the top of the stack and sets
385 * registry["vis.objects"][addr] = userdata
387 static void obj_ref_set(lua_State
*L
, void *addr
) {
388 //debug("set: vis.objects[%p] = %s\n", addr, obj_type_get(L));
389 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
390 lua_pushlightuserdata(L
, addr
);
391 lua_pushvalue(L
, -3);
396 /* invalidates an object reference
398 * registry["vis.objects"][addr] = nil
400 static void obj_ref_free(lua_State
*L
, void *addr
) {
402 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
403 lua_pushlightuserdata(L
, addr
);
406 if (lua_isnil(L
, -1))
407 debug("free-unused: %p\n", addr
);
409 debug("free: vis.objects[%p] = %s\n", addr
, obj_type_get(L
));
413 obj_ref_set(L
, addr
);
416 /* creates a new object reference of given type if it does not already exist in the registry:
418 * if (registry["vis.types"][metatable(registry["vis.objects"][addr])] != type) {
419 * // XXX: should not happen
420 * registry["vis.objects"][addr] = new_obj(addr, type)
422 * return registry["vis.objects"][addr];
424 static void *obj_ref_new(lua_State
*L
, void *addr
, const char *type
) {
429 lua_getfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
430 lua_pushlightuserdata(L
, addr
);
433 const char *old_type
= obj_type_get(L
);
434 if (strcmp(type
, old_type
) == 0) {
435 debug("new: vis.objects[%p] = %s (returning existing object)\n", addr
, old_type
);
436 void **handle
= luaL_checkudata(L
, -1, type
);
438 debug("new: vis.objects[%p] = %s (BUG: invalid handle)\n", addr
, old_type
);
439 else if (*handle
!= addr
)
440 debug("new: vis.objects[%p] = %s (BUG: handle mismatch %p)\n", addr
, old_type
, *handle
);
443 if (!lua_isnil(L
, -1))
444 debug("new: vis.objects[%p] = %s (WARNING: changing object type from %s)\n", addr
, type
, old_type
);
446 debug("new: vis.objects[%p] = %s (creating new object)\n", addr
, type
);
448 void **handle
= obj_new(L
, sizeof(addr
), type
);
449 obj_ref_set(L
, addr
);
454 /* (type) check validity of object reference at stack location `idx' and retrieve it */
455 static void *obj_ref_check(lua_State
*L
, int idx
, const char *type
) {
456 void **addr
= luaL_checkudata(L
, idx
, type
);
457 if (!obj_ref_get(L
, *addr
, 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 /* on most systems SIZE_MAX can't be represented in lua_Number.
507 * using < avoids undefined behaviour when n == SIZE_MAX+1
508 * which can be represented in lua_Number
510 if (n
>= 0 && n
< (lua_Number
)SIZE_MAX
&& n
== (size_t)n
)
512 return luaL_argerror(L
, narg
, "expected position, got number");
515 static void pushpos(lua_State
*L
, size_t pos
) {
519 lua_pushunsigned(L
, pos
);
522 static void pushrange(lua_State
*L
, Filerange
*r
) {
523 if (!r
|| !text_range_valid(r
)) {
527 lua_createtable(L
, 0, 2);
528 lua_pushstring(L
, "start");
529 lua_pushunsigned(L
, r
->start
);
531 lua_pushstring(L
, "finish");
532 lua_pushunsigned(L
, r
->end
);
536 static Filerange
getrange(lua_State
*L
, int index
) {
537 Filerange range
= text_range_empty();
538 if (lua_istable(L
, index
)) {
539 lua_getfield(L
, index
, "start");
540 range
.start
= checkpos(L
, -1);
542 lua_getfield(L
, index
, "finish");
543 range
.end
= checkpos(L
, -1);
546 range
.start
= checkpos(L
, index
);
547 range
.end
= range
.start
+ checkpos(L
, index
+1);
552 static const char *keymapping(Vis
*vis
, const char *keys
, const Arg
*arg
) {
553 lua_State
*L
= vis
->lua
;
554 if (!func_ref_get(L
, arg
->v
))
556 lua_pushstring(L
, keys
);
557 if (pcall(vis
, L
, 1, 1) != 0)
559 if (lua_type(L
, -1) != LUA_TNUMBER
)
560 return keys
; /* invalid or no return value, assume zero */
561 lua_Number number
= lua_tonumber(L
, -1);
562 lua_Integer integer
= lua_tointeger(L
, -1);
563 if (number
!= integer
)
566 return NULL
; /* need more input */
567 size_t len
= integer
;
568 size_t max
= strlen(keys
);
569 return (len
<= max
) ? keys
+len
: keys
;
573 * The main editor object.
578 * Version information.
579 * @tfield string VERSION
580 * version information in `git describe` format, same as reported by `vis -v`.
583 * Lua API object types
584 * @field types meta tables of userdata objects used for type checking
589 * @tfield Ui ui the user interface being used
593 * @tfield modes modes
597 * @tfield events events
601 * @field registers array to access the register by single letter name
604 * Scintillua lexer module.
605 * @field lexers might be `nil` if module is not found
609 * @field lpeg might be `nil` if module is not found
613 * @tfield int count the specified count for the current command or `nil` if none was given
617 * Create an iterator over all windows.
619 * @return the new iterator
622 * for win in vis:windows() do
623 * -- do something with win
626 static int windows_iter(lua_State
*L
);
627 static int windows(lua_State
*L
) {
628 Vis
*vis
= obj_ref_check(L
, 1, "vis");
629 Win
**handle
= lua_newuserdata(L
, sizeof *handle
), *next
;
630 for (next
= vis
->windows
; next
&& next
->file
->internal
; next
= next
->next
);
632 lua_pushcclosure(L
, windows_iter
, 1);
636 static int windows_iter(lua_State
*L
) {
637 Win
**handle
= lua_touserdata(L
, lua_upvalueindex(1));
640 Win
*win
= obj_ref_new(L
, *handle
, VIS_LUA_TYPE_WINDOW
), *next
;
642 for (next
= win
->next
; next
&& next
->file
->internal
; next
= next
->next
);
649 * Create an iterator over all files.
651 * @return the new iterator
653 * for file in vis:files() do
654 * -- do something with file
657 static int files_iter(lua_State
*L
);
658 static int files(lua_State
*L
) {
659 Vis
*vis
= obj_ref_check(L
, 1, "vis");
660 File
**handle
= lua_newuserdata(L
, sizeof *handle
);
661 *handle
= vis
->files
;
662 lua_pushcclosure(L
, files_iter
, 1);
666 static int files_iter(lua_State
*L
) {
667 File
**handle
= lua_touserdata(L
, lua_upvalueindex(1));
670 File
*file
= obj_ref_new(L
, *handle
, VIS_LUA_TYPE_FILE
);
672 *handle
= file
->next
;
677 * Create an iterator over all mark names.
678 * @function mark_names
679 * @return the new iterator
681 * local marks = vis.win.marks
682 * for name in vis:mark_names() do
683 * local mark = marks[name]
684 * for i = 1, #mark do
685 * -- do something with: name, mark[i].start, mark[i].finish
689 static int mark_names_iter(lua_State
*L
);
690 static int mark_names(lua_State
*L
) {
691 Vis
*vis
= obj_ref_check(L
, 1, "vis");
692 lua_pushlightuserdata(L
, vis
);
693 enum VisMark
*handle
= lua_newuserdata(L
, sizeof *handle
);
695 lua_pushcclosure(L
, mark_names_iter
, 2);
699 static int mark_names_iter(lua_State
*L
) {
700 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
701 enum VisMark
*handle
= lua_touserdata(L
, lua_upvalueindex(2));
702 char mark
= vis_mark_to(vis
, *handle
);
704 lua_pushlstring(L
, &mark
, 1);
712 * Create an iterator over all register names.
713 * @function register_names
714 * @return the new iterator
716 * for name in vis:register_names() do
717 * local reg = vis.registers[name]
719 * -- do something with register value reg[i]
723 static int register_names_iter(lua_State
*L
);
724 static int register_names(lua_State
*L
) {
725 Vis
*vis
= obj_ref_check(L
, 1, "vis");
726 lua_pushlightuserdata(L
, vis
);
727 enum VisRegister
*handle
= lua_newuserdata(L
, sizeof *handle
);
729 lua_pushcclosure(L
, register_names_iter
, 2);
733 static int register_names_iter(lua_State
*L
) {
734 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
735 enum VisRegister
*handle
= lua_touserdata(L
, lua_upvalueindex(2));
736 char reg
= vis_register_to(vis
, *handle
);
738 lua_pushlstring(L
, ®
, 1);
746 * Execute a `:`-command.
748 * @tparam string command the command to execute
749 * @treturn bool whether the command succeeded
751 * vis:command("set number")
753 static int command(lua_State
*L
) {
754 Vis
*vis
= obj_ref_check(L
, 1, "vis");
755 const char *cmd
= luaL_checkstring(L
, 2);
756 bool ret
= vis_cmd(vis
, cmd
);
757 lua_pushboolean(L
, ret
);
762 * Display a short message.
764 * The single line message will be displayed at the bottom of
765 * the screen and automatically hidden once a key is pressed.
768 * @tparam string message the message to display
770 static int info(lua_State
*L
) {
771 Vis
*vis
= obj_ref_check(L
, 1, "vis");
772 const char *msg
= luaL_checkstring(L
, 2);
773 vis_info_show(vis
, "%s", msg
);
778 * Display a multi line message.
780 * Opens a new window and displays an arbitrarily long message.
783 * @tparam string message the message to display
785 static int message(lua_State
*L
) {
786 Vis
*vis
= obj_ref_check(L
, 1, "vis");
787 const char *msg
= luaL_checkstring(L
, 2);
788 vis_message_show(vis
, msg
);
793 * Register a Lua function as key action.
794 * @function action_register
795 * @tparam string name the name of the action, can be referred to in key bindings as `<name>` pseudo key
796 * @tparam Function func the lua function implementing the key action (see @{keyhandler})
797 * @tparam[opt] string help the single line help text as displayed in `:help`
798 * @treturn KeyAction action the registered key action
802 static int action_register(lua_State
*L
) {
803 Vis
*vis
= obj_ref_check(L
, 1, "vis");
804 const char *name
= luaL_checkstring(L
, 2);
805 const void *func
= func_ref_new(L
, 3);
806 const char *help
= luaL_optstring(L
, 4, NULL
);
807 KeyAction
*action
= vis_action_new(vis
, name
, help
, keymapping
, (Arg
){ .v
= func
});
810 if (!vis_action_register(vis
, action
))
812 obj_ref_new(L
, action
, VIS_LUA_TYPE_KEYACTION
);
815 vis_action_free(vis
, action
);
820 static int keymap(lua_State
*L
, Vis
*vis
, Win
*win
) {
821 int mode
= luaL_checkint(L
, 2);
822 const char *key
= luaL_checkstring(L
, 3);
823 const char *help
= luaL_optstring(L
, 5, NULL
);
824 KeyBinding
*binding
= vis_binding_new(vis
);
827 if (lua_isstring(L
, 4)) {
828 const char *alias
= luaL_checkstring(L
, 4);
829 if (!(binding
->alias
= strdup(alias
)))
831 } else if (lua_isfunction(L
, 4)) {
832 const void *func
= func_ref_new(L
, 4);
833 if (!(binding
->action
= vis_action_new(vis
, NULL
, help
, keymapping
, (Arg
){ .v
= func
})))
835 } else if (lua_isuserdata(L
, 4)) {
836 binding
->action
= obj_ref_check(L
, 4, VIS_LUA_TYPE_KEYACTION
);
842 if (!vis_window_mode_map(win
, mode
, true, key
, binding
))
845 if (!vis_mode_map(vis
, mode
, true, key
, binding
))
849 lua_pushboolean(L
, true);
852 vis_binding_free(vis
, binding
);
853 lua_pushboolean(L
, false);
858 * Map a key to a Lua function.
860 * Creates a new key mapping in a given mode.
863 * @tparam int mode the mode to which the mapping should be added
864 * @tparam string key the key to map
865 * @tparam function func the Lua function to handle the key mapping (see @{keyhandler})
866 * @tparam[opt] string help the single line help text as displayed in `:help`
867 * @treturn bool whether the mapping was successfully established
870 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
872 * return -1 -- need more input
874 * local digraph = keys:sub(1, 2)
875 * if digraph == "l*" then
877 * return 2 -- consume 2 bytes of input
879 * end, "Insert digraph")
884 * This is equivalent to `vis:command('map! mode key alias')`.
886 * Mappings are always recursive!
888 * @tparam int mode the mode to which the mapping should be added
889 * @tparam string key the key to map
890 * @tparam string alias the key to map to
891 * @treturn bool whether the mapping was successfully established
894 * vis:map(vis.modes.NORMAL, "j", "k")
897 * Map a key to a key action.
900 * @tparam int mode the mode to which the mapping should be added
901 * @tparam string key the key to map
902 * @param action the action to map
903 * @treturn bool whether the mapping was successfully established
906 * local action = vis:action_register("info", function()
907 * vis:info("Mapping works!")
908 * end, "Info message help text")
909 * vis:map(vis.modes.NORMAL, "gh", action)
910 * vis:map(vis.modes.NORMAL, "gl", action)
912 static int map(lua_State
*L
) {
913 Vis
*vis
= obj_ref_check(L
, 1, "vis");
914 return keymap(L
, vis
, NULL
);
918 * Unmap a global key binding.
921 * @tparam int mode the mode from which the mapping should be removed
922 * @tparam string key the mapping to remove
923 * @treturn bool whether the mapping was successfully removed
926 static int keyunmap(lua_State
*L
, Vis
*vis
, Win
*win
) {
927 enum VisMode mode
= luaL_checkint(L
, 2);
928 const char *key
= luaL_checkstring(L
, 3);
931 ret
= vis_mode_unmap(vis
, mode
, key
);
933 ret
= vis_window_mode_unmap(win
, mode
, key
);
934 lua_pushboolean(L
, ret
);
938 static int unmap(lua_State
*L
) {
939 Vis
*vis
= obj_ref_check(L
, 1, "vis");
940 return keyunmap(L
, vis
, NULL
);
944 * Get all currently active mappings of a mode.
947 * @tparam int mode the mode to query
948 * @treturn table the active mappings and their associated help texts
950 * local bindings = vis:mappings(vis.modes.NORMAL)
951 * for key, help in pairs(bindings) do
956 static bool binding_collect(const char *key
, void *value
, void *ctx
) {
958 KeyBinding
*binding
= value
;
959 lua_getfield(L
, -1, key
);
960 bool new = lua_isnil(L
, -1);
963 const char *help
= binding
->alias
? binding
->alias
: VIS_HELP_USE(binding
->action
->help
);
964 lua_pushstring(L
, help
? help
: "");
965 lua_setfield(L
, -2, key
);
970 static int mappings(lua_State
*L
) {
971 Vis
*vis
= obj_ref_check(L
, 1, "vis");
973 for (Mode
*mode
= mode_get(vis
, luaL_checkint(L
, 2)); mode
; mode
= mode
->parent
) {
976 map_iterate(mode
->bindings
, binding_collect
, vis
->lua
);
985 * @tparam int id the id of the motion to execute
986 * @treturn bool whether the id was valid
989 static int motion(lua_State
*L
) {
990 Vis
*vis
= obj_ref_check(L
, 1, "vis");
991 enum VisMotion id
= luaL_checkunsigned(L
, 2);
992 // TODO handle var args?
993 lua_pushboolean(L
, vis
&& vis_motion(vis
, id
));
997 static size_t motion_lua(Vis
*vis
, Win
*win
, void *data
, size_t pos
) {
998 lua_State
*L
= vis
->lua
;
999 if (!L
|| !func_ref_get(L
, data
) || !obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
))
1002 lua_pushunsigned(L
, pos
);
1003 if (pcall(vis
, L
, 2, 1) != 0)
1005 return getpos(L
, -1);
1009 * Register a custom motion.
1011 * @function motion_register
1012 * @tparam function motion the Lua function implementing the motion
1013 * @treturn int the associated motion id, or `-1` on failure
1014 * @see motion, motion_new
1017 * -- custom motion advancing to the next byte
1018 * local id = vis:motion_register(function(win, pos)
1022 static int motion_register(lua_State
*L
) {
1023 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1024 const void *func
= func_ref_new(L
, 2);
1025 int id
= vis_motion_register(vis
, (void*)func
, motion_lua
);
1026 lua_pushinteger(L
, id
);
1031 * Execute an operator.
1033 * @function operator
1034 * @tparam int id the id of the operator to execute
1035 * @treturn bool whether the id was valid
1038 static int operator(lua_State
*L
) {
1039 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1040 enum VisOperator id
= luaL_checkunsigned(L
, 2);
1041 // TODO handle var args?
1042 lua_pushboolean(L
, vis
&& vis_operator(vis
, id
));
1046 static size_t operator_lua(Vis
*vis
, Text
*text
, OperatorContext
*c
) {
1047 lua_State
*L
= vis
->lua
;
1048 if (!L
|| !func_ref_get(L
, c
->context
))
1050 File
*file
= vis
->files
;
1051 while (file
&& (file
->internal
|| file
->text
!= text
))
1053 if (!file
|| !obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
))
1055 pushrange(L
, &c
->range
);
1057 if (pcall(vis
, L
, 3, 1) != 0)
1059 return getpos(L
, -1);
1063 * Register a custom operator.
1065 * @function operator_register
1066 * @tparam function operator the Lua function implementing the operator
1067 * @treturn int the associated operator id, or `-1` on failure
1068 * @see operator, operator_new
1071 * -- custom operator replacing every 'a' with 'b'
1072 * local id = vis:operator_register(function(file, range, pos)
1073 * local data = file:content(range)
1074 * data = data:gsub("a", "b")
1075 * file:delete(range)
1076 * file:insert(range.start, data)
1077 * return range.start -- new cursor location
1080 static int operator_register(lua_State
*L
) {
1081 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1082 const void *func
= func_ref_new(L
, 2);
1083 int id
= vis_operator_register(vis
, operator_lua
, (void*)func
);
1084 lua_pushinteger(L
, id
);
1089 * Execute a text object.
1091 * @function textobject
1092 * @tparam int id the id of the text object to execute
1093 * @treturn bool whether the id was valid
1094 * @see textobject_register, textobject_new
1097 static int textobject(lua_State
*L
) {
1098 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1099 enum VisTextObject id
= luaL_checkunsigned(L
, 2);
1100 lua_pushboolean(L
, vis_textobject(vis
, id
));
1104 static Filerange
textobject_lua(Vis
*vis
, Win
*win
, void *data
, size_t pos
) {
1105 lua_State
*L
= vis
->lua
;
1106 if (!L
|| !func_ref_get(L
, data
) || !obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
))
1107 return text_range_empty();
1108 lua_pushunsigned(L
, pos
);
1109 if (pcall(vis
, L
, 2, 2) != 0 || lua_isnil(L
, -1))
1110 return text_range_empty();
1111 return text_range_new(getpos(L
, -2), getpos(L
, -1));
1115 * Register a custom text object.
1117 * @function textobject_register
1118 * @tparam function textobject the Lua function implementing the text object
1119 * @treturn int the associated text object id, or `-1` on failure
1120 * @see textobject, textobject_new
1123 * -- custom text object covering the next byte
1124 * local id = vis:textobject_register(function(win, pos)
1128 static int textobject_register(lua_State
*L
) {
1129 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1130 const void *func
= func_ref_new(L
, 2);
1131 int id
= vis_textobject_register(vis
, 0, (void*)func
, textobject_lua
);
1132 lua_pushinteger(L
, id
);
1136 static bool option_lua(Vis
*vis
, Win
*win
, void *context
, bool toggle
,
1137 enum VisOption flags
, const char *name
, Arg
*value
) {
1138 lua_State
*L
= vis
->lua
;
1139 if (!L
|| !func_ref_get(L
, context
))
1141 if (flags
& VIS_OPTION_TYPE_BOOL
)
1142 lua_pushboolean(L
, value
->b
);
1143 else if (flags
& VIS_OPTION_TYPE_STRING
)
1144 lua_pushstring(L
, value
->s
);
1145 else if (flags
& VIS_OPTION_TYPE_NUMBER
)
1146 lua_pushnumber(L
, value
->i
);
1149 lua_pushboolean(L
, toggle
);
1150 return pcall(vis
, L
, 2, 2) == 0 && (!lua_isboolean(L
, -1) || lua_toboolean(L
, -1));
1154 * Register a custom `:set` option.
1156 * @function option_register
1157 * @tparam string name the option name
1158 * @tparam string type the option type (`bool`, `string` or `number`)
1159 * @tparam function handler the Lua function being called when the option is changed
1160 * @tparam[opt] string help the single line help text as displayed in `:help`
1161 * @treturn bool whether the option was successfully registered
1163 * vis:option_register("foo", "bool", function(value, toggle)
1164 * if not vis.win then return false end
1165 * vis.win.foo = toggle and not vis.win.foo or value
1166 * vis:info("Option foo = " .. tostring(vis.win.foo))
1168 * end, "Foo enables superpowers")
1170 static int option_register(lua_State
*L
) {
1171 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1172 const char *name
= luaL_checkstring(L
, 2);
1173 const char *type
= luaL_checkstring(L
, 3);
1174 const void *func
= func_ref_new(L
, 4);
1175 const char *help
= luaL_optstring(L
, 5, NULL
);
1176 const char *names
[] = { name
, NULL
};
1177 enum VisOption flags
= 0;
1178 if (strcmp(type
, "string") == 0)
1179 flags
|= VIS_OPTION_TYPE_STRING
;
1180 else if (strcmp(type
, "number") == 0)
1181 flags
|= VIS_OPTION_TYPE_NUMBER
;
1183 flags
|= VIS_OPTION_TYPE_BOOL
;
1184 bool ret
= vis_option_register(vis
, names
, flags
, option_lua
, (void*)func
, help
);
1185 lua_pushboolean(L
, ret
);
1190 * Unregister a `:set` option.
1192 * @function option_unregister
1193 * @tparam string name the option name
1194 * @treturn bool whether the option was successfully unregistered
1196 static int option_unregister(lua_State
*L
) {
1197 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1198 const char *name
= luaL_checkstring(L
, 2);
1199 bool ret
= vis_option_unregister(vis
, name
);
1200 lua_pushboolean(L
, ret
);
1204 static bool command_lua(Vis
*vis
, Win
*win
, void *data
, bool force
, const char *argv
[], Selection
*sel
, Filerange
*range
) {
1205 lua_State
*L
= vis
->lua
;
1206 if (!L
|| !func_ref_get(L
, data
))
1209 for (size_t i
= 0; argv
[i
]; i
++) {
1210 lua_pushunsigned(L
, i
);
1211 lua_pushstring(L
, argv
[i
]);
1212 lua_settable(L
, -3);
1214 lua_pushboolean(L
, force
);
1215 if (!obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
))
1218 sel
= view_selections_primary_get(win
->view
);
1219 if (!obj_lightref_new(L
, sel
, VIS_LUA_TYPE_SELECTION
))
1221 pushrange(L
, range
);
1222 if (pcall(vis
, L
, 5, 1) != 0)
1224 return lua_toboolean(L
, -1);
1228 * Register a custom `:`-command.
1230 * @function command_register
1231 * @tparam string name the command name
1232 * @tparam function command the Lua function implementing the command
1233 * @tparam[opt] string help the single line help text as displayed in `:help`
1234 * @treturn bool whether the command has been successfully registered
1236 * vis:command_register("foo", function(argv, force, win, selection, range)
1237 * for i,arg in ipairs(argv) do
1238 * print(i..": "..arg)
1240 * print("was command forced with ! "..(force and "yes" or "no"))
1241 * print(win.file.name)
1242 * print(selection.pos)
1243 * print(range ~= nil and ('['..range.start..', '..range.finish..']') or "invalid range")
1247 static int command_register(lua_State
*L
) {
1248 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1249 const char *name
= luaL_checkstring(L
, 2);
1250 const void *func
= func_ref_new(L
, 3);
1251 const char *help
= luaL_optstring(L
, 4, "");
1252 bool ret
= vis_cmd_register(vis
, name
, help
, (void*)func
, command_lua
);
1253 lua_pushboolean(L
, ret
);
1258 * Push keys to input queue and interpret them.
1260 * The keys are processed as if they were read from the keyboard.
1262 * @function feedkeys
1263 * @tparam string keys the keys to interpret
1265 static int feedkeys(lua_State
*L
) {
1266 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1267 const char *keys
= luaL_checkstring(L
, 2);
1268 vis_keys_feed(vis
, keys
);
1273 * Insert keys at all cursor positions of active window.
1275 * This function behaves as if the keys were entered in insert mode,
1276 * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
1277 * meaning mappings do not apply and the keys will not be recorded in macros.
1280 * @tparam string keys the keys to insert
1283 static int insert(lua_State
*L
) {
1284 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1286 const char *keys
= luaL_checklstring(L
, 2, &len
);
1287 vis_insert_key(vis
, keys
, len
);
1292 * Replace keys at all cursor positions of active window.
1294 * This function behaves as if the keys were entered in replace mode,
1295 * but in contrast to @{Vis:feedkeys} it bypasses the input queue,
1296 * meaning mappings do not apply and the keys will not be recorded in macros.
1299 * @tparam string keys the keys to insert
1302 static int replace(lua_State
*L
) {
1303 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1305 const char *keys
= luaL_checklstring(L
, 2, &len
);
1306 vis_replace_key(vis
, keys
, len
);
1311 * Terminate editor process.
1313 * Termination happens upon the next iteration of the main event loop.
1314 * This means the calling Lua code will be executed further until it
1315 * eventually hands over control to the editor core. The exit status
1316 * of the most recent call is used.
1318 * All unsaved changes will be lost!
1321 * @tparam int code the exit status returned to the operating system
1323 static int exit_func(lua_State
*L
) {
1324 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1325 int code
= luaL_checkint(L
, 2);
1326 vis_exit(vis
, code
);
1331 * Pipe file range to external process and collect output.
1333 * The editor core will be blocked while the external process is running.
1334 * File and Range can be omitted or nil to indicate empty input.
1337 * @tparam[opt] File file the file to which the range applies
1338 * @tparam[opt] Range range the range to pipe
1339 * @tparam string command the command to execute
1340 * @tparam[opt] bool fullscreen whether command is a fullscreen program (e.g. curses based)
1341 * @treturn int code the exit status of the executed command
1342 * @treturn string stdout the data written to stdout
1343 * @treturn string stderr the data written to stderr
1345 static int pipe_func(lua_State
*L
) {
1346 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1348 char *out
= NULL
, *err
= NULL
;
1349 File
*file
= vis
->win
? vis
->win
->file
: NULL
;
1350 Filerange range
= text_range_new(0, 0);
1351 if (lua_gettop(L
) <= 3) {
1353 } else if (!(lua_isnil(L
, 2) && lua_isnil(L
, 3))) {
1354 file
= obj_ref_check(L
, 2, VIS_LUA_TYPE_FILE
);
1355 range
= getrange(L
, 3);
1357 const char *cmd
= luaL_checkstring(L
, cmd_idx
);
1358 bool fullscreen
= lua_isboolean(L
, cmd_idx
+ 1) && lua_toboolean(L
, cmd_idx
+ 1);
1361 return luaL_error(L
, "vis:pipe(cmd = '%s'): win not open, file can't be nil", cmd
);
1363 int status
= vis_pipe_collect(vis
, file
, &range
, (const char*[]){ cmd
, NULL
}, &out
, &err
, fullscreen
);
1364 lua_pushinteger(L
, status
);
1366 lua_pushstring(L
, out
);
1371 lua_pushstring(L
, err
);
1380 * Redraw complete user interface.
1382 * Will trigger redraw events, make sure to avoid recursive events.
1386 static int redraw(lua_State
*L
) {
1387 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1392 * Closes a stream returned by @{Vis:communicate}.
1395 * @tparam io.file inputfd the stream to be closed
1396 * @treturn bool identical to @{io.close}
1398 static int close_subprocess(lua_State
*L
) {
1399 luaL_Stream
*file
= luaL_checkudata(L
, -1, "FILE*");
1400 int result
= fclose(file
->f
);
1403 file
->closef
= NULL
;
1405 return luaL_fileresult(L
, result
== 0, NULL
);
1408 * Open new process and return its input stream (stdin).
1409 * If the stream is closed (by calling the close method or by being removed by a garbage collector)
1410 * the spawned process will be killed by SIGTERM.
1411 * When the process will quit or will output anything to stdout or stderr,
1412 * the @{process_response} event will be fired.
1414 * The editor core won't be blocked while the external process is running.
1416 * @function communicate
1417 * @tparam string name the name of subprocess (to distinguish processes in the @{process_response} event)
1418 * @tparam string command the command to execute
1419 * @return the file handle to write data to the process, in case of error the return values are equivalent to @{io.open} error values.
1421 static int communicate_func(lua_State
*L
) {
1424 /* Lua stream structure for the process input stream */
1429 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1430 const char *name
= luaL_checkstring(L
, 2);
1431 const char *cmd
= luaL_checkstring(L
, 3);
1432 ProcessStream
*inputfd
= (ProcessStream
*)lua_newuserdata(L
, sizeof(ProcessStream
));
1433 luaL_setmetatable(L
, LUA_FILEHANDLE
);
1434 inputfd
->handler
= vis_process_communicate(vis
, name
, cmd
, &(inputfd
->stream
.closef
));
1435 if (inputfd
->handler
) {
1436 inputfd
->stream
.f
= fdopen(inputfd
->handler
->inpfd
, "w");
1437 inputfd
->stream
.closef
= &close_subprocess
;
1439 return inputfd
->stream
.f
? 1 : luaL_fileresult(L
, 0, name
);
1442 * Currently active window.
1443 * @tfield Window win
1447 * Currently active mode.
1448 * @tfield modes mode
1451 * Whether a macro is being recorded.
1452 * @tfield bool recording
1455 * Currently unconsumed keys in the input queue.
1456 * @tfield string input_queue
1459 * Register name in use.
1460 * @tfield string register
1464 * @tfield string mark
1466 static int vis_index(lua_State
*L
) {
1467 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1469 if (lua_isstring(L
, 2)) {
1470 const char *key
= lua_tostring(L
, 2);
1471 if (strcmp(key
, "win") == 0) {
1473 obj_ref_new(L
, vis
->win
, VIS_LUA_TYPE_WINDOW
);
1479 if (strcmp(key
, "mode") == 0) {
1480 lua_pushunsigned(L
, vis
->mode
->id
);
1484 if (strcmp(key
, "smartcase") == 0) {
1485 lua_pushboolean(L
, vis
->smartcase
);
1489 if (strcmp(key
, "literal") == 0) {
1490 lua_pushboolean(L
, vis
->literal
);
1494 if (strcmp(key
, "input_queue") == 0) {
1495 lua_pushstring(L
, buffer_content0(&vis
->input_queue
));
1499 if (strcmp(key
, "recording") == 0) {
1500 lua_pushboolean(L
, vis_macro_recording(vis
));
1504 if (strcmp(key
, "count") == 0) {
1505 int count
= vis_count_get(vis
);
1506 if (count
== VIS_COUNT_UNKNOWN
)
1509 lua_pushunsigned(L
, count
);
1513 if (strcmp(key
, "register") == 0) {
1514 char name
= vis_register_to(vis
, vis_register_used(vis
));
1515 lua_pushlstring(L
, &name
, 1);
1519 if (strcmp(key
, "registers") == 0) {
1520 obj_ref_new(L
, vis
->ui
, VIS_LUA_TYPE_REGISTERS
);
1524 if (strcmp(key
, "mark") == 0) {
1525 char name
= vis_mark_to(vis
, vis_mark_used(vis
));
1526 lua_pushlstring(L
, &name
, 1);
1530 if (strcmp(key
, "options") == 0) {
1531 obj_ref_new(L
, &vis
->options
, VIS_LUA_TYPE_VIS_OPTS
);
1535 if (strcmp(key
, "ui") == 0) {
1536 obj_ref_new(L
, vis
->ui
, VIS_LUA_TYPE_UI
);
1541 return index_common(L
);
1544 static int vis_options_assign(Vis
*vis
, lua_State
*L
, const char *key
, int next
) {
1545 if (strcmp(key
, "autoindent") == 0 || strcmp(key
, "ai") == 0) {
1546 vis
->autoindent
= lua_toboolean(L
, next
);
1547 } else if (strcmp(key
, "changecolors") == 0) {
1548 vis
->change_colors
= lua_toboolean(L
, next
);
1549 } else if (strcmp(key
, "escdelay") == 0) {
1550 TermKey
*tk
= vis
->ui
->termkey_get(vis
->ui
);
1551 termkey_set_waittime(tk
, luaL_checkint(L
, next
));
1552 } else if (strcmp(key
, "smartcase") == 0 || strcmp(key
, "scs") == 0) {
1553 vis
->smartcase
= lua_toboolean(L
, next
);
1554 } else if (strcmp(key
, "literal") == 0) {
1555 vis
->literal
= lua_toboolean(L
, next
);
1556 } else if (strcmp(key
, "loadmethod") == 0) {
1557 if (!lua_isstring(L
, next
))
1558 return newindex_common(L
);
1559 const char *lm
= lua_tostring(L
, next
);
1560 if (strcmp(lm
, "auto") == 0)
1561 vis
->load_method
= TEXT_LOAD_AUTO
;
1562 else if (strcmp(lm
, "read") == 0)
1563 vis
->load_method
= TEXT_LOAD_READ
;
1564 else if (strcmp(lm
, "mmap") == 0)
1565 vis
->load_method
= TEXT_LOAD_MMAP
;
1566 } else if (strcmp(key
, "shell") == 0) {
1567 if (!lua_isstring(L
, next
))
1568 return newindex_common(L
);
1569 vis_shell_set(vis
, lua_tostring(L
, next
));
1574 static int vis_newindex(lua_State
*L
) {
1575 Vis
*vis
= obj_ref_check(L
, 1, "vis");
1576 if (lua_isstring(L
, 2)) {
1577 const char *key
= lua_tostring(L
, 2);
1578 if (strcmp(key
, "mode") == 0) {
1579 enum VisMode mode
= luaL_checkunsigned(L
, 3);
1580 vis_mode_switch(vis
, mode
);
1584 if (strcmp(key
, "count") == 0) {
1586 if (lua_isnil(L
, 3))
1587 count
= VIS_COUNT_UNKNOWN
;
1589 count
= luaL_checkunsigned(L
, 3);
1590 vis_count_set(vis
, count
);
1594 if (strcmp(key
, "win") == 0) {
1595 vis_window_focus(obj_ref_check(L
, 3, VIS_LUA_TYPE_WINDOW
));
1599 if (strcmp(key
, "register") == 0) {
1600 const char *name
= luaL_checkstring(L
, 3);
1601 if (strlen(name
) == 1)
1602 vis_register(vis
, vis_register_from(vis
, name
[0]));
1606 if (strcmp(key
, "mark") == 0) {
1607 const char *name
= luaL_checkstring(L
, 3);
1608 if (strlen(name
) == 1)
1609 vis_mark(vis
, vis_mark_from(vis
, name
[0]));
1613 if (strcmp(key
, "options") == 0 && lua_istable(L
, 3)) {
1615 /* since we don't know which keys are in the table we push
1616 * a nil then use lua_next() to remove it and push the
1617 * table's key-value pairs to the stack. these can then be
1618 * used to assign options
1621 while (lua_next(L
, 3)) {
1622 if (lua_isstring(L
, 4))
1623 ret
+= vis_options_assign(vis
, L
, lua_tostring(L
, 4), 5);
1625 ret
+= newindex_common(L
);
1632 return newindex_common(L
);
1635 static const struct luaL_Reg vis_lua
[] = {
1637 { "windows", windows
},
1638 { "mark_names", mark_names
},
1639 { "register_names", register_names
},
1640 { "command", command
},
1642 { "message", message
},
1645 { "mappings", mappings
},
1646 { "operator", operator },
1647 { "operator_register", operator_register
},
1648 { "motion", motion
},
1649 { "motion_register", motion_register
},
1650 { "textobject", textobject
},
1651 { "textobject_register", textobject_register
},
1652 { "option_register", option_register
},
1653 { "option_unregister", option_unregister
},
1654 { "command_register", command_register
},
1655 { "feedkeys", feedkeys
},
1656 { "insert", insert
},
1657 { "replace", replace
},
1658 { "action_register", action_register
},
1659 { "exit", exit_func
},
1660 { "pipe", pipe_func
},
1661 { "redraw", redraw
},
1662 { "communicate", communicate_func
},
1663 { "__index", vis_index
},
1664 { "__newindex", vis_newindex
},
1671 * @tfield[opt=false] boolean autoindent {ai}
1672 * @tfield[opt=false] boolean changecolors
1673 * @tfield[opt=50] int escdelay
1674 * @tfield[opt=false] boolean smartcase {scs}
1675 * @tfield[opt=false] boolean literal
1676 * @tfield[opt="auto"] string loadmethod `"auto"`, `"read"`, or `"mmap"`.
1677 * @tfield[opt="/bin/sh"] string shell
1678 * @see Window.options
1681 static int vis_options_index(lua_State
*L
) {
1682 Vis
*vis
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_VIS_OPTS
, offsetof(Vis
, options
));
1685 if (lua_isstring(L
, 2)) {
1686 const char *key
= lua_tostring(L
, 2);
1687 if (strcmp(key
, "autoindent") == 0 || strcmp(key
, "ai") == 0) {
1688 lua_pushboolean(L
, vis
->autoindent
);
1690 } else if (strcmp(key
, "changecolors") == 0) {
1691 lua_pushboolean(L
, vis
->change_colors
);
1693 } else if (strcmp(key
, "escdelay") == 0) {
1694 TermKey
*tk
= vis
->ui
->termkey_get(vis
->ui
);
1695 lua_pushunsigned(L
, termkey_get_waittime(tk
));
1697 } else if (strcmp(key
, "smartcase") == 0 || strcmp(key
, "scs") == 0) {
1698 lua_pushboolean(L
, vis
->smartcase
);
1700 } else if (strcmp(key
, "literal") == 0) {
1701 lua_pushboolean(L
, vis
->literal
);
1703 } else if (strcmp(key
, "loadmethod") == 0) {
1704 switch (vis
->load_method
) {
1705 case TEXT_LOAD_AUTO
:
1706 lua_pushstring(L
, "auto");
1708 case TEXT_LOAD_READ
:
1709 lua_pushstring(L
, "read");
1711 case TEXT_LOAD_MMAP
:
1712 lua_pushstring(L
, "mmap");
1716 } else if (strcmp(key
, "shell") == 0) {
1717 lua_pushstring(L
, vis
->shell
);
1721 return index_common(L
);
1724 static int vis_options_newindex(lua_State
*L
) {
1725 Vis
*vis
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_VIS_OPTS
, offsetof(Vis
, options
));
1728 if (lua_isstring(L
, 2))
1729 return vis_options_assign(vis
, L
, lua_tostring(L
, 2), 3);
1730 return newindex_common(L
);
1733 static const struct luaL_Reg vis_option_funcs
[] = {
1734 { "__index", vis_options_index
},
1735 { "__newindex", vis_options_newindex
},
1740 * The user interface.
1745 * Number of available colors.
1746 * @tfield int colors
1750 * @tfield layouts layout current window layout.
1753 static int ui_index(lua_State
*L
) {
1754 Ui
*ui
= obj_ref_check(L
, 1, VIS_LUA_TYPE_UI
);
1756 if (lua_isstring(L
, 2)) {
1757 const char *key
= lua_tostring(L
, 2);
1759 if (strcmp(key
, "layout") == 0) {
1760 lua_pushunsigned(L
, ui_layout_get(ui
));
1765 return index_common(L
);
1768 static int ui_newindex(lua_State
*L
) {
1769 Ui
*ui
= obj_ref_check(L
, 1, VIS_LUA_TYPE_UI
);
1771 if (lua_isstring(L
, 2)) {
1772 const char *key
= lua_tostring(L
, 2);
1774 if (strcmp(key
, "layout") == 0) {
1775 ui
->arrange(ui
, luaL_checkint(L
, 3));
1779 return newindex_common(L
);
1782 static const struct luaL_Reg ui_funcs
[] = {
1783 { "__index", ui_index
},
1784 { "__newindex", ui_newindex
},
1788 static int registers_index(lua_State
*L
) {
1790 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
1791 const char *symbol
= luaL_checkstring(L
, 2);
1792 if (strlen(symbol
) != 1)
1794 enum VisRegister reg
= vis_register_from(vis
, symbol
[0]);
1795 if (reg
>= VIS_REG_INVALID
)
1797 Array data
= vis_register_get(vis
, reg
);
1798 for (size_t i
= 0, len
= array_length(&data
); i
< len
; i
++) {
1799 TextString
*string
= array_get(&data
, i
);
1800 lua_pushunsigned(L
, i
+1);
1801 lua_pushlstring(L
, string
->data
, string
->len
);
1802 lua_settable(L
, -3);
1804 array_release(&data
);
1808 static int registers_newindex(lua_State
*L
) {
1809 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
1810 const char *symbol
= luaL_checkstring(L
, 2);
1811 if (strlen(symbol
) != 1)
1813 enum VisRegister reg
= vis_register_from(vis
, symbol
[0]);
1815 array_init_sized(&data
, sizeof(TextString
));
1817 if (lua_istable(L
, 3)) {
1819 while (lua_next(L
, 3)) {
1821 string
.data
= luaL_checklstring(L
, -1, &string
.len
);
1822 array_add(&data
, &string
);
1827 vis_register_set(vis
, reg
, &data
);
1828 if (symbol
[0] == vis_registers
[VIS_REG_SEARCH
].name
) {
1829 Text
*txt
= vis
->search_file
->text
;
1830 size_t size
= text_size(txt
);
1831 size_t last_line
= text_lineno_by_pos(txt
, size
);
1833 if (last_line
> 1 && text_byte_get(txt
, size
-1, &lastchar
) && lastchar
== '\n')
1835 size_t start
= text_pos_by_lineno(txt
, last_line
);
1836 size_t end
= text_line_end(txt
, start
);
1837 if (start
!= EPOS
&& end
!= EPOS
) {
1838 size_t size
= end
- start
;
1839 char *last_search
= malloc(size
);
1840 if (last_search
&& size
) {
1841 size
= text_bytes_get(txt
, start
, size
, last_search
);
1842 if (0 == strncmp(last_search
+1, ((TextString
*)array_get(&data
, 0))->data
, size
-1)) {
1843 vis_regex(vis
, last_search
+1, vis
->smartcase
? 1 : 0);
1849 array_release(&data
);
1853 static int registers_len(lua_State
*L
) {
1854 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
1855 lua_pushunsigned(L
, LENGTH(vis
->registers
));
1859 static const struct luaL_Reg registers_funcs
[] = {
1860 { "__index", registers_index
},
1861 { "__newindex", registers_newindex
},
1862 { "__len", registers_len
},
1872 * Viewport currently being displayed.
1873 * Changing these values will not move the viewport.
1875 * @tfield Range bytes file bytes, from 0, at the start and end of the viewport
1876 * @tfield Range lines file lines, from 1, at the top and bottom of the viewport
1877 * @tfield int height lines in viewport, accounting for window decoration
1878 * @tfield int width columns in viewport, accounting for window decoration
1885 * The window height.
1886 * @tfield int height
1889 * The file being displayed in this window.
1893 * The primary selection of this window.
1894 * @tfield Selection selection
1897 * The selections of this window.
1898 * @tfield Array(Selection) selections
1902 * Most of these marks are stored in the associated File object, meaning they
1903 * are the same in all windows displaying the same file.
1904 * @field marks array to access the marks of this window by single letter name
1905 * @see Vis:mark_names
1907 static int window_index(lua_State
*L
) {
1908 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
1910 if (lua_isstring(L
, 2)) {
1911 const char *key
= lua_tostring(L
, 2);
1913 if (strcmp(key
, "viewport") == 0) {
1914 Filerange b
= view_viewport_get(win
->view
);
1916 l
.start
= view_lines_first(win
->view
)->lineno
;
1917 l
.end
= view_lines_last(win
->view
)->lineno
;
1919 lua_createtable(L
, 0, 4);
1920 lua_pushstring(L
, "bytes");
1922 lua_settable(L
, -3);
1923 lua_pushstring(L
, "lines");
1925 lua_settable(L
, -3);
1926 lua_pushstring(L
, "width");
1927 lua_pushunsigned(L
, view_width_get(win
->view
));
1928 lua_settable(L
, -3);
1929 lua_pushstring(L
, "height");
1930 lua_pushunsigned(L
, view_height_get(win
->view
));
1931 lua_settable(L
, -3);
1935 if (strcmp(key
, "width") == 0) {
1936 lua_pushunsigned(L
, vis_window_width_get(win
));
1940 if (strcmp(key
, "height") == 0) {
1941 lua_pushunsigned(L
, vis_window_height_get(win
));
1945 if (strcmp(key
, "file") == 0) {
1946 obj_ref_new(L
, win
->file
, VIS_LUA_TYPE_FILE
);
1950 if (strcmp(key
, "selection") == 0) {
1951 Selection
*sel
= view_selections_primary_get(win
->view
);
1952 obj_lightref_new(L
, sel
, VIS_LUA_TYPE_SELECTION
);
1956 if (strcmp(key
, "selections") == 0) {
1957 obj_ref_new(L
, win
->view
, VIS_LUA_TYPE_SELECTIONS
);
1961 if (strcmp(key
, "marks") == 0) {
1962 obj_ref_new(L
, &win
->saved_selections
, VIS_LUA_TYPE_MARKS
);
1965 if (strcmp(key
, "options") == 0) {
1966 obj_ref_new(L
, &win
->view
, VIS_LUA_TYPE_WIN_OPTS
);
1971 return index_common(L
);
1974 static int window_options_assign(Win
*win
, lua_State
*L
, const char *key
, int next
) {
1975 enum UiOption flags
= view_options_get(win
->view
);
1976 if (strcmp(key
, "breakat") == 0 || strcmp(key
, "brk") == 0) {
1977 if (lua_isstring(L
, next
))
1978 view_breakat_set(win
->view
, lua_tostring(L
, next
));
1979 } else if (strcmp(key
, "colorcolumn") == 0 || strcmp(key
, "cc") == 0) {
1980 view_colorcolumn_set(win
->view
, luaL_checkint(L
, next
));
1981 } else if (strcmp(key
, "cursorline") == 0 || strcmp(key
, "cul") == 0) {
1982 if (lua_toboolean(L
, next
))
1983 flags
|= UI_OPTION_CURSOR_LINE
;
1985 flags
&= ~UI_OPTION_CURSOR_LINE
;
1986 view_options_set(win
->view
, flags
);
1987 } else if (strcmp(key
, "numbers") == 0 || strcmp(key
, "nu") == 0) {
1988 if (lua_toboolean(L
, next
))
1989 flags
|= UI_OPTION_LINE_NUMBERS_ABSOLUTE
;
1991 flags
&= ~UI_OPTION_LINE_NUMBERS_ABSOLUTE
;
1992 view_options_set(win
->view
, flags
);
1993 } else if (strcmp(key
, "relativenumbers") == 0 || strcmp(key
, "rnu") == 0) {
1994 if (lua_toboolean(L
, next
))
1995 flags
|= UI_OPTION_LINE_NUMBERS_RELATIVE
;
1997 flags
&= ~UI_OPTION_LINE_NUMBERS_RELATIVE
;
1998 view_options_set(win
->view
, flags
);
1999 } else if (strcmp(key
, "showeof") == 0) {
2000 if (lua_toboolean(L
, next
))
2001 flags
|= UI_OPTION_SYMBOL_EOF
;
2003 flags
&= ~UI_OPTION_SYMBOL_EOF
;
2004 view_options_set(win
->view
, flags
);
2005 } else if (strcmp(key
, "shownewlines") == 0) {
2006 if (lua_toboolean(L
, next
))
2007 flags
|= UI_OPTION_SYMBOL_EOL
;
2009 flags
&= ~UI_OPTION_SYMBOL_EOL
;
2010 view_options_set(win
->view
, flags
);
2011 } else if (strcmp(key
, "showspaces") == 0) {
2012 if (lua_toboolean(L
, next
))
2013 flags
|= UI_OPTION_SYMBOL_SPACE
;
2015 flags
&= ~UI_OPTION_SYMBOL_SPACE
;
2016 view_options_set(win
->view
, flags
);
2017 } else if (strcmp(key
, "showtabs") == 0) {
2018 if (lua_toboolean(L
, next
))
2019 flags
|= UI_OPTION_SYMBOL_TAB
;
2021 flags
&= ~UI_OPTION_SYMBOL_TAB
;
2022 view_options_set(win
->view
, flags
);
2023 } else if (strcmp(key
, "statusbar") == 0) {
2024 if (lua_toboolean(L
, next
))
2025 flags
|= UI_OPTION_STATUSBAR
;
2027 flags
&= ~UI_OPTION_STATUSBAR
;
2028 view_options_set(win
->view
, flags
);
2029 } else if (strcmp(key
, "wrapcolumn") == 0 || strcmp(key
, "wc") == 0) {
2030 view_wrapcolumn_set(win
->view
, luaL_checkint(L
, next
));
2031 } else if (strcmp(key
, "tabwidth") == 0 || strcmp(key
, "tw") == 0) {
2032 view_tabwidth_set(win
->view
, luaL_checkint(L
, next
));
2033 } else if (strcmp(key
, "expandtab") == 0 || strcmp(key
, "et") == 0) {
2034 win
->expandtab
= lua_toboolean(L
, next
);
2039 static int window_newindex(lua_State
*L
) {
2040 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2042 if (lua_isstring(L
, 2)) {
2043 const char *key
= lua_tostring(L
, 2);
2044 if (strcmp(key
, "options") == 0 && lua_istable(L
, 3)) {
2046 /* since we don't know which keys are in the table we push
2047 * a nil then use lua_next() to remove it and push the
2048 * table's key-value pairs to the stack. these can then be
2049 * used to assign options
2052 while (lua_next(L
, 3)) {
2053 if (lua_isstring(L
, 4))
2054 ret
+= window_options_assign(win
, L
, lua_tostring(L
, 4), 5);
2056 ret
+= newindex_common(L
);
2064 return newindex_common(L
);
2067 static int window_selections_iterator_next(lua_State
*L
) {
2068 Selection
**handle
= lua_touserdata(L
, lua_upvalueindex(1));
2071 Selection
*sel
= obj_lightref_new(L
, *handle
, VIS_LUA_TYPE_SELECTION
);
2074 *handle
= view_selections_next(sel
);
2079 * Create an iterator over all selections of this window.
2080 * @function selections_iterator
2081 * @return the new iterator
2083 static int window_selections_iterator(lua_State
*L
) {
2084 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2085 Selection
**handle
= lua_newuserdata(L
, sizeof *handle
);
2086 *handle
= view_selections(win
->view
);
2087 lua_pushcclosure(L
, window_selections_iterator_next
, 1);
2092 * Set up a window local key mapping.
2093 * The function signatures are the same as for @{Vis:map}.
2098 static int window_map(lua_State
*L
) {
2099 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2100 return keymap(L
, win
->vis
, win
);
2104 * Remove a window local key mapping.
2105 * The function signature is the same as for @{Vis:unmap}.
2110 static int window_unmap(lua_State
*L
) {
2111 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2112 return keyunmap(L
, win
->vis
, win
);
2116 * Define a display style.
2117 * @function style_define
2118 * @tparam int id the style id to use
2119 * @tparam string style the style definition
2120 * @treturn bool whether the style definition has been successfully
2121 * associated with the given id
2124 * win:style_define(win.STYLE_DEFAULT, "fore:red")
2126 static int window_style_define(lua_State
*L
) {
2127 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2128 enum UiStyle id
= luaL_checkunsigned(L
, 2);
2129 const char *style
= luaL_checkstring(L
, 3);
2130 bool ret
= view_style_define(win
->view
, id
, style
);
2131 lua_pushboolean(L
, ret
);
2136 * Style a window range.
2138 * The style will be cleared after every window redraw.
2140 * @tparam int id the display style as registered with @{style_define}
2141 * @tparam int start the absolute file position in bytes
2142 * @tparam int finish the end position
2145 * win:style(win.STYLE_DEFAULT, 0, 10)
2147 static int window_style(lua_State
*L
) {
2148 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2149 enum UiStyle style
= luaL_checkunsigned(L
, 2);
2150 size_t start
= checkpos(L
, 3);
2151 size_t end
= checkpos(L
, 4);
2152 view_style(win
->view
, style
, start
, end
);
2157 * Style the single terminal cell at the given coordinates, relative to this window.
2159 * Completely independent of the file buffer, and can be used to style UI elements,
2160 * such as the status bar.
2161 * The style will be cleared after every window redraw.
2162 * @function style_pos
2163 * @tparam int id display style registered with @{style_define}
2164 * @tparam int x 0-based x coordinate within Win, where (0,0) is the top left corner
2165 * @tparam int y See above
2166 * @treturn bool false if the coordinates would be outside the window's dimensions
2169 * win:style_pos(win.STYLE_COLOR_COLUMN, 0, win.height - 1)
2170 * -- Styles the first character of the status bar (or the last line, if disabled)
2172 static int window_style_pos(lua_State
*L
) {
2173 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2174 enum UiStyle style
= luaL_checkunsigned(L
, 2);
2175 size_t x
= checkpos(L
, 3);
2176 size_t y
= checkpos(L
, 4);
2177 bool ret
= win
->ui
->style_set_pos(win
->ui
, (int)x
, (int)y
, style
);
2178 lua_pushboolean(L
, ret
);
2183 * Set window status line.
2186 * @tparam string left the left aligned part of the status line
2187 * @tparam[opt] string right the right aligned part of the status line
2189 static int window_status(lua_State
*L
) {
2190 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2191 char status
[1024] = "";
2192 int width
= vis_window_width_get(win
);
2193 const char *left
= luaL_checkstring(L
, 2);
2194 const char *right
= luaL_optstring(L
, 3, "");
2195 int left_width
= text_string_width(left
, strlen(left
));
2196 int right_width
= text_string_width(right
, strlen(right
));
2197 int spaces
= width
- left_width
- right_width
;
2200 snprintf(status
, sizeof(status
)-1, "%s%*s%s", left
, spaces
, " ", right
);
2201 vis_window_status(win
, status
);
2206 * Redraw window content.
2210 static int window_draw(lua_State
*L
) {
2211 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2212 view_draw(win
->view
);
2219 * After a successful call the Window reference becomes invalid and
2220 * must no longer be used. Attempting to close the last window will
2225 * @tparam bool force whether unsaved changes should be discarded
2226 * @treturn bool whether the window was closed
2228 static int window_close(lua_State
*L
) {
2229 Win
*win
= obj_ref_check(L
, 1, VIS_LUA_TYPE_WINDOW
);
2231 for (Win
*w
= win
->vis
->windows
; w
; w
= w
->next
) {
2232 if (!w
->file
->internal
)
2235 bool force
= lua_isboolean(L
, 2) && lua_toboolean(L
, 2);
2236 bool close
= count
> 1 && (force
|| vis_window_closable(win
));
2238 vis_window_close(win
);
2239 lua_pushboolean(L
, close
);
2243 static const struct luaL_Reg window_funcs
[] = {
2244 { "__index", window_index
},
2245 { "__newindex", window_newindex
},
2246 { "selections_iterator", window_selections_iterator
},
2247 { "map", window_map
},
2248 { "unmap", window_unmap
},
2249 { "style_define", window_style_define
},
2250 { "style", window_style
},
2251 { "style_pos", window_style_pos
},
2252 { "status", window_status
},
2253 { "draw", window_draw
},
2254 { "close", window_close
},
2261 * @tfield[opt=""] string breakat {brk}
2262 * @tfield[opt=0] int colorcolumn {cc}
2263 * @tfield[opt=false] boolean cursorline {cul}
2264 * @tfield[opt=false] boolean expandtab {et}
2265 * @tfield[opt=false] boolean numbers {nu}
2266 * @tfield[opt=false] boolean relativenumbers {rnu}
2267 * @tfield[opt=true] boolean showeof
2268 * @tfield[opt=false] boolean shownewlines
2269 * @tfield[opt=false] boolean showspaces
2270 * @tfield[opt=false] boolean showtabs
2271 * @tfield[opt=true] boolean statusbar
2272 * @tfield[opt=8] int tabwidth {tw}
2273 * @tfield[opt=0] int wrapcolumn {wc}
2277 static int window_options_index(lua_State
*L
) {
2278 Win
*win
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_WIN_OPTS
, offsetof(Win
, view
));
2281 if (lua_isstring(L
, 2)) {
2282 const char *key
= lua_tostring(L
, 2);
2283 if (strcmp(key
, "breakat") == 0 || strcmp(key
, "brk") == 0) {
2284 lua_pushstring(L
, view_breakat_get(win
->view
));
2286 } else if (strcmp(key
, "colorcolumn") == 0 || strcmp(key
, "cc") == 0) {
2287 lua_pushunsigned(L
, view_colorcolumn_get(win
->view
));
2289 } else if (strcmp(key
, "cursorline") == 0 || strcmp(key
, "cul") == 0) {
2290 lua_pushboolean(L
, view_options_get(win
->view
) & UI_OPTION_CURSOR_LINE
);
2292 } else if (strcmp(key
, "expandtab") == 0 || strcmp(key
, "et") == 0) {
2293 lua_pushboolean(L
, win
->expandtab
);
2295 } else if (strcmp(key
, "numbers") == 0 || strcmp(key
, "nu") == 0) {
2296 lua_pushboolean(L
, view_options_get(win
->view
) & UI_OPTION_LINE_NUMBERS_ABSOLUTE
);
2298 } else if (strcmp(key
, "relativenumbers") == 0 || strcmp(key
, "rnu") == 0) {
2299 lua_pushboolean(L
, view_options_get(win
->view
) & UI_OPTION_LINE_NUMBERS_RELATIVE
);
2301 } else if (strcmp(key
, "showeof") == 0) {
2302 lua_pushboolean(L
, view_options_get(win
->view
) & UI_OPTION_SYMBOL_EOF
);
2304 } else if (strcmp(key
, "shownewlines") == 0) {
2305 lua_pushboolean(L
, view_options_get(win
->view
) & UI_OPTION_SYMBOL_EOL
);
2307 } else if (strcmp(key
, "showspaces") == 0) {
2308 lua_pushboolean(L
, view_options_get(win
->view
) & UI_OPTION_SYMBOL_SPACE
);
2310 } else if (strcmp(key
, "showtabs") == 0) {
2311 lua_pushboolean(L
, view_options_get(win
->view
) & UI_OPTION_SYMBOL_TAB
);
2313 } else if (strcmp(key
, "statusbar") == 0) {
2314 lua_pushboolean(L
, view_options_get(win
->view
) & UI_OPTION_STATUSBAR
);
2316 } else if (strcmp(key
, "tabwidth") == 0 || strcmp(key
, "tw") == 0) {
2317 lua_pushinteger(L
, view_tabwidth_get(win
->view
));
2319 } else if (strcmp(key
, "wrapcolumn") == 0 || strcmp(key
, "wc") == 0) {
2320 lua_pushunsigned(L
, view_wrapcolumn_get(win
->view
));
2324 return index_common(L
);
2327 static int window_options_newindex(lua_State
*L
) {
2328 Win
*win
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_WIN_OPTS
, offsetof(Win
, view
));
2331 if (lua_isstring(L
, 2))
2332 return window_options_assign(win
, L
, lua_tostring(L
, 2), 3);
2333 return newindex_common(L
);
2336 static const struct luaL_Reg window_option_funcs
[] = {
2337 { "__index", window_options_index
},
2338 { "__newindex", window_options_newindex
},
2342 static int window_selections_index(lua_State
*L
) {
2343 View
*view
= obj_ref_check(L
, 1, VIS_LUA_TYPE_SELECTIONS
);
2344 size_t index
= luaL_checkunsigned(L
, 2);
2345 size_t count
= view_selections_count(view
);
2346 if (index
== 0 || index
> count
)
2348 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
)) {
2350 obj_lightref_new(L
, s
, VIS_LUA_TYPE_SELECTION
);
2359 static int window_selections_len(lua_State
*L
) {
2360 View
*view
= obj_ref_check(L
, 1, VIS_LUA_TYPE_SELECTIONS
);
2361 lua_pushunsigned(L
, view_selections_count(view
));
2365 static const struct luaL_Reg window_selections_funcs
[] = {
2366 { "__index", window_selections_index
},
2367 { "__len", window_selections_len
},
2372 * A selection object.
2374 * A selection is a non-empty, directed range with two endpoints called
2375 * *cursor* and *anchor*. A selection can be anchored in which case
2376 * the anchor remains fixed while only the position of the cursor is
2377 * adjusted. For non-anchored selections both endpoints are updated. A
2378 * singleton selection covers one character on which both cursor and
2379 * anchor reside. There always exists a primary selection which remains
2380 * visible (i.e. changes to its position will adjust the viewport).
2382 * The range covered by a selection is represented as an interval whose
2383 * endpoints are absolute byte offsets from the start of the file.
2384 * Valid addresses are within the closed interval `[0, file.size]`.
2386 * Selections are currently implemented using character marks into
2387 * the underlying persistent
2388 * [text management data structure](https://github.com/martanne/vis/wiki/Text-management-using-a-piece-chain).
2390 * This has a few consequences you should be aware of:
2392 * - A selection becomes invalid when the delimiting boundaries of the underlying
2393 * text it is referencing is deleted:
2395 * -- leaves selection in an invalid state
2396 * win.file:delete(win.selection.pos, 1)
2397 * assert(win.selection.pos == nil)
2399 * Like a regular mark it will become valid again when the text is reverted
2400 * to the state before the deletion.
2402 * - Inserts after the selection position (`> selection.pos`) will not affect the
2403 * selection position.
2405 * local pos = win.selection.pos
2406 * win.file:insert(pos+1, "-")
2407 * assert(win.selection.pos == pos)
2409 * - Non-cached inserts before the selection position (`<= selection.pos`) will
2410 * affect the mark and adjust the selection position by the number of bytes
2411 * which were inserted.
2413 * local pos = win.selection.pos
2414 * win.file:insert(pos, "-")
2415 * assert(win.selection.pos == pos+1)
2417 * - Cached inserts before the selection position (`<= selection.pos`) will
2418 * not affect the selection position because the underlying text is replaced
2421 * For these reasons it is generally recommended to update the selection position
2422 * after a modification. The general procedure amounts to:
2424 * 1. Read out the current selection position
2425 * 2. Perform text modifications
2426 * 3. Update the selection position
2428 * This is what @{Vis:insert} and @{Vis:replace} do internally.
2432 * local data = "new text"
2433 * local pos = win.selection.pos
2434 * win.file:insert(pos, data)
2435 * win.selection.pos = pos + #data
2439 * The zero based byte position in the file.
2441 * Might be `nil` if the selection is in an invalid state.
2442 * Setting this field will move the cursor endpoint of the
2443 * selection to the given position.
2447 * The 1-based line the cursor of this selection resides on.
2453 * The 1-based column position the cursor of this selection resides on.
2458 * The 1-based selection index.
2459 * @tfield int number
2462 * The range covered by this selection.
2463 * @tfield Range range
2466 * Whether this selection is anchored.
2467 * @tfield bool anchored
2469 static int window_selection_index(lua_State
*L
) {
2470 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_SELECTION
);
2476 if (lua_isstring(L
, 2)) {
2477 const char *key
= lua_tostring(L
, 2);
2478 if (strcmp(key
, "pos") == 0) {
2479 pushpos(L
, view_cursors_pos(sel
));
2483 if (strcmp(key
, "line") == 0) {
2484 lua_pushunsigned(L
, view_cursors_line(sel
));
2488 if (strcmp(key
, "col") == 0) {
2489 lua_pushunsigned(L
, view_cursors_col(sel
));
2493 if (strcmp(key
, "number") == 0) {
2494 lua_pushunsigned(L
, view_selections_number(sel
)+1);
2498 if (strcmp(key
, "range") == 0) {
2499 Filerange range
= view_selections_get(sel
);
2500 pushrange(L
, &range
);
2504 if (strcmp(key
, "anchored") == 0) {
2505 lua_pushboolean(L
, view_selections_anchored(sel
));
2511 return index_common(L
);
2514 static int window_selection_newindex(lua_State
*L
) {
2515 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_SELECTION
);
2518 if (lua_isstring(L
, 2)) {
2519 const char *key
= lua_tostring(L
, 2);
2520 if (strcmp(key
, "pos") == 0) {
2521 size_t pos
= checkpos(L
, 3);
2522 view_cursors_to(sel
, pos
);
2526 if (strcmp(key
, "range") == 0) {
2527 Filerange range
= getrange(L
, 3);
2528 if (text_range_valid(&range
)) {
2529 view_selections_set(sel
, &range
);
2530 view_selections_anchor(sel
, true);
2532 view_selection_clear(sel
);
2537 if (strcmp(key
, "anchored") == 0) {
2538 view_selections_anchor(sel
, lua_toboolean(L
, 3));
2542 return newindex_common(L
);
2546 * Move cursor of selection.
2548 * @tparam int line the 1-based line number
2549 * @tparam int col the 1-based column number
2551 static int window_selection_to(lua_State
*L
) {
2552 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_SELECTION
);
2554 size_t line
= checkpos(L
, 2);
2555 size_t col
= checkpos(L
, 3);
2556 view_cursors_place(sel
, line
, col
);
2565 static int window_selection_remove(lua_State
*L
) {
2566 Selection
*sel
= obj_lightref_check(L
, 1, VIS_LUA_TYPE_SELECTION
);
2568 view_selections_dispose(sel
);
2573 static const struct luaL_Reg window_selection_funcs
[] = {
2574 { "__index", window_selection_index
},
2575 { "__newindex", window_selection_newindex
},
2576 { "to", window_selection_to
},
2577 { "remove", window_selection_remove
},
2587 * @tfield string name the file name relative to current working directory or `nil` if not yet named
2591 * @tfield string path the absolute file path or `nil` if not yet named
2594 * File content by logical lines.
2596 * Assigning to array element `0` (`#lines+1`) will insert a new line at
2597 * the beginning (end) of the file.
2598 * @tfield Array(string) lines the file content accessible as 1-based array
2601 * local lines = vis.win.file.lines
2602 * for i=1, #lines do
2603 * lines[i] = i .. ": " .. lines[i]
2608 * @tfield[opt="auto"] string savemethod `"auto"`, `"atomic"`, or `"inplace"`.
2611 * File size in bytes.
2612 * @tfield int size the current file size in bytes
2616 * @tfield bool modified whether the file contains unsaved changes
2620 * @tfield int permission the file permission bits as of the most recent load/save
2622 static int file_index(lua_State
*L
) {
2623 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2625 if (lua_isstring(L
, 2)) {
2626 const char *key
= lua_tostring(L
, 2);
2627 if (strcmp(key
, "name") == 0) {
2628 lua_pushstring(L
, file_name_get(file
));
2632 if (strcmp(key
, "path") == 0) {
2633 lua_pushstring(L
, file
->name
);
2637 if (strcmp(key
, "lines") == 0) {
2638 obj_ref_new(L
, file
->text
, VIS_LUA_TYPE_TEXT
);
2642 if (strcmp(key
, "size") == 0) {
2643 lua_pushunsigned(L
, text_size(file
->text
));
2647 if (strcmp(key
, "modified") == 0) {
2648 lua_pushboolean(L
, text_modified(file
->text
));
2652 if (strcmp(key
, "permission") == 0) {
2653 struct stat stat
= text_stat(file
->text
);
2654 lua_pushunsigned(L
, stat
.st_mode
& 0777);
2658 if (strcmp(key
, "savemethod") == 0) {
2659 switch (file
->save_method
) {
2660 case TEXT_SAVE_AUTO
:
2661 lua_pushstring(L
, "auto");
2663 case TEXT_SAVE_ATOMIC
:
2664 lua_pushstring(L
, "atomic");
2666 case TEXT_SAVE_INPLACE
:
2667 lua_pushstring(L
, "inplace");
2674 return index_common(L
);
2677 static int file_newindex(lua_State
*L
) {
2678 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2680 if (lua_isstring(L
, 2)) {
2681 const char *key
= lua_tostring(L
, 2);
2683 if (strcmp(key
, "modified") == 0) {
2684 bool modified
= lua_isboolean(L
, 3) && lua_toboolean(L
, 3);
2686 text_insert(file
->text
, 0, " ", 1);
2687 text_delete(file
->text
, 0, 1);
2689 text_save(file
->text
, NULL
);
2694 if (strcmp(key
, "savemethod") == 0) {
2695 if (!lua_isstring(L
, 3))
2696 return newindex_common(L
);
2697 const char *sm
= lua_tostring(L
, 3);
2698 if (strcmp(sm
, "auto") == 0)
2699 file
->save_method
= TEXT_SAVE_AUTO
;
2700 else if (strcmp(sm
, "atomic") == 0)
2701 file
->save_method
= TEXT_SAVE_ATOMIC
;
2702 else if (strcmp(sm
, "inplace") == 0)
2703 file
->save_method
= TEXT_SAVE_INPLACE
;
2708 return newindex_common(L
);
2712 * Insert data at position.
2714 * @tparam int pos the 0-based file position in bytes
2715 * @tparam string data the data to insert
2716 * @treturn bool whether the file content was successfully changed
2718 static int file_insert(lua_State
*L
) {
2719 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2720 size_t pos
= checkpos(L
, 2);
2722 luaL_checkstring(L
, 3);
2723 const char *data
= lua_tolstring(L
, 3, &len
);
2724 lua_pushboolean(L
, text_insert(file
->text
, pos
, data
, len
));
2729 * Delete data at position.
2732 * @tparam int pos the 0-based file position in bytes
2733 * @tparam int len the length in bytes to delete
2734 * @treturn bool whether the file content was successfully changed
2737 * Delete file range.
2740 * @tparam Range range the range to delete
2741 * @treturn bool whether the file content was successfully changed
2743 static int file_delete(lua_State
*L
) {
2744 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2745 Filerange range
= getrange(L
, 2);
2746 lua_pushboolean(L
, text_delete_range(file
->text
, &range
));
2751 * Create an iterator over all lines of the file.
2753 * For large files this is probably faster than @{lines}.
2754 * @function lines_iterator
2755 * @return the new iterator
2758 * for line in file:lines_iterator() do
2759 * -- do something with line
2762 static int file_lines_iterator_it(lua_State
*L
);
2763 static int file_lines_iterator(lua_State
*L
) {
2764 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2765 size_t line
= luaL_optunsigned(L
, 2, 1);
2766 size_t *pos
= lua_newuserdata(L
, sizeof *pos
);
2767 *pos
= text_pos_by_lineno(file
->text
, line
);
2768 lua_pushcclosure(L
, file_lines_iterator_it
, 2);
2772 static int file_lines_iterator_it(lua_State
*L
) {
2773 File
*file
= *(File
**)lua_touserdata(L
, lua_upvalueindex(1));
2774 size_t *start
= lua_touserdata(L
, lua_upvalueindex(2));
2775 if (*start
== text_size(file
->text
))
2777 size_t end
= text_line_end(file
->text
, *start
);
2778 size_t len
= end
- *start
;
2779 char *buf
= lua_newuserdata(L
, len
);
2782 len
= text_bytes_get(file
->text
, *start
, len
, buf
);
2783 lua_pushlstring(L
, buf
, len
);
2784 *start
= text_line_next(file
->text
, end
);
2789 * Get file content of position and length.
2792 * @tparam int pos the 0-based file position in bytes
2793 * @tparam int len the length in bytes to read
2794 * @treturn string the file content corresponding to the range
2797 * local file = vis.win.file
2798 * local text = file:content(0, file.size)
2801 * Get file content of range.
2804 * @tparam Range range the range to read
2805 * @treturn string the file content corresponding to the range
2807 static int file_content(lua_State
*L
) {
2808 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2809 Filerange range
= getrange(L
, 2);
2810 if (!text_range_valid(&range
))
2812 size_t len
= text_range_size(&range
);
2813 char *data
= lua_newuserdata(L
, len
);
2816 len
= text_bytes_get(file
->text
, range
.start
, len
, data
);
2817 lua_pushlstring(L
, data
, len
);
2826 * @function mark_set
2827 * @tparam int pos the position to set the mark to, must be in [0, file.size]
2828 * @treturn Mark mark the mark which can be looked up later
2830 static int file_mark_set(lua_State
*L
) {
2831 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2832 size_t pos
= checkpos(L
, 2);
2833 Mark mark
= text_mark_set(file
->text
, pos
);
2835 obj_lightref_new(L
, (void*)mark
, VIS_LUA_TYPE_MARK
);
2842 * Get position of mark.
2843 * @function mark_get
2844 * @tparam Mark mark the mark to look up
2845 * @treturn int pos the position of the mark, or `nil` if invalid
2847 static int file_mark_get(lua_State
*L
) {
2848 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2849 Mark mark
= (Mark
)obj_lightref_check(L
, 2, VIS_LUA_TYPE_MARK
);
2850 size_t pos
= text_mark_get(file
->text
, mark
);
2854 lua_pushunsigned(L
, pos
);
2861 * @function text_object_word
2862 * @tparam int pos the position which must be part of the word
2863 * @treturn Range range the range
2869 * @function text_object_longword
2870 * @tparam int pos the position which must be part of the word
2871 * @treturn Range range the range
2874 static int file_text_object(lua_State
*L
) {
2875 Filerange range
= text_range_empty();
2876 File
*file
= obj_ref_check(L
, 1, VIS_LUA_TYPE_FILE
);
2877 size_t pos
= checkpos(L
, 2);
2878 size_t idx
= lua_tointeger(L
, lua_upvalueindex(1));
2879 if (idx
< LENGTH(vis_textobjects
)) {
2880 const TextObject
*txtobj
= &vis_textobjects
[idx
];
2882 range
= txtobj
->txt(file
->text
, pos
);
2884 pushrange(L
, &range
);
2888 static const struct luaL_Reg file_funcs
[] = {
2889 { "__index", file_index
},
2890 { "__newindex", file_newindex
},
2891 { "insert", file_insert
},
2892 { "delete", file_delete
},
2893 { "lines_iterator", file_lines_iterator
},
2894 { "content", file_content
},
2895 { "mark_set", file_mark_set
},
2896 { "mark_get", file_mark_get
},
2900 static int file_lines_index(lua_State
*L
) {
2901 Text
*txt
= obj_ref_check(L
, 1, VIS_LUA_TYPE_TEXT
);
2902 size_t line
= luaL_checkunsigned(L
, 2);
2903 size_t start
= text_pos_by_lineno(txt
, line
);
2904 size_t end
= text_line_end(txt
, start
);
2905 if (start
!= EPOS
&& end
!= EPOS
) {
2906 size_t size
= end
- start
;
2907 char *data
= lua_newuserdata(L
, size
);
2910 size
= text_bytes_get(txt
, start
, size
, data
);
2911 lua_pushlstring(L
, data
, size
);
2919 static int file_lines_newindex(lua_State
*L
) {
2920 Text
*txt
= obj_ref_check(L
, 1, VIS_LUA_TYPE_TEXT
);
2921 size_t line
= luaL_checkunsigned(L
, 2);
2923 const char *data
= luaL_checklstring(L
, 3, &size
);
2925 text_insert(txt
, 0, data
, size
);
2926 text_insert(txt
, size
, "\n", 1);
2929 size_t start
= text_pos_by_lineno(txt
, line
);
2930 size_t end
= text_line_end(txt
, start
);
2931 if (start
!= EPOS
&& end
!= EPOS
) {
2932 text_delete(txt
, start
, end
- start
);
2933 text_insert(txt
, start
, data
, size
);
2934 if (text_size(txt
) == start
+ size
)
2935 text_insert(txt
, text_size(txt
), "\n", 1);
2940 static int file_lines_len(lua_State
*L
) {
2941 Text
*txt
= obj_ref_check(L
, 1, VIS_LUA_TYPE_TEXT
);
2944 size_t size
= text_size(txt
);
2946 lines
= text_lineno_by_pos(txt
, size
);
2947 if (lines
> 1 && text_byte_get(txt
, size
-1, &lastchar
) && lastchar
== '\n')
2949 lua_pushunsigned(L
, lines
);
2953 static const struct luaL_Reg file_lines_funcs
[] = {
2954 { "__index", file_lines_index
},
2955 { "__newindex", file_lines_newindex
},
2956 { "__len", file_lines_len
},
2960 static int window_marks_index(lua_State
*L
) {
2962 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
2963 Win
*win
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_MARKS
, offsetof(Win
, saved_selections
));
2966 const char *symbol
= luaL_checkstring(L
, 2);
2967 if (strlen(symbol
) != 1)
2969 enum VisMark mark
= vis_mark_from(vis
, symbol
[0]);
2970 if (mark
== VIS_MARK_INVALID
)
2973 Array arr
= vis_mark_get(win
, mark
);
2974 for (size_t i
= 0, len
= array_length(&arr
); i
< len
; i
++) {
2975 Filerange
*range
= array_get(&arr
, i
);
2976 lua_pushunsigned(L
, i
+1);
2977 pushrange(L
, range
);
2978 lua_settable(L
, -3);
2980 array_release(&arr
);
2984 static int window_marks_newindex(lua_State
*L
) {
2985 Vis
*vis
= lua_touserdata(L
, lua_upvalueindex(1));
2986 Win
*win
= obj_ref_check_containerof(L
, 1, VIS_LUA_TYPE_MARKS
, offsetof(Win
, saved_selections
));
2989 const char *symbol
= luaL_checkstring(L
, 2);
2990 if (strlen(symbol
) != 1)
2992 enum VisMark mark
= vis_mark_from(vis
, symbol
[0]);
2993 if (mark
== VIS_MARK_INVALID
)
2997 array_init_sized(&ranges
, sizeof(Filerange
));
2999 if (lua_istable(L
, 3)) {
3001 while (lua_next(L
, 3)) {
3002 Filerange range
= getrange(L
, -1);
3003 if (text_range_valid(&range
))
3004 array_add(&ranges
, &range
);
3009 vis_mark_set(win
, mark
, &ranges
);
3010 array_release(&ranges
);
3014 static int window_marks_len(lua_State
*L
) {
3015 lua_pushunsigned(L
, VIS_MARK_INVALID
);
3019 static const struct luaL_Reg window_marks_funcs
[] = {
3020 { "__index", window_marks_index
},
3021 { "__newindex", window_marks_newindex
},
3022 { "__len", window_marks_len
},
3029 * For a valid range `start <= finish` holds.
3030 * An invalid range is represented as `nil`.
3034 * The beginning of the range.
3038 * The end of the range.
3039 * @tfield int finish
3050 * @tfield int HORIZONTAL
3051 * @tfield int VERTICAL
3062 * @tfield int NORMAL
3063 * @tfield int OPERATOR_PENDING
3064 * @tfield int INSERT
3065 * @tfield int REPLACE
3066 * @tfield int VISUAL
3067 * @tfield int VISUAL_LINE
3075 * This section describes the contract between the editor core and Lua
3076 * key handling functions mapped to symbolic keys using either @{Vis:map}
3079 * @section Key_Handling
3083 * Example of a key handling function.
3085 * The keyhandler is invoked with the pending content of the input queue
3086 * given as argument. This might be the empty string if no further input
3089 * The function is expected to return the number of *bytes* it has
3090 * consumed from the passed input keys. A negative return value is
3091 * interpreted as an indication that not enough input was available. The
3092 * function will be called again once the user has provided more input. A
3093 * missing return value (i.e. `nil`) is interpreted as zero, meaning
3094 * no further input was consumed but the function completed successfully.
3096 * @function keyhandler
3097 * @tparam string keys the keys following the mapping
3098 * @treturn int the number of *bytes* being consumed by the function (see above)
3099 * @see Vis:action_register
3103 * vis:map(vis.modes.INSERT, "<C-k>", function(keys)
3105 * return -1 -- need more input
3107 * local digraph = keys:sub(1, 2)
3108 * if digraph == "l*" then
3110 * return 2 -- consume 2 bytes of input
3112 * end, "Insert digraph")
3118 * These events are invoked from the editor core.
3119 * The following functions are invoked if they are registered in the
3120 * `vis.events` table. Users scripts should generally use the [Events](#events)
3121 * mechanism instead which multiplexes these core events.
3123 * @section Core_Events
3126 static void vis_lua_event_get(lua_State
*L
, const char *name
) {
3127 lua_getglobal(L
, "vis");
3128 lua_getfield(L
, -1, "events");
3129 if (lua_istable(L
, -1)) {
3130 lua_getfield(L
, -1, name
);
3135 static void vis_lua_event_call(Vis
*vis
, const char *name
) {
3136 lua_State
*L
= vis
->lua
;
3137 vis_lua_event_get(L
, name
);
3138 if (lua_isfunction(L
, -1))
3139 pcall(vis
, L
, 0, 0);
3143 static bool vis_lua_path_strip(Vis
*vis
) {
3144 lua_State
*L
= vis
->lua
;
3145 lua_getglobal(L
, "package");
3147 for (const char **var
= (const char*[]){ "path", "cpath", NULL
}; *var
; var
++) {
3149 lua_getfield(L
, -1, *var
);
3150 const char *path
= lua_tostring(L
, -1);
3155 char *copy
= strdup(path
), *stripped
= calloc(1, strlen(path
)+2);
3156 if (!copy
|| !stripped
) {
3162 for (char *elem
= copy
, *stripped_elem
= stripped
, *next
; elem
; elem
= next
) {
3163 if ((next
= strstr(elem
, ";")))
3165 if (strstr(elem
, "./"))
3166 continue; /* skip relative path entries */
3167 stripped_elem
+= sprintf(stripped_elem
, "%s;", elem
);
3170 lua_pushstring(L
, stripped
);
3171 lua_setfield(L
, -2, *var
);
3177 lua_pop(L
, 1); /* package */
3181 bool vis_lua_path_add(Vis
*vis
, const char *path
) {
3182 lua_State
*L
= vis
->lua
;
3185 lua_getglobal(L
, "package");
3186 lua_pushstring(L
, path
);
3187 lua_pushstring(L
, "/?.lua;");
3188 lua_pushstring(L
, path
);
3189 lua_pushstring(L
, "/?/init.lua;");
3190 lua_getfield(L
, -5, "path");
3192 lua_setfield(L
, -2, "path");
3193 lua_pop(L
, 1); /* package */
3197 bool vis_lua_paths_get(Vis
*vis
, char **lpath
, char **cpath
) {
3198 lua_State
*L
= vis
->lua
;
3202 lua_getglobal(L
, "package");
3203 lua_getfield(L
, -1, "path");
3204 s
= lua_tostring(L
, -1);
3205 *lpath
= s
? strdup(s
) : NULL
;
3206 lua_getfield(L
, -2, "cpath");
3207 s
= lua_tostring(L
, -1);
3208 *cpath
= s
? strdup(s
) : NULL
;
3212 static bool package_exist(Vis
*vis
, lua_State
*L
, const char *name
) {
3214 "local name = ...\n"
3215 "for _, searcher in ipairs(package.searchers or package.loaders) do\n"
3216 "local loader = searcher(name)\n"
3217 "if type(loader) == 'function' then\n"
3222 if (luaL_loadstring(L
, lua
) != LUA_OK
)
3224 lua_pushstring(L
, name
);
3225 /* an error indicates package exists */
3226 bool ret
= lua_pcall(L
, 1, 1, 0) != LUA_OK
|| lua_toboolean(L
, -1);
3231 static void *alloc_lua(void *ud
, void *ptr
, size_t osize
, size_t nsize
) {
3236 return realloc(ptr
, nsize
);
3241 * Editor initialization completed.
3242 * This event is emitted immediately after `visrc.lua` has been sourced, but
3243 * before any other events have occurred, in particular the command line arguments
3244 * have not yet been processed.
3246 * Can be used to set *global* configuration options.
3249 void vis_lua_init(Vis
*vis
) {
3250 lua_State
*L
= lua_newstate(alloc_lua
, vis
);
3254 lua_atpanic(L
, &panic_handler
);
3259 extern int luaopen_lpeg(lua_State
*L
);
3260 lua_getglobal(L
, "package");
3261 lua_getfield(L
, -1, "preload");
3262 lua_pushcfunction(L
, luaopen_lpeg
);
3263 lua_setfield(L
, -2, "lpeg");
3267 /* remove any relative paths from lua's default package.path */
3268 vis_lua_path_strip(vis
);
3270 /* extends lua's package.path with:
3272 * - ./lua (relative path to the binary location)
3273 * - $XDG_CONFIG_HOME/vis (defaulting to $HOME/.config/vis)
3274 * - /etc/vis (for system-wide configuration provided by administrator)
3275 * - /usr/(local/)?share/vis (or whatever is specified during ./configure)
3276 * - package.path (standard lua search path)
3278 char path
[PATH_MAX
];
3280 vis_lua_path_add(vis
, VIS_PATH
);
3282 /* try to get users home directory */
3283 const char *home
= getenv("HOME");
3284 if (!home
|| !*home
) {
3285 struct passwd
*pw
= getpwuid(getuid());
3290 vis_lua_path_add(vis
, "/etc/vis");
3292 const char *xdg_config
= getenv("XDG_CONFIG_HOME");
3294 snprintf(path
, sizeof path
, "%s/vis", xdg_config
);
3295 vis_lua_path_add(vis
, path
);
3296 } else if (home
&& *home
) {
3297 snprintf(path
, sizeof path
, "%s/.config/vis", home
);
3298 vis_lua_path_add(vis
, path
);
3301 ssize_t len
= readlink("/proc/self/exe", path
, sizeof(path
)-1);
3304 /* some idiotic dirname(3) implementations return pointers to statically
3305 * allocated memory, hence we use memmove to copy it back */
3306 char *dir
= dirname(path
);
3308 size_t len
= strlen(dir
)+1;
3309 if (len
< sizeof(path
) - sizeof("/lua")) {
3310 memmove(path
, dir
, len
);
3311 strcat(path
, "/lua");
3312 vis_lua_path_add(vis
, path
);
3317 vis_lua_path_add(vis
, getenv("VIS_PATH"));
3319 /* table in registry to lookup object type, stores metatable -> type mapping */
3321 lua_setfield(L
, LUA_REGISTRYINDEX
, "vis.types");
3322 /* table in registry to track lifetimes of C objects */
3324 lua_setfield(L
, LUA_REGISTRYINDEX
, "vis.objects");
3325 /* table in registry to store references to Lua functions */
3327 lua_setfield(L
, LUA_REGISTRYINDEX
, "vis.functions");
3328 /* metatable used to type check user data */
3329 obj_type_new(L
, VIS_LUA_TYPE_VIS
);
3330 luaL_setfuncs(L
, vis_lua
, 0);
3332 lua_setfield(L
, -2, "types");
3333 /* create reference to main vis object, such that the further
3334 * calls to obj_type_new can register the type meta tables in
3335 * vis.types[name] */
3336 obj_ref_new(L
, vis
, "vis");
3337 lua_setglobal(L
, "vis");
3339 obj_type_new(L
, VIS_LUA_TYPE_FILE
);
3342 enum VisTextObject id
;
3345 { VIS_TEXTOBJECT_INNER_WORD
, "text_object_word" },
3346 { VIS_TEXTOBJECT_INNER_LONGWORD
, "text_object_longword" },
3349 for (size_t i
= 0; i
< LENGTH(textobjects
); i
++) {
3350 lua_pushunsigned(L
, textobjects
[i
].id
);
3351 lua_pushcclosure(L
, file_text_object
, 1);
3352 lua_setfield(L
, -2, textobjects
[i
].name
);
3355 luaL_setfuncs(L
, file_funcs
, 0);
3357 obj_type_new(L
, VIS_LUA_TYPE_TEXT
);
3358 luaL_setfuncs(L
, file_lines_funcs
, 0);
3359 obj_type_new(L
, VIS_LUA_TYPE_WINDOW
);
3360 luaL_setfuncs(L
, window_funcs
, 0);
3366 { UI_STYLE_LEXER_MAX
, "STYLE_LEXER_MAX" },
3367 { UI_STYLE_DEFAULT
, "STYLE_DEFAULT" },
3368 { UI_STYLE_CURSOR
, "STYLE_CURSOR" },
3369 { UI_STYLE_CURSOR_PRIMARY
, "STYLE_CURSOR_PRIMARY" },
3370 { UI_STYLE_CURSOR_LINE
, "STYLE_CURSOR_LINE" },
3371 { UI_STYLE_SELECTION
, "STYLE_SELECTION" },
3372 { UI_STYLE_LINENUMBER
, "STYLE_LINENUMBER" },
3373 { UI_STYLE_LINENUMBER_CURSOR
, "STYLE_LINENUMBER_CURSOR" },
3374 { UI_STYLE_COLOR_COLUMN
, "STYLE_COLOR_COLUMN" },
3375 { UI_STYLE_STATUS
, "STYLE_STATUS" },
3376 { UI_STYLE_STATUS_FOCUSED
, "STYLE_STATUS_FOCUSED" },
3377 { UI_STYLE_SEPARATOR
, "STYLE_SEPARATOR" },
3378 { UI_STYLE_INFO
, "STYLE_INFO" },
3379 { UI_STYLE_EOF
, "STYLE_EOF" },
3382 for (size_t i
= 0; i
< LENGTH(styles
); i
++) {
3383 lua_pushunsigned(L
, styles
[i
].id
);
3384 lua_setfield(L
, -2, styles
[i
].name
);
3387 obj_type_new(L
, VIS_LUA_TYPE_WIN_OPTS
);
3388 luaL_setfuncs(L
, window_option_funcs
, 0);
3390 obj_type_new(L
, VIS_LUA_TYPE_MARK
);
3391 obj_type_new(L
, VIS_LUA_TYPE_MARKS
);
3392 lua_pushlightuserdata(L
, vis
);
3393 luaL_setfuncs(L
, window_marks_funcs
, 1);
3395 obj_type_new(L
, VIS_LUA_TYPE_SELECTION
);
3396 luaL_setfuncs(L
, window_selection_funcs
, 0);
3397 obj_type_new(L
, VIS_LUA_TYPE_SELECTIONS
);
3398 luaL_setfuncs(L
, window_selections_funcs
, 0);
3400 obj_type_new(L
, VIS_LUA_TYPE_UI
);
3401 luaL_setfuncs(L
, ui_funcs
, 0);
3402 lua_pushunsigned(L
, vis
->ui
->colors(vis
->ui
));
3403 lua_setfield(L
, -2, "colors");
3405 static const struct {
3409 { UI_LAYOUT_HORIZONTAL
, "HORIZONTAL" },
3410 { UI_LAYOUT_VERTICAL
, "VERTICAL" },
3412 for (size_t i
= 0; i
< LENGTH(layouts
); i
++) {
3413 lua_pushunsigned(L
, layouts
[i
].id
);
3414 lua_setfield(L
, -2, layouts
[i
].name
);
3416 lua_setfield(L
, -2, "layouts");
3418 obj_type_new(L
, VIS_LUA_TYPE_REGISTERS
);
3419 lua_pushlightuserdata(L
, vis
);
3420 luaL_setfuncs(L
, registers_funcs
, 1);
3422 obj_type_new(L
, VIS_LUA_TYPE_KEYACTION
);
3424 lua_getglobal(L
, "vis");
3425 lua_getmetatable(L
, -1);
3427 lua_pushstring(L
, VERSION
);
3428 lua_setfield(L
, -2, "VERSION");
3431 static const struct {
3435 { VIS_MODE_NORMAL
, "NORMAL" },
3436 { VIS_MODE_OPERATOR_PENDING
, "OPERATOR_PENDING" },
3437 { VIS_MODE_VISUAL
, "VISUAL" },
3438 { VIS_MODE_VISUAL_LINE
, "VISUAL_LINE" },
3439 { VIS_MODE_INSERT
, "INSERT" },
3440 { VIS_MODE_REPLACE
, "REPLACE" },
3442 for (size_t i
= 0; i
< LENGTH(modes
); i
++) {
3443 lua_pushunsigned(L
, modes
[i
].id
);
3444 lua_setfield(L
, -2, modes
[i
].name
);
3446 lua_setfield(L
, -2, "modes");
3448 obj_type_new(L
, VIS_LUA_TYPE_VIS_OPTS
);
3449 luaL_setfuncs(L
, vis_option_funcs
, 0);
3451 if (!package_exist(vis
, L
, "visrc")) {
3452 vis_info_show(vis
, "WARNING: failed to load visrc.lua");
3454 lua_getglobal(L
, "require");
3455 lua_pushstring(L
, "visrc");
3456 pcall(vis
, L
, 1, 0);
3457 vis_lua_event_call(vis
, "init");
3462 * Editor startup completed.
3463 * This event is emitted immediately before the main loop starts.
3464 * At this point all files are loaded and corresponding windows are created.
3465 * We are about to process interactive keyboard input.
3468 void vis_lua_start(Vis
*vis
) {
3469 vis_lua_event_call(vis
, "start");
3473 * Editor is about to terminate.
3476 void vis_lua_quit(Vis
*vis
) {
3479 vis_lua_event_call(vis
, "quit");
3480 lua_close(vis
->lua
);
3485 * Input key event in either input or replace mode.
3487 * @tparam string key
3488 * @treturn bool whether the key was consumed or not
3490 static bool vis_lua_input(Vis
*vis
, const char *key
, size_t len
) {
3491 lua_State
*L
= vis
->lua
;
3492 if (!L
|| !vis
->win
|| vis
->win
->file
->internal
)
3495 vis_lua_event_get(L
, "input");
3496 if (lua_isfunction(L
, -1)) {
3497 lua_pushlstring(L
, key
, len
);
3498 if (pcall(vis
, L
, 1, 1) == 0) {
3499 ret
= lua_isboolean(L
, -1) && lua_toboolean(L
, -1);
3507 void vis_lua_mode_insert_input(Vis
*vis
, const char *key
, size_t len
) {
3508 if (!vis_lua_input(vis
, key
, len
))
3509 vis_insert_key(vis
, key
, len
);
3512 void vis_lua_mode_replace_input(Vis
*vis
, const char *key
, size_t len
) {
3513 if (!vis_lua_input(vis
, key
, len
))
3514 vis_replace_key(vis
, key
, len
);
3519 * @function file_open
3520 * @tparam File file the file to be opened
3522 void vis_lua_file_open(Vis
*vis
, File
*file
) {
3523 debug("event: file-open: %s %p %p\n", file
->name
? file
->name
: "unnamed", (void*)file
, (void*)file
->text
);
3524 lua_State
*L
= vis
->lua
;
3527 vis_lua_event_get(L
, "file_open");
3528 if (lua_isfunction(L
, -1)) {
3529 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
3530 pcall(vis
, L
, 1, 0);
3537 * Triggered *before* the file is being written.
3538 * @function file_save_pre
3539 * @tparam File file the file being written
3540 * @tparam string path the absolute path to which the file will be written, `nil` if standard output
3541 * @treturn bool whether the write operation should be proceeded
3543 bool vis_lua_file_save_pre(Vis
*vis
, File
*file
, const char *path
) {
3544 lua_State
*L
= vis
->lua
;
3547 vis_lua_event_get(L
, "file_save_pre");
3548 if (lua_isfunction(L
, -1)) {
3549 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
3550 lua_pushstring(L
, path
);
3551 if (pcall(vis
, L
, 2, 1) != 0)
3553 return !lua_isboolean(L
, -1) || lua_toboolean(L
, -1);
3561 * Triggered *after* a successful write operation.
3562 * @function file_save_post
3563 * @tparam File file the file which was written
3564 * @tparam string path the absolute path to which it was written, `nil` if standard output
3566 void vis_lua_file_save_post(Vis
*vis
, File
*file
, const char *path
) {
3567 lua_State
*L
= vis
->lua
;
3570 vis_lua_event_get(L
, "file_save_post");
3571 if (lua_isfunction(L
, -1)) {
3572 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
3573 lua_pushstring(L
, path
);
3574 pcall(vis
, L
, 2, 0);
3581 * The last window displaying the file has been closed.
3582 * @function file_close
3583 * @tparam File file the file being closed
3585 void vis_lua_file_close(Vis
*vis
, File
*file
) {
3586 debug("event: file-close: %s %p %p\n", file
->name
? file
->name
: "unnamed", (void*)file
, (void*)file
->text
);
3587 lua_State
*L
= vis
->lua
;
3590 vis_lua_event_get(L
, "file_close");
3591 if (lua_isfunction(L
, -1)) {
3592 obj_ref_new(L
, file
, VIS_LUA_TYPE_FILE
);
3593 pcall(vis
, L
, 1, 0);
3595 obj_ref_free(L
, file
->marks
);
3596 obj_ref_free(L
, file
->text
);
3597 obj_ref_free(L
, file
);
3603 * A new window has been created.
3604 * @function win_open
3605 * @tparam Window win the window being opened
3607 void vis_lua_win_open(Vis
*vis
, Win
*win
) {
3608 debug("event: win-open: %s %p %p\n", win
->file
->name
? win
->file
->name
: "unnamed", (void*)win
, (void*)win
->view
);
3609 lua_State
*L
= vis
->lua
;
3612 vis_lua_event_get(L
, "win_open");
3613 if (lua_isfunction(L
, -1)) {
3614 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
3615 pcall(vis
, L
, 1, 0);
3622 * An window is being closed.
3623 * @function win_close
3624 * @tparam Window win the window being closed
3626 void vis_lua_win_close(Vis
*vis
, Win
*win
) {
3627 debug("event: win-close: %s %p %p\n", win
->file
->name
? win
->file
->name
: "unnamed", (void*)win
, (void*)win
->view
);
3628 lua_State
*L
= vis
->lua
;
3631 vis_lua_event_get(L
, "win_close");
3632 if (lua_isfunction(L
, -1)) {
3633 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
3634 pcall(vis
, L
, 1, 0);
3636 obj_ref_free(L
, win
->view
);
3637 obj_ref_free(L
, win
);
3643 * The window has been redrawn and the syntax highlighting needs to be performed.
3644 * @function win_highlight
3645 * @tparam Window win the window being redrawn
3648 void vis_lua_win_highlight(Vis
*vis
, Win
*win
) {
3649 lua_State
*L
= vis
->lua
;
3652 vis_lua_event_get(L
, "win_highlight");
3653 if (lua_isfunction(L
, -1)) {
3654 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
3655 pcall(vis
, L
, 1, 0);
3661 * Window status bar redraw.
3662 * @function win_status
3663 * @tparam Window win the affected window
3666 void vis_lua_win_status(Vis
*vis
, Win
*win
) {
3667 lua_State
*L
= vis
->lua
;
3668 if (!L
|| win
->file
->internal
) {
3669 window_status_update(vis
, win
);
3672 vis_lua_event_get(L
, "win_status");
3673 if (lua_isfunction(L
, -1)) {
3674 obj_ref_new(L
, win
, VIS_LUA_TYPE_WINDOW
);
3675 pcall(vis
, L
, 1, 0);
3677 window_status_update(vis
, win
);
3683 * CSI command received from terminal.
3684 * @function term_csi
3685 * @param List of CSI parameters
3687 void vis_lua_term_csi(Vis
*vis
, const long *csi
) {
3688 lua_State
*L
= vis
->lua
;
3691 vis_lua_event_get(L
, "term_csi");
3692 if (lua_isfunction(L
, -1)) {
3694 lua_pushinteger(L
, csi
[0]);
3695 for (int i
= 0; i
< nargs
; i
++)
3696 lua_pushinteger(L
, csi
[2 + i
]);
3697 pcall(vis
, L
, 1 + nargs
, 0);
3702 * The response received from the process started via @{Vis:communicate}.
3703 * @function process_response
3704 * @tparam string name the name of process given to @{Vis:communicate}
3705 * @tparam string response_type can be "STDOUT" or "STDERR" if new output was received in corresponding channel, "SIGNAL" if the process was terminated by a signal or "EXIT" when the process terminated normally
3706 * @tparam int code the exit code number if response_type is "EXIT", or the signal number if response_type is "SIGNAL"
3707 * @tparam string buffer the available content sent by the process
3709 void vis_lua_process_response(Vis
*vis
, const char *name
,
3710 char *buffer
, size_t len
, ResponseType rtype
) {
3711 lua_State
*L
= vis
->lua
;
3715 vis_lua_event_get(L
, "process_response");
3716 if (lua_isfunction(L
, -1)) {
3717 lua_pushstring(L
, name
);
3719 case STDOUT
: lua_pushstring(L
, "STDOUT"); break;
3720 case STDERR
: lua_pushstring(L
, "STDERR"); break;
3721 case SIGNAL
: lua_pushstring(L
, "SIGNAL"); break;
3722 case EXIT
: lua_pushstring(L
, "EXIT"); break;
3727 lua_pushinteger(L
, len
);
3732 lua_pushlstring(L
, buffer
, len
);
3734 pcall(vis
, L
, 4, 0);
3740 * Emitted immediately before the UI is drawn to the screen.
3741 * Allows last-minute overrides to the styling of UI elements.
3743 * *WARNING:* This is emitted every screen draw!
3744 * Use sparingly and check for `nil` values!
3747 void vis_lua_ui_draw(Vis
*vis
) {
3748 vis_lua_event_call(vis
, "ui_draw");