vis-lua: expose vis:textobject_register
[vis.git] / vis-lua.c
blob0ea7d4848d2c3f769a90d77a5af1d433cfb4c508
1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #include <pwd.h>
7 #include "vis-lua.h"
8 #include "vis-core.h"
9 #include "text-motions.h"
11 #if !CONFIG_LUA
13 void vis_lua_start(Vis *vis) { }
14 void vis_lua_quit(Vis *vis) { }
15 void vis_lua_file_open(Vis *vis, File *file) { }
16 void vis_lua_file_save(Vis *vis, File *file) { }
17 void vis_lua_file_close(Vis *vis, File *file) { }
18 void vis_lua_win_open(Vis *vis, Win *win) { }
19 void vis_lua_win_close(Vis *vis, Win *win) { }
20 bool vis_theme_load(Vis *vis, const char *name) { return true; }
22 #else
24 #if 0
25 static void stack_dump_entry(lua_State *L, int i) {
26 int t = lua_type(L, i);
27 switch (t) {
28 case LUA_TNIL:
29 printf("nil");
30 break;
31 case LUA_TBOOLEAN:
32 printf(lua_toboolean(L, i) ? "true" : "false");
33 break;
34 case LUA_TLIGHTUSERDATA:
35 printf("lightuserdata(%p)", lua_touserdata(L, i));
36 break;
37 case LUA_TNUMBER:
38 printf("%g", lua_tonumber(L, i));
39 break;
40 case LUA_TSTRING:
41 printf("`%s'", lua_tostring(L, i));
42 break;
43 case LUA_TTABLE:
44 printf("table[");
45 lua_pushnil(L); /* first key */
46 while (lua_next(L, i > 0 ? i : i - 1)) {
47 stack_dump_entry(L, -2);
48 printf("=");
49 stack_dump_entry(L, -1);
50 printf(",");
51 lua_pop(L, 1); /* remove value, keep key */
53 printf("]");
54 break;
55 case LUA_TUSERDATA:
56 printf("userdata(%p)", lua_touserdata(L, i));
57 break;
58 default: /* other values */
59 printf("%s", lua_typename(L, t));
60 break;
64 static void stack_dump(lua_State *L, const char *format, ...) {
65 va_list ap;
66 va_start(ap, format);
67 vprintf(format, ap);
68 va_end(ap);
69 int top = lua_gettop(L);
70 for (int i = 1; i <= top; i++) {
71 printf("%d: ", i);
72 stack_dump_entry(L, i);
73 printf("\n");
75 printf("\n\n");
76 fflush(stdout);
79 #endif
81 static int error_function(lua_State *L) {
82 Vis *vis = lua_touserdata(L, lua_upvalueindex(1));
83 size_t len;
84 const char *msg = lua_tostring(L, 1);
85 if (msg)
86 luaL_traceback(L, L, msg, 1);
87 msg = lua_tolstring(L, 1, &len);
88 vis_message_show(vis, msg);
89 return 1;
92 static int pcall(Vis *vis, lua_State *L, int nargs, int nresults) {
93 /* insert a custom error function below all arguments */
94 int msgh = lua_gettop(L) - nargs;
95 lua_pushlightuserdata(L, vis);
96 lua_pushcclosure(L, error_function, 1);
97 lua_insert(L, msgh);
98 int ret = lua_pcall(L, nargs, nresults, msgh);
99 lua_remove(L, msgh);
100 return ret;
103 /* expects a lua function at the top of the stack and stores a
104 * reference to it in the registry. The return value can be used
105 * to look it up.
107 * registry["vis.functions"][(void*)(function)] = function
109 static const void *func_ref_new(lua_State *L) {
110 const void *addr = lua_topointer(L, -1);
111 if (!lua_isfunction(L, -1) || !addr)
112 return NULL;
113 lua_getfield(L, LUA_REGISTRYINDEX, "vis.functions");
114 lua_pushlightuserdata(L, (void*)addr);
115 lua_pushvalue(L, -3);
116 lua_settable(L, -3);
117 lua_pop(L, 1);
118 return addr;
121 /* retrieve function from registry and place it at the top of the stack */
122 static bool func_ref_get(lua_State *L, const void *addr) {
123 lua_getfield(L, LUA_REGISTRYINDEX, "vis.functions");
124 lua_pushlightuserdata(L, (void*)addr);
125 lua_gettable(L, -2);
126 lua_remove(L, -2);
127 if (!lua_isfunction(L, -1)) {
128 lua_pop(L, 1);
129 return false;
131 return true;
134 static void *obj_new(lua_State *L, size_t size, const char *type) {
135 void *obj = lua_newuserdata(L, size);
136 luaL_getmetatable(L, type);
137 lua_setmetatable(L, -2);
138 lua_newtable(L);
139 lua_setuservalue(L, -2);
140 return obj;
143 /* returns registry["vis.objects"][addr] if it is of correct type */
144 static void *obj_ref_get(lua_State *L, void *addr, const char *type) {
145 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
146 lua_pushlightuserdata(L, addr);
147 lua_gettable(L, -2);
148 lua_remove(L, -2);
149 if (lua_isnil(L, -1)) {
150 lua_pop(L, 1);
151 return NULL;
153 return luaL_checkudata(L, -1, type);
156 /* expects a userdatum at the top of the stack and sets
158 * registry["vis.objects"][addr] = userdata
160 static void obj_ref_set(lua_State *L, void *addr) {
161 lua_getfield(L, LUA_REGISTRYINDEX, "vis.objects");
162 lua_pushlightuserdata(L, addr);
163 lua_pushvalue(L, -3);
164 lua_settable(L, -3);
165 lua_pop(L, 1);
168 /* invalidates an object reference
170 * registry["vis.objects"][addr] = nil
172 static void obj_ref_free(lua_State *L, void *addr) {
173 lua_pushnil(L);
174 obj_ref_set(L, addr);
177 /* creates a new object reference of given type if it does not
178 * already exist in the registry */
179 static void *obj_ref_new(lua_State *L, void *addr, const char *type) {
180 if (!addr)
181 return NULL;
182 void **handle = (void**)obj_ref_get(L, addr, type);
183 if (!handle) {
184 handle = obj_new(L, sizeof(addr), type);
185 obj_ref_set(L, addr);
186 *handle = addr;
188 return *handle;
191 /* retrieve object stored in reference at stack location `idx' */
192 static void *obj_ref_check_get(lua_State *L, int idx, const char *type) {
193 void **addr = luaL_checkudata(L, idx, type);
194 if (!obj_ref_get(L, *addr, type))
195 return NULL;
196 return *addr;
199 /* (type) check validity of object reference at stack location `idx' */
200 static void *obj_ref_check(lua_State *L, int idx, const char *type) {
201 void *obj = obj_ref_check_get(L, idx, type);
202 if (obj)
203 lua_pop(L, 1);
204 return obj;
207 static int index_common(lua_State *L) {
208 lua_getmetatable(L, 1);
209 lua_pushvalue(L, 2);
210 lua_gettable(L, -2);
211 if (lua_isnil(L, -1)) {
212 lua_getuservalue(L, 1);
213 lua_pushvalue(L, 2);
214 lua_gettable(L, -2);
216 return 1;
219 static int newindex_common(lua_State *L) {
220 lua_getuservalue(L, 1);
221 lua_pushvalue(L, 2);
222 lua_pushvalue(L, 3);
223 lua_settable(L, -3);
224 return 0;
227 static const char *keymapping(Vis *vis, const char *keys, const Arg *arg) {
228 lua_State *L = vis->lua;
229 if (!func_ref_get(L, arg->v))
230 return keys;
231 pcall(vis, L, 0, 0);
232 return keys;
235 static int windows_iter(lua_State *L);
237 static int windows(lua_State *L) {
238 Vis *vis = obj_ref_check(L, 1, "vis");
239 if (!vis) {
240 lua_pushnil(L);
241 return 1;
243 Win **handle = lua_newuserdata(L, sizeof *handle);
244 *handle = vis->windows;
245 lua_pushcclosure(L, windows_iter, 1);
246 return 1;
249 static int windows_iter(lua_State *L) {
250 Win **handle = lua_touserdata(L, lua_upvalueindex(1));
251 if (!*handle)
252 return 0;
253 Win *win = obj_ref_new(L, *handle, "vis.window");
254 if (!win)
255 return 0;
256 *handle = win->next;
257 return 1;
260 static int files_iter(lua_State *L);
262 static int files(lua_State *L) {
263 Vis *vis = obj_ref_check(L, 1, "vis");
264 if (!vis) {
265 lua_pushnil(L);
266 return 1;
268 File **handle = lua_newuserdata(L, sizeof *handle);
269 *handle = vis->files;
270 lua_pushcclosure(L, files_iter, 1);
271 return 1;
274 static int files_iter(lua_State *L) {
275 File **handle = lua_touserdata(L, lua_upvalueindex(1));
276 if (!*handle)
277 return 0;
278 File *file = obj_ref_new(L, *handle, "vis.file");
279 if (!file)
280 return 0;
281 *handle = file->next;
282 return 1;
285 static int command(lua_State *L) {
286 Vis *vis = obj_ref_check(L, 1, "vis");
287 if (!vis) {
288 lua_pushnil(L);
289 return 1;
291 const char *cmd = luaL_checkstring(L, 2);
292 bool ret = vis_cmd(vis, cmd);
293 lua_pushboolean(L, ret);
294 return 1;
297 static int info(lua_State *L) {
298 Vis *vis = obj_ref_check(L, 1, "vis");
299 if (!vis) {
300 lua_pushnil(L);
301 return 1;
303 const char *msg = luaL_checkstring(L, 2);
304 vis_info_show(vis, "%s", msg);
305 return 0;
308 static int open(lua_State *L) {
309 Vis *vis = obj_ref_check(L, 1, "vis");
310 if (!vis) {
311 lua_pushnil(L);
312 return 1;
314 const char *name = luaL_checkstring(L, 2);
315 File *file = NULL;
316 if (vis_window_new(vis, name))
317 file = obj_ref_new(L, vis->win->file, "vis.file");
318 if (!file)
319 lua_pushnil(L);
320 return 1;
323 static int map(lua_State *L) {
324 Vis *vis = obj_ref_check(L, 1, "vis");
325 if (!vis) {
326 lua_pushnil(L);
327 return 1;
329 KeyBinding *binding = NULL;
330 KeyAction *action = NULL;
332 int mode = luaL_checkint(L, 2);
333 const char *key = luaL_checkstring(L, 3);
335 if (!key || !lua_isfunction(L, 4))
336 goto err;
337 if (!(binding = calloc(1, sizeof *binding)) || !(action = calloc(1, sizeof *action)))
338 goto err;
340 /* store reference to function in the registry */
341 lua_pushvalue(L, 4);
342 const void *func = func_ref_new(L);
343 if (!func)
344 goto err;
346 *action = (KeyAction){
347 .name = NULL,
348 .help = NULL,
349 .func = keymapping,
350 .arg = (const Arg){
351 .v = func,
355 binding->action = action;
357 if (!vis_mode_map(vis, mode, key, binding))
358 goto err;
360 lua_pushboolean(L, true);
361 return 1;
362 err:
363 free(binding);
364 free(action);
365 lua_pushboolean(L, false);
366 return 1;
369 static int motion(lua_State *L) {
370 Vis *vis = obj_ref_check(L, 1, "vis");
371 enum VisMotion id = luaL_checkunsigned(L, 2);
372 // TODO handle var args?
373 lua_pushboolean(L, vis && vis_motion(vis, id));
374 return 1;
377 static size_t motion_lua(Vis *vis, Win *win, void *data, size_t pos) {
378 lua_State *L = vis->lua;
379 if (!func_ref_get(L, data) || !obj_ref_new(L, win, "vis.window"))
380 return EPOS;
382 lua_pushunsigned(L, pos);
383 if (pcall(vis, L, 2, 1) != 0)
384 return EPOS;
385 return luaL_checkunsigned(L, -1);
388 static int motion_register(lua_State *L) {
389 int id = -1;
390 const void *func;
391 Vis *vis = obj_ref_check(L, 1, "vis");
392 if (!vis || !lua_isfunction(L, 2) || !(func = func_ref_new(L)))
393 goto err;
394 id = vis_motion_register(vis, 0, (void*)func, motion_lua);
395 err:
396 lua_pushinteger(L, id);
397 return 1;
400 static int textobject(lua_State *L) {
401 Vis *vis = obj_ref_check(L, 1, "vis");
402 enum VisTextObject id = luaL_checkunsigned(L, 2);
403 lua_pushboolean(L, vis && vis_textobject(vis, id));
404 return 1;
408 static Filerange textobject_lua(Vis *vis, Win *win, void *data, size_t pos) {
409 lua_State *L = vis->lua;
410 if (!func_ref_get(L, data) || !obj_ref_new(L, win, "vis.window"))
411 return text_range_empty();
412 lua_pushunsigned(L, pos);
413 if (pcall(vis, L, 2, 2) != 0)
414 return text_range_empty();
415 return text_range_new(luaL_checkunsigned(L, -2), luaL_checkunsigned(L, -1));
418 static int textobject_register(lua_State *L) {
419 int id = -1;
420 const void *func;
421 Vis *vis = obj_ref_check(L, 1, "vis");
422 if (!vis || !lua_isfunction(L, 2) || !(func = func_ref_new(L)))
423 goto err;
424 id = vis_textobject_register(vis, 0, (void*)func, textobject_lua);
425 err:
426 lua_pushinteger(L, id);
427 return 1;
430 static int vis_index(lua_State *L) {
431 Vis *vis = obj_ref_check(L, 1, "vis");
432 if (!vis) {
433 lua_pushnil(L);
434 return 1;
437 if (lua_isstring(L, 2)) {
438 const char *key = lua_tostring(L, 2);
439 if (strcmp(key, "win") == 0) {
440 obj_ref_new(L, vis->windows, "vis.window");
441 return 1;
444 if (strcmp(key, "MODE_NORMAL") == 0) {
445 lua_pushunsigned(L, VIS_MODE_NORMAL);
446 return 1;
449 if (strcmp(key, "MODE_OPERATOR_PENDING") == 0) {
450 lua_pushunsigned(L, VIS_MODE_OPERATOR_PENDING);
451 return 1;
454 if (strcmp(key, "MODE_VISUAL") == 0) {
455 lua_pushunsigned(L, VIS_MODE_VISUAL);
456 return 1;
459 if (strcmp(key, "MODE_VISUAL_LINE") == 0) {
460 lua_pushunsigned(L, VIS_MODE_VISUAL_LINE);
461 return 1;
464 if (strcmp(key, "MODE_INSERT") == 0) {
465 lua_pushunsigned(L, VIS_MODE_INSERT);
466 return 1;
469 if (strcmp(key, "MODE_REPLACE") == 0) {
470 lua_pushunsigned(L, VIS_MODE_REPLACE);
471 return 1;
475 return index_common(L);
478 static int vis_newindex(lua_State *L) {
479 Vis *vis = obj_ref_check(L, 1, "vis");
480 if (!vis)
481 return 0;
482 return newindex_common(L);
485 static const struct luaL_Reg vis_lua[] = {
486 { "files", files },
487 { "windows", windows },
488 { "command", command },
489 { "info", info },
490 { "open", open },
491 { "map", map },
492 { "motion", motion },
493 { "motion_register", motion_register },
494 { "textobject", textobject },
495 { "textobject_register", textobject_register },
496 { "__index", vis_index },
497 { "__newindex", vis_newindex },
498 { NULL, NULL },
501 static int window_index(lua_State *L) {
502 Win *win = obj_ref_check(L, 1, "vis.window");
503 if (!win) {
504 lua_pushnil(L);
505 return 1;
508 if (lua_isstring(L, 2)) {
509 const char *key = lua_tostring(L, 2);
510 if (strcmp(key, "file") == 0) {
511 obj_ref_new(L, win->file, "vis.file");
512 return 1;
515 if (strcmp(key, "cursor") == 0) {
516 obj_ref_new(L, win->view, "vis.window.cursor");
517 return 1;
520 if (strcmp(key, "syntax") == 0) {
521 const char *syntax = view_syntax_get(win->view);
522 if (syntax)
523 lua_pushstring(L, syntax);
524 else
525 lua_pushnil(L);
526 return 1;
530 return index_common(L);
533 static int window_newindex(lua_State *L) {
534 Win *win = obj_ref_check(L, 1, "vis.window");
535 if (!win)
536 return 0;
537 if (lua_isstring(L, 2)) {
538 const char *key = lua_tostring(L, 2);
539 if (strcmp(key, "syntax") == 0) {
540 const char *syntax = luaL_checkstring(L, 3);
541 view_syntax_set(win->view, syntax);
542 return 0;
545 return newindex_common(L);
548 static const struct luaL_Reg window_funcs[] = {
549 { "__index", window_index },
550 { "__newindex", window_newindex },
551 { NULL, NULL },
554 static int window_cursor_index(lua_State *L) {
555 View *view = obj_ref_check(L, 1, "vis.window.cursor");
556 if (!view) {
557 lua_pushnil(L);
558 return 1;
561 if (lua_isstring(L, 2)) {
562 Text *txt = view_text(view);
563 const char *key = lua_tostring(L, 2);
564 if (strcmp(key, "pos") == 0) {
565 lua_pushunsigned(L, view_cursor_get(view));
566 return 1;
569 if (strcmp(key, "line") == 0) {
570 size_t pos = view_cursor_get(view);
571 size_t line = text_lineno_by_pos(txt, pos);
572 lua_pushunsigned(L, line);
573 return 1;
576 if (strcmp(key, "col") == 0) {
577 size_t pos = view_cursor_get(view);
578 int col = text_line_char_get(txt, pos);
579 lua_pushunsigned(L, col);
580 return 1;
584 return index_common(L);
587 static int window_cursor_newindex(lua_State *L) {
588 View *view = obj_ref_check(L, 1, "vis.window.cursor");
589 if (!view)
590 return 0;
591 if (lua_isstring(L, 2)) {
592 const char *key = lua_tostring(L, 2);
593 if (strcmp(key, "pos") == 0) {
594 size_t pos = luaL_checkunsigned(L, 3);
595 view_cursor_to(view, pos);
596 return 0;
599 return newindex_common(L);
602 static int window_cursor_to(lua_State *L) {
603 View *view = obj_ref_check(L, 1, "vis.window.cursor");
604 if (view) {
605 Text *txt = view_text(view);
606 size_t line = luaL_checkunsigned(L, 2);
607 size_t col = luaL_checkunsigned(L, 3);
608 size_t pos = text_pos_by_lineno(txt, line);
609 pos = text_line_char_set(txt, pos, col);
610 view_cursor_to(view, pos);
612 return 0;
615 static const struct luaL_Reg window_cursor_funcs[] = {
616 { "__index", window_cursor_index },
617 { "__newindex", window_cursor_newindex },
618 { "to", window_cursor_to },
619 { NULL, NULL },
622 static int file_index(lua_State *L) {
623 File *file = obj_ref_check(L, 1, "vis.file");
624 if (!file) {
625 lua_pushnil(L);
626 return 1;
629 if (lua_isstring(L, 2)) {
630 const char *key = lua_tostring(L, 2);
631 if (strcmp(key, "name") == 0) {
632 lua_pushstring(L, file->name);
633 return 1;
635 if (strcmp(key, "lines") == 0) {
636 obj_ref_new(L, file->text, "vis.file.text");
637 return 1;
641 return index_common(L);
644 static int file_newindex(lua_State *L) {
645 File *file = obj_ref_check(L, 1, "vis.file");
646 if (!file)
647 return 0;
648 return newindex_common(L);
651 static int file_insert(lua_State *L) {
652 File *file = obj_ref_check(L, 1, "vis.file");
653 if (file) {
654 size_t pos = luaL_checkunsigned(L, 2);
655 size_t len;
656 luaL_checkstring(L, 3);
657 const char *data = lua_tolstring(L, 3, &len);
658 bool ret = text_insert(file->text, pos, data, len);
659 lua_pushboolean(L, ret);
660 } else {
661 lua_pushboolean(L, false);
663 return 1;
666 static int file_delete(lua_State *L) {
667 File *file = obj_ref_check(L, 1, "vis.file");
668 if (file) {
669 size_t pos = luaL_checkunsigned(L, 2);
670 size_t len = luaL_checkunsigned(L, 3);
671 bool ret = text_delete(file->text, pos, len);
672 lua_pushboolean(L, ret);
673 } else {
674 lua_pushboolean(L, false);
676 return 1;
679 static int file_lines_iterator_it(lua_State *L);
681 static int file_lines_iterator(lua_State *L) {
682 /* need to check second parameter first, because obj_ref_check_get
683 * modifies the stack */
684 size_t line = luaL_optunsigned(L, 2, 1);
685 File *file = obj_ref_check_get(L, 1, "vis.file");
686 size_t *pos = lua_newuserdata(L, sizeof *pos);
687 *pos = text_pos_by_lineno(file->text, line);
688 lua_pushcclosure(L, file_lines_iterator_it, 2);
689 return 1;
692 static int file_lines_iterator_it(lua_State *L) {
693 File *file = *(File**)lua_touserdata(L, lua_upvalueindex(1));
694 size_t *start = lua_touserdata(L, lua_upvalueindex(2));
695 if (*start == text_size(file->text))
696 return 0;
697 size_t end = text_line_end(file->text, *start);
698 size_t len = end - *start;
699 char *buf = malloc(len);
700 if (!buf && len)
701 return 0;
702 len = text_bytes_get(file->text, *start, len, buf);
703 lua_pushlstring(L, buf, len);
704 free(buf);
705 *start = text_line_next(file->text, end);
706 return 1;
709 static const struct luaL_Reg file_funcs[] = {
710 { "__index", file_index },
711 { "__newindex", file_newindex },
712 { "insert", file_insert },
713 { "delete", file_delete },
714 { "lines_iterator", file_lines_iterator },
715 { NULL, NULL },
718 static int file_lines_index(lua_State *L) {
719 Text *txt = obj_ref_check(L, 1, "vis.file.text");
720 if (!txt)
721 goto err;
722 size_t line = luaL_checkunsigned(L, 2);
723 size_t start = text_pos_by_lineno(txt, line);
724 size_t end = text_line_end(txt, start);
725 if (start != EPOS && end != EPOS) {
726 size_t size = end - start;
727 char *data = malloc(size);
728 if (!data && size)
729 goto err;
730 size = text_bytes_get(txt, start, size, data);
731 lua_pushlstring(L, data, size);
732 free(data);
733 return 1;
735 err:
736 lua_pushnil(L);
737 return 1;
740 static int file_lines_newindex(lua_State *L) {
741 Text *txt = obj_ref_check(L, 1, "vis.file.text");
742 if (!txt)
743 return 0;
744 size_t line = luaL_checkunsigned(L, 2);
745 size_t size;
746 const char *data = luaL_checklstring(L, 3, &size);
747 if (line == 0) {
748 text_insert(txt, 0, data, size);
749 text_insert_newline(txt, size);
750 return 0;
752 size_t start = text_pos_by_lineno(txt, line);
753 size_t end = text_line_end(txt, start);
754 if (start != EPOS && end != EPOS) {
755 text_delete(txt, start, end - start);
756 text_insert(txt, start, data, size);
757 if (text_size(txt) == start + size)
758 text_insert_newline(txt, text_size(txt));
760 return 0;
763 static int file_lines_len(lua_State *L) {
764 Text *txt = obj_ref_check(L, 1, "vis.file.text");
765 size_t lines = 0;
766 if (txt) {
767 char lastchar;
768 size_t size = text_size(txt);
769 if (size > 0)
770 lines = text_lineno_by_pos(txt, size);
771 if (lines > 1 && text_byte_get(txt, size-1, &lastchar) && lastchar == '\n')
772 lines--;
774 lua_pushunsigned(L, lines);
775 return 1;
778 static const struct luaL_Reg file_lines_funcs[] = {
779 { "__index", file_lines_index },
780 { "__newindex", file_lines_newindex },
781 { "__len", file_lines_len },
782 { NULL, NULL },
785 static void vis_lua_event(Vis *vis, const char *name) {
786 lua_State *L = vis->lua;
787 lua_getglobal(L, "vis");
788 lua_getfield(L, -1, "events");
789 if (lua_istable(L, -1)) {
790 lua_getfield(L, -1, name);
792 lua_remove(L, -2);
795 void vis_lua_start(Vis *vis) {
796 lua_State *L = luaL_newstate();
797 if (!L)
798 return;
799 vis->lua = L;
800 luaL_openlibs(L);
803 /* extends lua's package.path with:
804 * - $VIS_PATH/{,lexers}
805 * - $XDG_CONFIG_HOME/vis/{,lexers} (defaulting to $HOME/.config/vis/{,lexers})
806 * - /usr/local/share/vis/{,lexers}
807 * - /usr/share/vis/{,lexers}
808 * - package.path (standard lua search path)
810 int paths = 3;
811 lua_getglobal(L, "package");
813 const char *vis_path = getenv("VIS_PATH");
814 if (vis_path) {
815 lua_pushstring(L, vis_path);
816 lua_pushstring(L, "/?.lua;");
817 lua_pushstring(L, vis_path);
818 lua_pushstring(L, "/lexers/?.lua;");
819 lua_concat(L, 4);
820 paths++;
823 /* try to get users home directory */
824 const char *home = getenv("HOME");
825 if (!home || !*home) {
826 struct passwd *pw = getpwuid(getuid());
827 if (pw)
828 home = pw->pw_dir;
831 const char *xdg_config = getenv("XDG_CONFIG_HOME");
832 if (xdg_config) {
833 lua_pushstring(L, xdg_config);
834 lua_pushstring(L, "/vis/?.lua;");
835 lua_pushstring(L, xdg_config);
836 lua_pushstring(L, "/vis/lexers/?.lua;");
837 lua_concat(L, 4);
838 paths++;
839 } else if (home && *home) {
840 lua_pushstring(L, home);
841 lua_pushstring(L, "/.config/vis/?.lua;");
842 lua_pushstring(L, home);
843 lua_pushstring(L, "/.config/vis/lexers/?.lua;");
844 lua_concat(L, 4);
845 paths++;
848 lua_pushstring(L, "/usr/local/share/vis/?.lua;/usr/local/share/vis/lexers/?.lua;");
849 lua_pushstring(L, "/usr/share/vis/?.lua;/usr/share/vis/lexers/?.lua;");
850 lua_getfield(L, -paths, "path");
851 lua_concat(L, paths);
852 lua_setfield(L, -2, "path");
853 lua_pop(L, 1); /* package */
855 /* table in registry to track lifetimes of C objects */
856 lua_newtable(L);
857 lua_setfield(L, LUA_REGISTRYINDEX, "vis.objects");
858 /* table in registry to store references to Lua functions */
859 lua_newtable(L);
860 lua_setfield(L, LUA_REGISTRYINDEX, "vis.functions");
861 /* metatable used to type check user data */
862 luaL_newmetatable(L, "vis.file");
863 luaL_setfuncs(L, file_funcs, 0);
864 luaL_newmetatable(L, "vis.file.text");
865 luaL_setfuncs(L, file_lines_funcs, 0);
866 luaL_newmetatable(L, "vis.window");
867 luaL_setfuncs(L, window_funcs, 0);
868 luaL_newmetatable(L, "vis.window.cursor");
869 luaL_setfuncs(L, window_cursor_funcs, 0);
870 /* vis module table with up value as the C pointer */
871 luaL_newmetatable(L, "vis");
872 luaL_setfuncs(L, vis_lua, 0);
873 obj_ref_new(L, vis, "vis");
874 lua_setglobal(L, "vis");
876 lua_getglobal(L, "require");
877 lua_pushstring(L, "visrc");
878 pcall(vis, L, 1, 0);
879 vis_lua_event(vis, "start");
880 if (lua_isfunction(L, -1))
881 pcall(vis, L, 0, 0);
882 lua_pop(L, 1);
885 void vis_lua_quit(Vis *vis) {
886 lua_State *L = vis->lua;
887 if (!L)
888 return;
889 vis_lua_event(vis, "quit");
890 if (lua_isfunction(L, -1))
891 pcall(vis, L, 0, 0);
892 lua_pop(L, 1);
893 lua_close(L);
896 void vis_lua_file_open(Vis *vis, File *file) {
900 void vis_lua_file_save(Vis *vis, File *file) {
904 void vis_lua_file_close(Vis *vis, File *file) {
905 lua_State *L = vis->lua;
906 vis_lua_event(vis, "file_close");
907 if (lua_isfunction(L, -1)) {
908 obj_ref_new(L, file, "vis.file");
909 pcall(vis, L, 1, 0);
911 obj_ref_free(L, file->text);
912 obj_ref_free(L, file);
913 lua_pop(L, 1);
916 void vis_lua_win_open(Vis *vis, Win *win) {
917 lua_State *L = vis->lua;
918 vis_lua_event(vis, "win_open");
919 if (lua_isfunction(L, -1)) {
920 obj_ref_new(L, win, "vis.window");
921 pcall(vis, L, 1, 0);
923 lua_pop(L, 1);
926 void vis_lua_win_close(Vis *vis, Win *win) {
927 lua_State *L = vis->lua;
928 vis_lua_event(vis, "win_close");
929 if (lua_isfunction(L, -1)) {
930 obj_ref_new(L, win, "vis.window");
931 pcall(vis, L, 1, 0);
933 obj_ref_free(L, win->view);
934 obj_ref_free(L, win);
935 lua_pop(L, 1);
938 bool vis_theme_load(Vis *vis, const char *name) {
939 lua_State *L = vis->lua;
940 if (!L)
941 return false;
942 /* package.loaded['themes/'..name] = nil
943 * require 'themes/'..name */
944 lua_pushstring(L, "themes/");
945 lua_pushstring(L, name);
946 lua_concat(L, 2);
947 lua_getglobal(L, "package");
948 lua_getfield(L, -1, "loaded");
949 lua_pushvalue(L, -3);
950 lua_pushnil(L);
951 lua_settable(L, -3);
952 lua_pop(L, 2);
953 lua_getglobal(L, "require");
954 lua_pushvalue(L, -2);
955 if (pcall(vis, L, 1, 0))
956 return false;
957 for (Win *win = vis->windows; win; win = win->next)
958 view_syntax_set(win->view, view_syntax_get(win->view));
959 return true;
962 #endif