2
* luah.c - Lua helper functions
4
* Copyright © 2010-2011 Mason Larobina <mason.larobina@gmail.com>
5
* Copyright © 2008-2009 Julien Danjou <julien@danjou.info>
7
* This program is free software: you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation, either version 3 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24
/* include clib headers */
25
#include "clib/download.h"
26
#include "clib/soup/soup.h"
27
#include "clib/sqlite3.h"
28
#include "clib/timer.h"
29
#include "clib/widget.h"
30
#include "clib/luakit.h"
36
luaH_modifier_table_push(lua_State *L, guint state) {
39
if (state & GDK_MODIFIER_MASK) {
41
#define MODKEY(key, name) \
42
if (state & GDK_##key##_MASK) { \
43
lua_pushstring(L, name); \
44
lua_rawseti(L, -2, i++); \
47
MODKEY(SHIFT, "Shift");
49
MODKEY(CONTROL, "Control");
62
luaH_keystr_push(lua_State *L, guint keyval)
66
guint32 ukval = gdk_keyval_to_unicode(keyval);
68
/* check for printable unicode character */
69
if (g_unichar_isgraph(ukval)) {
70
ulen = g_unichar_to_utf8(ukval, ucs);
72
lua_pushstring(L, ucs);
74
/* sent keysym for non-printable characters */
76
lua_pushstring(L, gdk_keyval_name(keyval));
79
/* UTF-8 aware string length computing.
80
* Returns the number of elements pushed on the stack. */
82
luaH_utf8_strlen(lua_State *L)
84
const gchar *cmd = luaL_checkstring(L, 1);
85
lua_pushnumber(L, (ssize_t) g_utf8_strlen(NONULL(cmd), -1));
89
/* Overload standard Lua next function to use __next key on metatable.
90
* Returns the number of elements pushed on stack. */
92
luaHe_next(lua_State *L)
94
if(luaL_getmetafield(L, 1, "__next")) {
96
lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
99
luaL_checktype(L, 1, LUA_TTABLE);
107
/* Overload lua_next() function by using __next metatable field to get
108
* next elements. `idx` is the index number of elements in stack.
109
* Returns 1 if more elements to come, 0 otherwise. */
111
luaH_mtnext(lua_State *L, gint idx)
113
if(luaL_getmetafield(L, idx, "__next")) {
114
/* if idx is relative, reduce it since we got __next */
116
/* copy table and then move key */
117
lua_pushvalue(L, idx);
118
lua_pushvalue(L, -3);
120
lua_pcall(L, 2, 2, 0);
121
/* next returned nil, it's the end */
122
if(lua_isnil(L, -1)) {
129
else if(lua_istable(L, idx))
130
return lua_next(L, idx);
136
/* Generic pairs function.
137
* Returns the number of elements pushed on stack. */
139
luaH_generic_pairs(lua_State *L)
141
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
142
lua_pushvalue(L, 1); /* state, */
143
lua_pushnil(L); /* and initial value */
147
/* Overload standard pairs function to use __pairs field of metatables.
148
* Returns the number of elements pushed on stack. */
150
luaHe_pairs(lua_State *L)
152
if(luaL_getmetafield(L, 1, "__pairs")) {
154
lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
155
return lua_gettop(L);
157
luaL_checktype(L, 1, LUA_TTABLE);
158
return luaH_generic_pairs(L);
162
luaH_ipairs_aux(lua_State *L)
164
gint i = luaL_checkint(L, 2) + 1;
165
luaL_checktype(L, 1, LUA_TTABLE);
166
lua_pushinteger(L, i);
167
lua_rawgeti(L, 1, i);
168
return (lua_isnil(L, -1)) ? 0 : 2;
171
/* Overload standard ipairs function to use __ipairs field of metatables.
172
* Returns the number of elements pushed on stack. */
174
luaHe_ipairs(lua_State *L)
176
if(luaL_getmetafield(L, 1, "__ipairs")) {
178
lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
179
return lua_gettop(L);
182
luaL_checktype(L, 1, LUA_TTABLE);
183
lua_pushvalue(L, lua_upvalueindex(1));
185
lua_pushinteger(L, 0); /* and initial value */
189
/* Enhanced type() function which recognize luakit objects.
190
* \param L The Lua VM state.
191
* \return The number of arguments pushed on the stack.
194
luaHe_type(lua_State *L)
197
lua_pushstring(L, luaH_typename(L, 1));
201
/* Fix up and add handy standard lib functions */
203
luaH_fixups(lua_State *L)
205
/* export string.wlen */
206
lua_getglobal(L, "string");
207
lua_pushcfunction(L, &luaH_utf8_strlen);
208
lua_setfield(L, -2, "wlen");
211
lua_pushliteral(L, "next");
212
lua_pushcfunction(L, luaHe_next);
213
lua_settable(L, LUA_GLOBALSINDEX);
215
lua_pushliteral(L, "pairs");
216
lua_pushcfunction(L, luaHe_next);
217
lua_pushcclosure(L, luaHe_pairs, 1); /* pairs get next as upvalue */
218
lua_settable(L, LUA_GLOBALSINDEX);
220
lua_pushliteral(L, "ipairs");
221
lua_pushcfunction(L, luaH_ipairs_aux);
222
lua_pushcclosure(L, luaHe_ipairs, 1);
223
lua_settable(L, LUA_GLOBALSINDEX);
225
lua_pushliteral(L, "type");
226
lua_pushcfunction(L, luaHe_type);
227
lua_settable(L, LUA_GLOBALSINDEX);
230
/* Look for an item: table, function, etc.
231
* \param L The Lua VM state.
232
* \param item The pointer item.
235
luaH_hasitem(lua_State *L, gconstpointer item)
238
while(luaH_mtnext(L, -2)) {
239
if(lua_topointer(L, -1) == item) {
240
/* remove value and key */
244
if(lua_istable(L, -1))
245
if(luaH_hasitem(L, item)) {
246
/* remove key and value */
256
/* Browse a table pushed on top of the index, and put all its table and
257
* sub-table ginto an array.
258
* \param L The Lua VM state.
259
* \param elems The elements array.
260
* \return False if we encounter an elements already in list.
263
luaH_isloop_check(lua_State *L, GPtrArray *elems)
265
if(lua_istable(L, -1)) {
266
gconstpointer object = lua_topointer(L, -1);
268
/* Check that the object table is not already in the list */
269
for(guint i = 0; i < elems->len; i++)
270
if(elems->pdata[i] == object)
273
/* push the table in the elements list */
274
g_ptr_array_add(elems, (gpointer) object);
276
/* look every object in the "table" */
278
while(luaH_mtnext(L, -2)) {
279
if(!luaH_isloop_check(L, elems)) {
280
/* remove key and value */
284
/* remove value, keep key for next iteration */
291
/* Check if a table is a loop. When using tables as direct acyclic digram,
293
* \param L The Lua VM state.
294
* \param idx The index of the table in the stack
295
* \return True if the table loops.
298
luaH_isloop(lua_State *L, gint idx)
300
/* elems is an elements array that we will fill with all array we
301
* encounter while browsing the tables */
302
GPtrArray *elems = g_ptr_array_new();
304
/* push table on top */
305
lua_pushvalue(L, idx);
307
gboolean ret = luaH_isloop_check(L, elems);
309
/* remove pushed table */
312
g_ptr_array_free(elems, TRUE);
318
luaH_panic(lua_State *L)
320
warn("unprotected error in call to Lua API (%s)", lua_tostring(L, -1));
325
luaH_dofunction_on_error(lua_State *L)
327
/* duplicate string error */
328
lua_pushvalue(L, -1);
329
/* emit error signal */
330
signal_object_emit(L, luakit_class.signals, "debug::error", 1, 0);
332
if(!luaL_dostring(L, "return debug.traceback(\"error while running function\", 3)"))
334
/* Move traceback before error */
336
/* Insert sentence */
337
lua_pushliteral(L, "\nerror: ");
338
/* Move it before error */
351
L = globalconf.L = luaL_newstate();
353
/* Set panic fuction */
354
lua_atpanic(L, luaH_panic);
356
/* Set error handling function */
357
lualib_dofunction_on_error = luaH_dofunction_on_error;
363
luaH_object_setup(L);
365
/* Export luakit lib */
368
/* Export soup lib */
372
widget_class_setup(L);
374
/* Export download */
375
download_class_setup(L);
378
sqlite3_class_setup(L);
381
timer_class_setup(L);
383
/* add Lua search paths */
384
lua_getglobal(L, "package");
385
if(LUA_TTABLE != lua_type(L, 1)) {
386
warn("package is not a table");
389
lua_getfield(L, 1, "path");
390
if(LUA_TSTRING != lua_type(L, 2)) {
391
warn("package.path is not a string");
396
/* compile list of package search paths */
397
GPtrArray *paths = g_ptr_array_new_with_free_func(g_free);
399
#if DEVELOPMENT_PATHS
400
/* allows for testing luakit in the project directory */
401
g_ptr_array_add(paths, g_strdup("./lib"));
402
g_ptr_array_add(paths, g_strdup("./config"));
405
/* add users config dir (see: XDG_CONFIG_DIR) */
406
g_ptr_array_add(paths, g_strdup(globalconf.config_dir));
408
/* add system config dirs (see: XDG_CONFIG_DIRS) */
409
const gchar* const *config_dirs = g_get_system_config_dirs();
410
for (; *config_dirs; config_dirs++)
411
g_ptr_array_add(paths, g_build_filename(*config_dirs, "luakit", NULL));
413
/* add luakit install path */
414
g_ptr_array_add(paths, g_build_filename(LUAKIT_INSTALL_PATH, "lib", NULL));
417
for (guint i = 0; i < paths->len; i++) {
418
path = paths->pdata[i];
419
/* Search for file */
420
lua_pushliteral(L, ";");
421
lua_pushstring(L, path);
422
lua_pushliteral(L, "/?.lua");
425
lua_pushliteral(L, ";");
426
lua_pushstring(L, path);
427
lua_pushliteral(L, "/?/init.lua");
429
/* concat with package.path */
433
g_ptr_array_free(paths, TRUE);
435
/* package.path = "concatenated string" */
436
lua_setfield(L, 1, "path");
438
/* remove package module from stack */
443
luaH_loadrc(const gchar *confpath, gboolean run)
445
debug("Loading rc: %s", confpath);
446
lua_State *L = globalconf.L;
447
if(!luaL_loadfile(L, confpath)) {
449
if(lua_pcall(L, 0, LUA_MULTRET, 0)) {
450
g_fprintf(stderr, "%s\n", lua_tostring(L, -1));
457
g_fprintf(stderr, "%s\n", lua_tostring(L, -1));
461
/* Load a configuration file. */
463
luaH_parserc(const gchar *confpath, gboolean run)
465
const gchar* const *config_dirs = NULL;
466
gboolean ret = FALSE;
467
GPtrArray *paths = NULL;
469
/* try to load, return if it's ok */
471
if(luaH_loadrc(confpath, run))
476
/* compile list of config search paths */
477
paths = g_ptr_array_new_with_free_func(g_free);
479
#if DEVELOPMENT_PATHS
480
/* allows for testing luakit in the project directory */
481
g_ptr_array_add(paths, g_strdup("./config/rc.lua"));
484
/* search users config dir (see: XDG_CONFIG_HOME) */
485
g_ptr_array_add(paths, g_build_filename(globalconf.config_dir, "rc.lua", NULL));
487
/* search system config dirs (see: XDG_CONFIG_DIRS) */
488
config_dirs = g_get_system_config_dirs();
489
for(; *config_dirs; config_dirs++)
490
g_ptr_array_add(paths, g_build_filename(*config_dirs, "luakit", "rc.lua", NULL));
493
for (guint i = 0; i < paths->len; i++) {
494
path = paths->pdata[i];
495
if (file_exists(path)) {
496
if(luaH_loadrc(path, run)) {
497
globalconf.confpath = g_strdup(path);
507
if (paths) g_ptr_array_free(paths, TRUE);
512
luaH_class_index_miss_property(lua_State *L, lua_object_t *obj)
515
signal_object_emit(L, luakit_class.signals, "debug::index::miss", 2, 0);
520
luaH_class_newindex_miss_property(lua_State *L, lua_object_t *obj)
523
signal_object_emit(L, luakit_class.signals, "debug::newindex::miss", 3, 0);
527
// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80