1 /* Copyright © 2007-2016 Evgeny Ratnikov
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <string.h>
18 #include <lua.h>
19 #include <lualib.h>
20 #include <lauxlib.h>
21 
22 #include "termit.h"
23 #include "termit_core_api.h"
24 #include "keybindings.h"
25 #include "configs.h"
26 #include "callbacks.h"
27 #include "lua_api.h"
28 
29 extern lua_State* L;
30 
termit_lua_load_table(lua_State * ls,TermitLuaTableLoaderFunc func,const int tableIndex,void * data)31 TermitLuaTableLoaderResult termit_lua_load_table(lua_State* ls, TermitLuaTableLoaderFunc func,
32         const int tableIndex, void* data)
33 {
34     if (!lua_istable(ls, tableIndex)) {
35         ERROR("not a table");
36         return TERMIT_LUA_TABLE_LOADER_FAILED;
37     }
38 
39     lua_pushnil(ls);
40     while (lua_next(ls, tableIndex) != 0) {
41         if (lua_isnumber(ls, tableIndex + 1)) {
42             func("0", ls, tableIndex + 2, data);
43         } else if (lua_isstring(ls, tableIndex + 1)) {
44             const char* name = lua_tostring(ls, tableIndex + 1);
45             func(name, ls, tableIndex + 2, data);
46         } else {
47             ERROR("neither number nor string value found - skipping");
48             lua_pop(ls, 1);
49         }
50         lua_pop(ls, 1);
51     }
52     return TERMIT_LUA_TABLE_LOADER_OK;
53 }
54 
55 
termit_lua_execute(const gchar * cmd)56 void termit_lua_execute(const gchar* cmd)
57 {
58     TRACE("executing script: %s", cmd);
59     int s = luaL_dostring(L, cmd);
60     termit_lua_report_error(__FILE__, __LINE__, s);
61 }
62 
termit_lua_report_error(const char * file,int line,int status)63 void termit_lua_report_error(const char* file, int line, int status)
64 {
65     if (status == 0) {
66         return;
67     }
68     g_fprintf(stderr, "%s:%d %s\n", file, line, lua_tostring(L, -1));
69     lua_pop(L, 1);
70 }
71 
termit_lua_setOptions(lua_State * ls)72 static int termit_lua_setOptions(lua_State* ls)
73 {
74     termit_lua_load_table(ls, termit_lua_options_loader, 1, &configs);
75     if (configs.default_tabs) {
76         guint i = 0;
77         for (; i < configs.default_tabs->len; ++i) {
78             struct TabInfo* ti = &g_array_index(configs.default_tabs, struct TabInfo, i);
79             termit_append_tab_with_details(ti);
80             g_free(ti->name);
81             g_strfreev(ti->argv);
82             g_free(ti->encoding);
83             g_free(ti->working_dir);
84         }
85         g_array_free(configs.default_tabs, TRUE);
86         configs.default_tabs = NULL;
87     }
88     return 0;
89 }
90 
termit_lua_dofunction(int f)91 int termit_lua_dofunction(int f)
92 {
93     lua_State* ls = L;
94     if(f != LUA_REFNIL) {
95         lua_rawgeti(ls, LUA_REGISTRYINDEX, f);
96         if (lua_pcall(ls, 0, 0, 0)) {
97             TRACE("error running function (%d): %s", f, lua_tostring(ls, -1));
98             lua_pop(ls, 1);
99             return 0;
100         }
101         return 1;
102     }
103     return 0;
104 }
105 
termit_lua_dofunction2(int f,const char * arg1)106 int termit_lua_dofunction2(int f, const char* arg1)
107 {
108     lua_State* ls = L;
109     if(f != LUA_REFNIL) {
110         lua_rawgeti(ls, LUA_REGISTRYINDEX, f);
111         lua_pushstring(ls, arg1);
112         if (lua_pcall(ls, 1, 0, 0)) {
113             TRACE("error running function (%d): %s", f, lua_tostring(ls, -1));
114             lua_pop(ls, 1);
115             return 0;
116         }
117         return 1;
118     }
119     return 0;
120 }
121 
termit_lua_domatch(int f,const gchar * matchedText)122 int termit_lua_domatch(int f, const gchar* matchedText)
123 {
124     lua_State* ls = L;
125     if(f != LUA_REFNIL) {
126         lua_rawgeti(ls, LUA_REGISTRYINDEX, f);
127         lua_pushstring(ls, matchedText);
128         if (lua_pcall(ls, 1, 0, 0)) {
129             TRACE("error running function (%d: %s): %s", f, matchedText, lua_tostring(ls, -1));
130             lua_pop(ls, 1);
131             return 0;
132         }
133         return 1;
134     }
135     return 0;
136 }
137 
termit_lua_unref(int * lua_callback)138 void termit_lua_unref(int* lua_callback)
139 {
140     if (*lua_callback) {
141         luaL_unref(L, LUA_REGISTRYINDEX, *lua_callback);
142         *lua_callback = 0;
143     }
144 }
145 
termit_lua_getStatusbarCallback(int f,guint page)146 gchar* termit_lua_getStatusbarCallback(int f, guint page)
147 {
148     lua_State* ls = L;
149     if(f != LUA_REFNIL) {
150         lua_rawgeti(ls, LUA_REGISTRYINDEX, f);
151         lua_pushnumber(ls, page);
152         if (lua_pcall(ls, 1, 1, 0)) {
153             TRACE("error running function: %s", lua_tostring(ls, -1));
154             lua_pop(ls, 1);
155             return NULL;
156         }
157         if (lua_isstring(ls, -1)) {
158             return g_strdup(lua_tostring(ls, -1));
159         }
160     }
161     return NULL;
162 }
163 
termit_lua_getTitleCallback(int f,const gchar * title)164 gchar* termit_lua_getTitleCallback(int f, const gchar* title)
165 {
166     lua_State* ls = L;
167     if(f != LUA_REFNIL) {
168         lua_rawgeti(ls, LUA_REGISTRYINDEX, f);
169         lua_pushstring(ls, title);
170         if (lua_pcall(ls, 1, 1, 0)) {
171             TRACE("error running function: %s", lua_tostring(ls, -1));
172             lua_pop(ls, 1);
173             return NULL;
174         }
175         if (lua_isstring(ls, -1)) {
176             return g_strdup(lua_tostring(ls, -1));
177         }
178     }
179     return NULL;
180 }
181 
termit_lua_bindKey(lua_State * ls)182 static int termit_lua_bindKey(lua_State* ls)
183 {
184     TRACE_MSG(__FUNCTION__);
185     if (lua_isnil(ls, 1)) {
186         TRACE_MSG("nil args: skipping");
187     } else if (!lua_isstring(ls, 1)) {
188         TRACE_MSG("bad args: skipping");
189     } else if (lua_isnil(ls, 2)) {
190         const char* keybinding = lua_tostring(ls, 1);
191         termit_keys_unbind(keybinding);
192         TRACE("unbindKey: %s", keybinding);
193     } else if (lua_isfunction(ls, 2)) {
194         const char* keybinding = lua_tostring(ls, 1);
195         int func = luaL_ref(ls, LUA_REGISTRYINDEX);
196         termit_keys_bind(keybinding, func);
197         TRACE("bindKey: %s - %d", keybinding, func);
198     }
199     return 0;
200 }
201 
termit_lua_bindMouse(lua_State * ls)202 static int termit_lua_bindMouse(lua_State* ls)
203 {
204     if (lua_isnil(ls, 1)) {
205         TRACE_MSG("nil args: skipping");
206     } else if (!lua_isstring(ls, 1)) {
207         TRACE_MSG("bad args: skipping");
208     } else if (lua_isnil(ls, 2)) {
209         const char* mousebinding = lua_tostring(ls, 1);
210         termit_mouse_unbind(mousebinding);
211         TRACE("unbindMouse: %s", mousebinding);
212     } else if (lua_isfunction(ls, 2)) {
213         const char* mousebinding = lua_tostring(ls, 1);
214         int func = luaL_ref(ls, LUA_REGISTRYINDEX);
215         termit_mouse_bind(mousebinding, func);
216         TRACE("bindMouse: %s - %d", mousebinding, func);
217     }
218     return 0;
219 }
220 
termit_lua_toggleMenubar(lua_State * ls)221 static int termit_lua_toggleMenubar(lua_State* ls)
222 {
223     termit_toggle_menubar();
224     return 0;
225 }
226 
termit_lua_toggleTabbar(lua_State * ls)227 static int termit_lua_toggleTabbar(lua_State* ls)
228 {
229     termit_toggle_tabbar();
230     return 0;
231 }
232 
termit_lua_tab_loader(const gchar * name,lua_State * ls,int index,void * data)233 void termit_lua_tab_loader(const gchar* name, lua_State* ls, int index, void* data)
234 {
235     struct TabInfo* ti = (struct TabInfo*)data;
236     if (strcmp(name, "title") == 0) {
237         termit_config_get_string(&ti->name, ls, index);
238     } else if (strcmp(name, "command") == 0) {
239         if (ti->argv == NULL) {
240             ti->argv = (gchar**)g_new0(gchar*, 2);
241         }
242         termit_config_get_string(&ti->argv[0], ls, index);
243     } else if (strcmp(name, "encoding") == 0) {
244         termit_config_get_string(&ti->encoding, ls, index);
245     } else if (strcmp(name, "backspaceBinding") == 0) {
246         termit_config_get_erase_binding(&ti->bksp_binding, ls, index);
247     } else if (strcmp(name, "deleteBinding") == 0) {
248         termit_config_get_erase_binding(&ti->delete_binding, ls, index);
249     } else if (strcmp(name, "cursorBlinkMode") == 0) {
250         termit_config_get_cursor_blink_mode(&ti->cursor_blink_mode, ls, index);
251     } else if (strcmp(name, "cursorShape") == 0) {
252         termit_config_get_cursor_shape(&ti->cursor_shape, ls, index);
253     } else if (strcmp(name, "workingDir") == 0) {
254         termit_config_get_string(&ti->working_dir, ls, index);
255     }
256 }
257 
termit_lua_nextTab(lua_State * ls)258 static int termit_lua_nextTab(lua_State* ls)
259 {
260     TRACE_MSG(__FUNCTION__);
261     termit_next_tab();
262     return 0;
263 }
264 
termit_lua_prevTab(lua_State * ls)265 static int termit_lua_prevTab(lua_State* ls)
266 {
267     TRACE_MSG(__FUNCTION__);
268     termit_prev_tab();
269     return 0;
270 }
271 
termit_lua_copy(lua_State * ls)272 static int termit_lua_copy(lua_State* ls)
273 {
274     TRACE_MSG(__FUNCTION__);
275     termit_copy();
276     return 0;
277 }
278 
termit_lua_paste(lua_State * ls)279 static int termit_lua_paste(lua_State* ls)
280 {
281     TRACE_MSG(__FUNCTION__);
282     termit_paste();
283     return 0;
284 }
285 
termit_lua_openTab(lua_State * ls)286 static int termit_lua_openTab(lua_State* ls)
287 {
288     TRACE_MSG(__FUNCTION__);
289     if (lua_istable(ls, 1)) {
290         struct TabInfo ti = {};
291         if (termit_lua_load_table(ls, termit_lua_tab_loader, 1, &ti)
292                 != TERMIT_LUA_TABLE_LOADER_OK) {
293             ERROR("openTab failed");
294             return 0;
295         }
296         termit_append_tab_with_details(&ti);
297         g_free(ti.name);
298         g_strfreev(ti.argv);
299         g_free(ti.encoding);
300         g_free(ti.working_dir);
301     } else {
302         termit_append_tab();
303     }
304     return 0;
305 }
306 
termit_lua_closeTab(lua_State * ls)307 static int termit_lua_closeTab(lua_State* ls)
308 {
309     TRACE_FUNC;
310     termit_close_tab();
311     return 0;
312 }
313 
termit_lua_setKbPolicy(lua_State * ls)314 static int termit_lua_setKbPolicy(lua_State* ls)
315 {
316     if (lua_isnil(ls, 1)) {
317         TRACE_MSG("no kbPolicy defined: skipping");
318         return 0;
319     } else if (!lua_isstring(ls, 1)) {
320         TRACE_MSG("kbPolicy is not string: skipping");
321         return 0;
322     }
323     const gchar* val = lua_tostring(ls, 1);
324     TRACE("setKbPolicy: %s", val);
325     if (!strcmp(val, "keycode")) {
326         termit_set_kb_policy(TermitKbUseKeycode);
327     } else if (!strcmp(val, "keysym")) {
328         termit_set_kb_policy(TermitKbUseKeysym);
329     } else {
330         ERROR("unknown kbPolicy: %s", val);
331     }
332     return 0;
333 }
334 
menuItemLoader(const gchar * name,lua_State * ls,int index,void * data)335 static void menuItemLoader(const gchar* name, lua_State* ls, int index, void* data)
336 {
337     struct UserMenuItem* umi = (struct UserMenuItem*)data;
338     if (!strcmp(name, "name") && lua_isstring(ls, index)) {
339         const gchar* value = lua_tostring(ls, index);
340         umi->name = g_strdup(value);
341     } else if (!strcmp(name, "action") && lua_isfunction(ls, index)) {
342         umi->lua_callback = luaL_ref(ls, LUA_REGISTRYINDEX);
343         lua_pushnil(ls); // luaL_ref pops value so we restore stack size
344     } else if (!strcmp(name, "accel") && lua_isstring(ls, index)) {
345         const gchar* value = lua_tostring(ls, index);
346         umi->accel = g_strdup(value);
347     }
348 }
349 
menuLoader(const gchar * name,lua_State * ls,int index,void * data)350 static void menuLoader(const gchar* name, lua_State* ls, int index, void* data)
351 {
352     struct UserMenu* um = (struct UserMenu*)data;
353     if (lua_istable(ls, index)) {
354         struct UserMenuItem umi = {};
355         if (termit_lua_load_table(ls, menuItemLoader, index, &umi) == TERMIT_LUA_TABLE_LOADER_OK) {
356             g_array_append_val(um->items, umi);
357         } else {
358             ERROR("failed to load item: %s.%s", name, lua_tostring(ls, 3));
359         }
360     } else {
361         ERROR("unknown type instead if menu table: skipping");
362         lua_pop(ls, 1);
363     }
364 }
365 
loadMenu(lua_State * ls,GArray * menus)366 static int loadMenu(lua_State* ls, GArray* menus)
367 {
368     if (lua_isnil(ls, 1) || lua_isnil(ls, 2)) {
369         TRACE_MSG("menu not defined: skipping");
370         return -1;
371     } else if (!lua_istable(ls, 1) || !lua_isstring(ls, 2)) {
372         TRACE_MSG("menu is not table: skipping");
373         return -1;
374     }
375     struct UserMenu um = {};
376     um.name = g_strdup(lua_tostring(ls, 2));
377     lua_pop(ls, 1);
378     um.items = g_array_new(FALSE, TRUE, sizeof(struct UserMenuItem));
379     if (termit_lua_load_table(ls, menuLoader, 1, &um) != TERMIT_LUA_TABLE_LOADER_OK) {
380         ERROR("addMenu failed");
381     }
382     if (um.items->len > 0) {
383         g_array_append_val(menus, um);
384     } else {
385         g_free(um.name);
386         g_array_free(um.items, TRUE);
387     }
388     return 0;
389 }
390 
termit_lua_addMenu(lua_State * ls)391 static int termit_lua_addMenu(lua_State* ls)
392 {
393     if (loadMenu(ls, configs.user_menus) < 0) {
394         ERROR("addMenu failed");
395     }
396     return 0;
397 }
398 
termit_lua_addPopupMenu(lua_State * ls)399 static int termit_lua_addPopupMenu(lua_State* ls)
400 {
401     if (loadMenu(ls, configs.user_popup_menus) < 0) {
402         ERROR("addMenu failed");
403     }
404     return 0;
405 }
406 
termit_lua_setColormap(lua_State * ls)407 static int termit_lua_setColormap(lua_State* ls)
408 {
409     const gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(termit.notebook));
410     TERMIT_GET_TAB_BY_INDEX(pTab, page, return 0);
411     termit_lua_load_colormap(ls, 1, &pTab->style.colors, &pTab->style.colors_size);
412     termit_tab_apply_colors(pTab);
413     return 0;
414 }
415 
termit_lua_setEncoding(lua_State * ls)416 static int termit_lua_setEncoding(lua_State* ls)
417 {
418     if (lua_isnil(ls, 1)) {
419         TRACE_MSG("no encoding defined: skipping");
420         return 0;
421     } else if (!lua_isstring(ls, 1)) {
422         TRACE_MSG("encoding is not string: skipping");
423         return 0;
424     }
425     const gchar* val = lua_tostring(ls, 1);
426     termit_set_encoding(val);
427     return 0;
428 }
429 
termit_lua_activateTab(lua_State * ls)430 static int termit_lua_activateTab(lua_State* ls)
431 {
432     if (lua_isnil(ls, 1)) {
433         TRACE_MSG("no tabNum defined: skipping");
434         return 0;
435     } else if (!lua_isnumber(ls, 1)) {
436         TRACE_MSG("tabNum is not number: skipping");
437         return 0;
438     }
439     int tab_index =  lua_tointeger(ls, 1);
440     termit_activate_tab(tab_index - 1);
441     return 0;
442 }
443 
termit_lua_currentTab(lua_State * ls)444 static int termit_lua_currentTab(lua_State* ls)
445 {
446     return termit_lua_fill_tab(termit_get_current_tab_index(), ls);
447 }
448 
termit_lua_currentTabIndex(lua_State * ls)449 static int termit_lua_currentTabIndex(lua_State* ls)
450 {
451     lua_pushinteger(ls, termit_get_current_tab_index() + 1);
452     return 1;
453 }
454 
termit_lua_loadSessionDialog(lua_State * ls)455 static int termit_lua_loadSessionDialog(lua_State* ls)
456 {
457     termit_on_load_session();
458     return 0;
459 }
460 
termit_lua_saveSessionDialog(lua_State * ls)461 static int termit_lua_saveSessionDialog(lua_State* ls)
462 {
463     termit_on_save_session();
464     return 0;
465 }
466 
termit_lua_preferencesDialog(lua_State * ls)467 static int termit_lua_preferencesDialog(lua_State* ls)
468 {
469     termit_on_edit_preferences();
470     return 0;
471 }
472 
termit_lua_setTabTitleDialog(lua_State * ls)473 static int termit_lua_setTabTitleDialog(lua_State* ls)
474 {
475     termit_on_set_tab_name();
476     return 0;
477 }
478 
termit_lua_setTabPos(lua_State * ls)479 static int termit_lua_setTabPos(lua_State* ls)
480 {
481     if (lua_isnil(ls, 1)) {
482         TRACE_MSG("no tabNum defined: skipping");
483         return 0;
484     } else if (!lua_isnumber(ls, 1)) {
485         TRACE_MSG("tabNum is not number: skipping");
486         return 0;
487     }
488     int tab_index =  lua_tointeger(ls, 1);
489     gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(termit.notebook));
490     TERMIT_GET_TAB_BY_INDEX(pTab, page, return 0);
491     termit_tab_set_pos(pTab, tab_index - 1);
492     return 0;
493 }
494 
termit_lua_setTabTitle(lua_State * ls)495 static int termit_lua_setTabTitle(lua_State* ls)
496 {
497     if (lua_isnil(ls, 1)) {
498         TRACE_MSG("no tabName defined: skipping");
499         return 0;
500     } else if (!lua_isstring(ls, 1)) {
501         TRACE_MSG("tabName is not string: skipping");
502         return 0;
503     }
504     const gchar* val = lua_tostring(ls, 1);
505     gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(termit.notebook));
506     TERMIT_GET_TAB_BY_INDEX(pTab, page, return 0);
507     termit_tab_set_title(pTab, val);
508     pTab->custom_tab_name = TRUE;
509     return 0;
510 }
511 
termit_lua_setWindowTitle(lua_State * ls)512 static int termit_lua_setWindowTitle(lua_State* ls)
513 {
514     if (lua_isnil(ls, 1)) {
515         TRACE_MSG("no title defined: skipping");
516         return 0;
517     } else if (!lua_isstring(ls, 1)) {
518         TRACE_MSG("title is not string: skipping");
519         return 0;
520     }
521     const gchar* val = lua_tostring(ls, 1);
522     termit_set_window_title(val);
523     return 0;
524 }
525 
termit_lua_setTabColor__(lua_State * ls,void (* callback)(gint,const GdkRGBA *))526 static int termit_lua_setTabColor__(lua_State* ls, void (*callback)(gint, const GdkRGBA*))
527 {
528     if (lua_isnil(ls, 1)) {
529         TRACE_MSG("no color defined: skipping");
530         return 0;
531     } else if (!lua_isstring(ls, 1)) {
532         TRACE_MSG("color is not string: skipping");
533         return 0;
534     }
535     const gchar* val = lua_tostring(ls, 1);
536     GdkRGBA color;
537     if (gdk_rgba_parse(&color, val) == TRUE) {
538         callback(-1, &color);
539     }
540     return 0;
541 }
542 
termit_lua_setTabForegroundColor(lua_State * ls)543 static int termit_lua_setTabForegroundColor(lua_State* ls)
544 {
545     return termit_lua_setTabColor__(ls, &termit_tab_set_color_foreground_by_index);
546 }
547 
termit_lua_setTabBackgroundColor(lua_State * ls)548 static int termit_lua_setTabBackgroundColor(lua_State* ls)
549 {
550     return termit_lua_setTabColor__(ls, &termit_tab_set_color_background_by_index);
551 }
552 
termit_lua_setTabFont(lua_State * ls)553 static int termit_lua_setTabFont(lua_State* ls)
554 {
555     if (lua_isnil(ls, 1)) {
556         TRACE_MSG("no font defined: skipping");
557         return 0;
558     } else if (!lua_isstring(ls, 1)) {
559         TRACE_MSG("font is not string: skipping");
560         return 0;
561     }
562     const gchar* val = lua_tostring(ls, 1);
563     termit_tab_set_font_by_index(-1, val);
564     return 0;
565 }
566 
termit_lua_spawn(lua_State * ls)567 static int termit_lua_spawn(lua_State* ls)
568 {
569     if (lua_isnil(ls, 1)) {
570         TRACE_MSG("no command defined: skipping");
571         return 0;
572     } else if (!lua_isstring(ls, 1)) {
573         TRACE_MSG("command is not string: skipping");
574         return 0;
575     }
576     GError *err = NULL;
577     const gchar* val = lua_tostring(ls, 1);
578     g_spawn_command_line_async(val, &err);
579     return 0;
580 }
581 
termit_lua_forEachRow(lua_State * ls)582 static int termit_lua_forEachRow(lua_State* ls)
583 {
584     if (lua_isnil(ls, 1)) {
585         TRACE_MSG("no function defined: skipping");
586         return 0;
587     } else if (!lua_isfunction(ls, 1)) {
588         TRACE_MSG("1 arg is not function: skipping");
589         return 0;
590     }
591     int func = luaL_ref(ls, LUA_REGISTRYINDEX);
592     termit_for_each_row(func);
593     termit_lua_unref(&func);
594     return 0;
595 }
596 
termit_lua_forEachVisibleRow(lua_State * ls)597 static int termit_lua_forEachVisibleRow(lua_State* ls)
598 {
599     if (lua_isnil(ls, 1)) {
600         TRACE_MSG("no function defined: skipping");
601         return 0;
602     } else if (!lua_isfunction(ls, 1)) {
603         TRACE_MSG("1 arg is not function: skipping");
604         return 0;
605     }
606     int func = luaL_ref(ls, LUA_REGISTRYINDEX);
607     termit_for_each_visible_row(func);
608     termit_lua_unref(&func);
609     return 0;
610 }
611 
termit_lua_feed(lua_State * ls)612 static int termit_lua_feed(lua_State* ls)
613 {
614     if (lua_isnil(ls, 1)) {
615         TRACE_MSG("no data defined: skipping");
616         return 0;
617     } else if (!lua_isstring(ls, 1)) {
618         TRACE_MSG("data is not string: skipping");
619         return 0;
620     }
621     const gchar* val = lua_tostring(ls, 1);
622     gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(termit.notebook));
623     TERMIT_GET_TAB_BY_INDEX(pTab, page, return 0);
624     termit_tab_feed(pTab, val);
625     return 0;
626 }
627 
termit_lua_feedChild(lua_State * ls)628 static int termit_lua_feedChild(lua_State* ls)
629 {
630     if (lua_isnil(ls, 1)) {
631         TRACE_MSG("no data defined: skipping");
632         return 0;
633     } else if (!lua_isstring(ls, 1)) {
634         TRACE_MSG("data is not string: skipping");
635         return 0;
636     }
637     const gchar* val = lua_tostring(ls, 1);
638     gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(termit.notebook));
639     TERMIT_GET_TAB_BY_INDEX(pTab, page, return 0);
640     termit_tab_feed_child(pTab, val);
641     return 0;
642 }
643 
termit_lua_findNext(lua_State * ls)644 static int termit_lua_findNext(lua_State* ls)
645 {
646     termit_search_find_next();
647     return 0;
648 }
649 
termit_lua_findPrev(lua_State * ls)650 static int termit_lua_findPrev(lua_State* ls)
651 {
652     termit_search_find_prev();
653     return 0;
654 }
655 
termit_lua_findDlg(lua_State * ls)656 static int termit_lua_findDlg(lua_State* ls)
657 {
658     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(termit.b_toggle_search), TRUE);
659     return 0;
660 }
661 
termit_lua_selection(lua_State * ls)662 static int termit_lua_selection(lua_State* ls)
663 {
664     gchar* buff = termit_get_selection();
665     if (!buff) {
666         return 0;
667     }
668     lua_pushstring(ls, buff);
669     g_free(buff);
670     return 1;
671 }
672 
termit_lua_reconfigure(lua_State * ls)673 static int termit_lua_reconfigure(lua_State* ls)
674 {
675     termit_reconfigure();
676     termit_config_trace();
677     return 0;
678 }
679 
termit_lua_quit(lua_State * ls)680 static int termit_lua_quit(lua_State* ls)
681 {
682     termit_on_exit();
683     return 0;
684 }
685 
686 struct TermitLuaFunction
687 {
688     const char* lua_func_name;
689     lua_CFunction c_func;
690     int lua_func;
691 } functions[] = {
692     {"activateTab", termit_lua_activateTab, 0},
693     {"addMenu", termit_lua_addMenu, 0},
694     {"addPopupMenu", termit_lua_addPopupMenu, 0},
695     {"bindKey", termit_lua_bindKey, 0},
696     {"bindMouse", termit_lua_bindMouse, 0},
697     {"closeTab", termit_lua_closeTab, 0},
698     {"copy", termit_lua_copy, 0},
699     {"currentTab", termit_lua_currentTab, 0},
700     {"currentTabIndex", termit_lua_currentTabIndex, 0},
701     {"feed", termit_lua_feed, 0},
702     {"feedChild", termit_lua_feedChild, 0},
703     {"findDlg", termit_lua_findDlg, 0},
704     {"findNext", termit_lua_findNext, 0},
705     {"findPrev", termit_lua_findPrev, 0},
706     {"forEachRow", termit_lua_forEachRow, 0},
707     {"forEachVisibleRow", termit_lua_forEachVisibleRow, 0},
708     {"loadSessionDlg", termit_lua_loadSessionDialog, 0},
709     {"nextTab", termit_lua_nextTab, 0},
710     {"openTab", termit_lua_openTab, 0},
711     {"paste", termit_lua_paste, 0},
712     {"preferencesDlg", termit_lua_preferencesDialog, 0},
713     {"prevTab", termit_lua_prevTab, 0},
714     {"quit", termit_lua_quit, 0},
715     {"reconfigure", termit_lua_reconfigure, 0},
716     {"saveSessionDlg", termit_lua_saveSessionDialog, 0},
717     {"selection", termit_lua_selection, 0},
718     {"setColormap", termit_lua_setColormap, 0},
719     {"setEncoding", termit_lua_setEncoding, 0},
720     {"setKbPolicy", termit_lua_setKbPolicy, 0},
721     {"setOptions", termit_lua_setOptions, 0},
722     {"setTabBackgroundColor", termit_lua_setTabBackgroundColor, 0},
723     {"setTabFont", termit_lua_setTabFont, 0},
724     {"setTabForegroundColor", termit_lua_setTabForegroundColor, 0},
725     {"setTabPos", termit_lua_setTabPos, 0},
726     {"setTabTitle", termit_lua_setTabTitle, 0},
727     {"setTabTitleDlg", termit_lua_setTabTitleDialog, 0},
728     {"setWindowTitle", termit_lua_setWindowTitle, 0},
729     {"spawn", termit_lua_spawn, 0},
730     {"toggleMenubar", termit_lua_toggleMenubar, 0},
731     {"toggleTabbar", termit_lua_toggleTabbar, 0}
732 };
733 
termit_get_lua_func(const char * name)734 int termit_get_lua_func(const char* name)
735 {
736     unsigned short i = 0;
737     for (; i < sizeof(functions)/sizeof(functions[0]); ++i) {
738         if (strcmp(name, functions[i].lua_func_name) == 0) {
739             return functions[i].lua_func;
740         }
741     }
742     ERROR("not found lua function by name [%s]", name);
743     return 0;
744 }
745 
746 
termit_lua_init_api()747 void termit_lua_init_api()
748 {
749     unsigned short i = 0;
750     for (; i < sizeof(functions)/sizeof(functions[0]); ++i) {
751         lua_pushcfunction(L, functions[i].c_func);
752         functions[i].lua_func = luaL_ref(L, LUA_REGISTRYINDEX);
753         lua_rawgeti(L, LUA_REGISTRYINDEX, functions[i].lua_func);
754         lua_setglobal(L, functions[i].lua_func_name);
755         TRACE("%s [%d]", functions[i].lua_func_name, functions[i].lua_func);
756     }
757 }
758