summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--README12
-rw-r--r--configure.ac130
-rw-r--r--libpeas/peas-engine.c12
-rw-r--r--libpeas/peas-utils.c3
-rw-r--r--libpeas/peas-utils.h2
-rw-r--r--loaders/Makefile.am4
-rw-r--r--loaders/lua5.1/Makefile.am31
-rw-r--r--loaders/lua5.1/peas-plugin-loader-lua-utils.c122
-rw-r--r--loaders/lua5.1/peas-plugin-loader-lua-utils.h42
-rw-r--r--loaders/lua5.1/peas-plugin-loader-lua.c404
-rw-r--r--loaders/lua5.1/peas-plugin-loader-lua.h60
-rw-r--r--peas-demo/peas-demo.c1
-rw-r--r--peas-demo/plugins/Makefile.am4
-rw-r--r--peas-demo/plugins/luahello/Makefile.am8
-rw-r--r--peas-demo/plugins/luahello/luahello.lua50
-rw-r--r--peas-demo/plugins/luahello/luahello.plugin7
-rw-r--r--tests/libpeas/Makefile.am7
-rw-r--r--tests/libpeas/extension-lua.c213
-rw-r--r--tests/libpeas/plugins/Makefile.am5
-rw-r--r--tests/libpeas/plugins/extension-lua/Makefile.am7
-rw-r--r--tests/libpeas/plugins/extension-lua/extension-lua51.gschema.xml9
-rw-r--r--tests/libpeas/plugins/extension-lua/extension-lua51.lua91
-rw-r--r--tests/libpeas/plugins/extension-lua/extension-lua51.plugin7
-rw-r--r--tests/libpeas/plugins/extension-lua51-nonexistent.plugin7
-rw-r--r--tests/libpeas/testing/testing-extension.c13
26 files changed, 1241 insertions, 11 deletions
diff --git a/.gitignore b/.gitignore
index 070467b..e7ae5cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -78,6 +78,7 @@ Makefile.in
/tests/*/vgdump-*
/tests/libpeas/engine
/tests/libpeas/extension-c
+/tests/libpeas/extension-lua51
/tests/libpeas/extension-python
/tests/libpeas/extension-python3
/tests/libpeas/extension-set
diff --git a/README b/README
index c7f92cc..3183089 100644
--- a/README
+++ b/README
@@ -20,11 +20,11 @@ GInterfaces the plugin writer will be able to implement as his plugin requires.
On-demand programming language support
--------------------------------------
-libpeas comes with a set of supported languages (currently, C, Python 2 and
-Python 3). Those languages are supported through “loaders” which are loaded
-on demand. What it means is that you only pay for what you use: if you have no
-Python plugin, the Python interpreter won't be loaded in memory. Of course, the
-same goes for the C loader.
+libpeas comes with a set of supported languages (currently, C, Lua 5.1,
+Python 2 and Python 3). Those languages are supported through “loaders” which
+are loaded on demand. What it means is that you only pay for what you use: if
+you have no Python plugin, the Python interpreter won't be loaded in memory.
+Of course, the same goes for the C loader.
Damn simple to use (or at least we try hard)
--------------------------------------------
@@ -82,7 +82,7 @@ Sample code
-----------
The libpeas package contains a sample application called peas-demo, and sample
-plugins written in C and Python.
+plugins written in C, Lua and Python.
The global idea is this one: you create a new PeasEngine instance and give it
the information needed for it to find your plugins. Then you load some plugins
diff --git a/configure.ac b/configure.ac
index bcd3d33..1786f09 100644
--- a/configure.ac
+++ b/configure.ac
@@ -232,6 +232,130 @@ fi
AM_CONDITIONAL([ENABLE_GLADE_CATALOG],[test "x$found_glade_catalog" = "xyes"])
dnl ================================================================
+dnl Lua
+dnl ================================================================
+
+LUA51_REQUIRED=5.1.0
+LUAJIT_REQUIRED=2.0
+
+LGI_MAJOR_VERSION=0
+LGI_MINOR_VERSION=8
+LGI_MICRO_VERSION=0
+LGI_REQUIRED=$LGI_MAJOR_VERSION.$LGI_MINOR_VERSION.$LGI_MICRO_VERSION
+AC_DEFINE_UNQUOTED(LGI_MAJOR_VERSION, [$LGI_MAJOR_VERSION], [LGI major version.])
+AC_DEFINE_UNQUOTED(LGI_MINOR_VERSION, [$LGI_MINOR_VERSION], [LGI minor version.])
+AC_DEFINE_UNQUOTED(LGI_MICRO_VERSION, [$LGI_MICRO_VERSION], [LGI micro version.])
+
+dnl
+dnl Test program for LGI version
+dnl
+m4_define([peas_lgi_version_test], [
+#include <lauxlib.h>
+#include <lualib.h>
+
+#include "peas-plugin-loader-lua-utils.c"
+
+int main(int argc, char **argv)
+{
+ lua_State *L;
+ gboolean success;
+
+ L = luaL_newstate ();
+ luaL_openlibs (L);
+
+ success = (peas_lua_utils_require (L, "lgi") &&
+ peas_lua_utils_check_version (L,
+ LGI_MAJOR_VERSION,
+ LGI_MINOR_VERSION,
+ LGI_MICRO_VERSION));
+
+ lua_close (L);
+ return success ? 0 : 1;
+}])
+
+AC_ARG_ENABLE(lua5.1,
+ AS_HELP_STRING([--enable-lua5.1],[Enable Lua 5.1 support]),
+ [enable_lua51=$enableval],
+ [enable_lua51=auto])
+
+AC_ARG_ENABLE(luajit,
+ AS_HELP_STRING([--enable-luajit],[Enable LuaJIT for Lua 5.1 support]),
+ [enable_luajit=$enableval],
+ [enable_luajit=auto])
+
+AC_MSG_CHECKING([for Lua 5.1 availability.])
+
+if test "x$enable_lua51" = "xno"; then
+ found_lua51="no (disabled, use --enable-lua5.1 to enable)"
+ AC_MSG_RESULT([$found_lua51])
+else
+ if test "x$enable_luajit" != "xno"; then
+ PKG_CHECK_EXISTS([luajit >= $LUAJIT_REQUIRED], [
+ found_lua51=yes
+ with_lua51=luajit
+ ], [
+ found_lua51=no
+ ])
+
+ if test "x$enable_luajit" = "xyes" -a "x$found_lua51" = "xno"; then
+ AC_MSG_ERROR([You need to have LuaJIT >= $LUAJIT_REQUIRED
+ installed to build libpeas])
+ fi
+ fi
+
+ if test "x$found_lua51" != "xyes"; then
+ PKG_CHECK_EXISTS([lua5.1 >= $LUA51_REQUIRED], [
+ found_lua51=yes
+ with_lua51=lua5.1
+ ], [
+ found_lua51=no
+ ])
+
+ if test "x$enable_lua51" = "xyes" -a "x$found_lua51" = "xno"; then
+ AC_MSG_ERROR([You need to have Lua 5.1 >= $LUA51_REQUIRED
+ installed to build libpeas])
+ fi
+ fi
+
+ if test "x$found_lua51" != "xyes"; then
+ AC_MSG_RESULT([$found_lua51])
+ else
+ AC_MSG_RESULT([$found_lua51 ($with_lua51)])
+
+ LUA51_CFLAGS=`$PKG_CONFIG --cflags $with_lua51`
+ LUA51_LIBS=`$PKG_CONFIG --libs $with_lua51`
+ AC_SUBST(LUA51_CFLAGS)
+ AC_SUBST(LUA51_LIBS)
+
+ AC_MSG_CHECKING(for LGI availability in Lua 5.1.)
+
+ peas_save_CFLAGS="$CFLAGS"
+ peas_save_LIBS="$LIBS"
+ CFLAGS="$PEAS_CFLAGS $LUA51_CFLAGS -Iloaders/lua5.1"
+ LIBS="$PEAS_LIBS $LUA51_LIBS"
+ AC_TRY_RUN(peas_lgi_version_test(0),
+ found_lua51=yes,
+ found_lua51=no,
+ found_lua51=yes)
+ CFLAGS="$peas_save_CFLAGS"
+ LIBS="$peas_save_LIBS"
+
+ if test "x$enable_lua51" = "xyes" -a "x$found_lua51" = "xno"; then
+ AC_MSG_ERROR([You need to have LGI >= $LGI_REQUIRED
+ installed to build libpeas])
+ fi
+
+ if test "x$found_lua51" = "xyes"; then
+ AC_DEFINE(ENABLE_LUA51, 1, [Define to compile with Lua support])
+ fi
+
+ AC_MSG_RESULT([$found_lua51])
+ fi
+fi
+
+AM_CONDITIONAL([ENABLE_LUA51], [test "x$found_lua51" = "xyes"])
+
+dnl ================================================================
dnl Python
dnl ================================================================
@@ -290,7 +414,7 @@ else
fi
if test "x$enable_python2" = "xyes" -a "x$found_python2" != "xyes"; then
- AC_MSG_ERROR([You need to have Python 2 and PyGobject installed to build libpeas])
+ AC_MSG_ERROR([You need to have Python 2 and PyGObject installed to build libpeas])
fi
AC_MSG_RESULT([$found_python2])
@@ -393,6 +517,7 @@ docs/reference/version.xml
libpeas/Makefile
libpeas-gtk/Makefile
loaders/Makefile
+loaders/lua5.1/Makefile
loaders/python/Makefile
loaders/python3/Makefile
data/Makefile
@@ -403,6 +528,7 @@ data/libpeas-gtk-1.0.pc
peas-demo/Makefile
peas-demo/plugins/Makefile
peas-demo/plugins/helloworld/Makefile
+peas-demo/plugins/luahello/Makefile
peas-demo/plugins/pythonhello/Makefile
peas-demo/plugins/secondtime/Makefile
po/Makefile.in
@@ -410,6 +536,7 @@ tests/Makefile
tests/libpeas/Makefile
tests/libpeas/plugins/Makefile
tests/libpeas/plugins/extension-c/Makefile
+tests/libpeas/plugins/extension-lua/Makefile
tests/libpeas/plugins/extension-python/Makefile
tests/libpeas/introspection/Makefile
tests/libpeas/testing/Makefile
@@ -443,6 +570,7 @@ Configuration:
Languages support:
+ Lua 5.1 support : ${found_lua51}
Python 2 support : ${found_python2}
Python 3 support : ${found_python3}
"
diff --git a/libpeas/peas-engine.c b/libpeas/peas-engine.c
index 249b357..c6b7043 100644
--- a/libpeas/peas-engine.c
+++ b/libpeas/peas-engine.c
@@ -589,6 +589,7 @@ static PeasPluginLoader *
get_plugin_loader (PeasEngine *engine,
gint loader_id)
{
+ gint i, j;
LoaderInfo *loader_info;
const gchar *loader_name;
gchar *module_name, *module_dir;
@@ -615,6 +616,15 @@ get_plugin_loader (PeasEngine *engine,
module_name = g_strconcat (loader_name, "loader", NULL);
module_dir = peas_dirs_get_plugin_loaders_dir ();
+ /* Remove '.'s from the module name */
+ for (i = 0, j = 0; module_name[i] != '\0'; ++i)
+ {
+ if (module_name[i] != '.')
+ module_name[j++] = module_name[i];
+ }
+
+ module_name[j] = '\0';
+
loader_info->module = load_module (module_name, module_dir);
if (loader_info->module == NULL)
@@ -667,7 +677,7 @@ get_plugin_loader (PeasEngine *engine,
*
* Enable a loader, enables a loader for plugins.
* The C plugin loader is always enabled. The other plugin
- * loaders are: python and python3.
+ * loaders are: lua5.1 and python and python3.
*
* For instance, the following code will enable python plugins
* to be loaded:
diff --git a/libpeas/peas-utils.c b/libpeas/peas-utils.c
index 21668f8..a2adb52 100644
--- a/libpeas/peas-utils.c
+++ b/libpeas/peas-utils.c
@@ -29,7 +29,8 @@
#include "peas-utils.h"
-static const gchar *all_plugin_loaders[] = {"c", "python", "python3"};
+static const gchar *all_plugin_loaders[] = {"c", "lua5.1",
+ "python", "python3"};
G_STATIC_ASSERT (G_N_ELEMENTS (all_plugin_loaders) == PEAS_UTILS_N_LOADERS);
static void
diff --git a/libpeas/peas-utils.h b/libpeas/peas-utils.h
index e7f55de..024d369 100644
--- a/libpeas/peas-utils.h
+++ b/libpeas/peas-utils.h
@@ -24,7 +24,7 @@
#include <glib-object.h>
-#define PEAS_UTILS_N_LOADERS 3
+#define PEAS_UTILS_N_LOADERS 4
gboolean peas_utils_valist_to_parameter_list (GType iface_type,
const gchar *first_property,
diff --git a/loaders/Makefile.am b/loaders/Makefile.am
index 5868750..c7c050b 100644
--- a/loaders/Makefile.am
+++ b/loaders/Makefile.am
@@ -1,5 +1,9 @@
SUBDIRS =
+if ENABLE_LUA51
+SUBDIRS += lua5.1
+endif
+
if ENABLE_PYTHON2
SUBDIRS += python
endif
diff --git a/loaders/lua5.1/Makefile.am b/loaders/lua5.1/Makefile.am
new file mode 100644
index 0000000..c49aa76
--- /dev/null
+++ b/loaders/lua5.1/Makefile.am
@@ -0,0 +1,31 @@
+# Lua 5.1 plugin loader
+
+loaderdir = $(libdir)/libpeas-1.0/loaders
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(PEAS_CFLAGS) \
+ $(GCOV_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ $(LUA51_CFLAGS)
+
+loader_LTLIBRARIES = liblua51loader.la
+
+liblua51loader_la_SOURCES = \
+ peas-plugin-loader-lua.c \
+ peas-plugin-loader-lua.h \
+ peas-plugin-loader-lua-utils.c \
+ peas-plugin-loader-lua-utils.h
+
+liblua51loader_la_LDFLAGS = \
+ $(LOADER_LIBTOOL_FLAGS) \
+ $(GCOV_LDFLAGS)
+
+liblua51loader_la_LIBADD = \
+ $(top_builddir)/libpeas/libpeas-1.0.la \
+ $(PEAS_LIBS) \
+ $(LUA51_LIBS)
+
+gcov_sources = $(liblua51loader_la_SOURCES)
+include $(top_srcdir)/Makefile.gcov
diff --git a/loaders/lua5.1/peas-plugin-loader-lua-utils.c b/loaders/lua5.1/peas-plugin-loader-lua-utils.c
new file mode 100644
index 0000000..fb043fb
--- /dev/null
+++ b/loaders/lua5.1/peas-plugin-loader-lua-utils.c
@@ -0,0 +1,122 @@
+/*
+ * peas-plugin-loader-lua-utils.c
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2014 - Garrett Regier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "peas-plugin-loader-lua-utils.h"
+
+#include <string.h>
+
+#include <lauxlib.h>
+#include <lualib.h>
+
+
+gboolean
+peas_lua_utils_require (lua_State *L,
+ const gchar *name)
+{
+ luaL_checkstack (L, 2, "");
+
+ lua_getglobal (L, "require");
+ lua_pushstring (L, name);
+
+ if (lua_pcall (L, 1, 1, 0) != 0)
+ {
+ g_warning ("Error failed to load Lua module '%s': %s",
+ name, lua_tostring (L, -1));
+
+ /* Pop error */
+ lua_pop (L, 1);
+ return FALSE;
+ }
+
+ if (!lua_istable (L, -1))
+ {
+ g_warning ("Error invalid Lua module for '%s': "
+ "expected table, got: %s",
+ name, lua_tostring (L, -1));
+
+ /* Pop the module's table */
+ lua_pop (L, 1);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+peas_lua_utils_check_version (lua_State *L,
+ guint req_major,
+ guint req_minor,
+ guint req_micro)
+{
+ const gchar *version_str;
+ gchar **version_str_parts;
+ gint n_version_parts;
+ gint *version_parts;
+ gint i;
+ gboolean success = FALSE;
+
+ lua_getfield (L, -1, "_VERSION");
+ version_str = lua_tostring (L, -1);
+
+ version_str_parts = g_strsplit (version_str, ".", 0);
+
+ n_version_parts = g_strv_length (version_str_parts);
+ version_parts = g_newa (gint, n_version_parts);
+
+ for (i = 0; i < n_version_parts; ++i)
+ {
+ gchar *end;
+
+ version_parts[i] = g_ascii_strtoll (version_str_parts[i], &end, 10);
+
+ if (*end != '\0' ||
+ version_parts[i] < 0 ||
+ version_parts[i] == G_MAXINT64)
+ {
+ g_warning ("Invalid version string: %s", version_str);
+ goto error;
+ }
+ }
+
+ if (n_version_parts < 3 ||
+ version_parts[0] != req_major ||
+ version_parts[1] < req_minor ||
+ (version_parts[1] == req_minor && version_parts[2] < req_micro))
+ {
+ g_warning ("Version mismatch %d.%d.%d is required, found %s",
+ req_major, req_minor, req_micro, version_str);
+ goto error;
+ }
+
+ success = TRUE;
+
+error:
+
+ /* Pop _VERSION */
+ lua_pop (L, 1);
+
+ g_strfreev (version_str_parts);
+ return success;
+}
diff --git a/loaders/lua5.1/peas-plugin-loader-lua-utils.h b/loaders/lua5.1/peas-plugin-loader-lua-utils.h
new file mode 100644
index 0000000..dafe94f
--- /dev/null
+++ b/loaders/lua5.1/peas-plugin-loader-lua-utils.h
@@ -0,0 +1,42 @@
+/*
+ * peas-plugin-loader-lua-utils.h
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2014 - Garrett Regier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __PEAS_PLUGIN_LOADER_LUA_UTILS_H__
+#define __PEAS_PLUGIN_LOADER_LUA_UTILS_H__
+
+#include <glib.h>
+#include <lua.h>
+
+G_BEGIN_DECLS
+
+
+gboolean peas_lua_utils_require (lua_State *L,
+ const gchar *name);
+
+gboolean peas_lua_utils_check_version (lua_State *L,
+ guint req_major,
+ guint req_minor,
+ guint req_micro);
+
+G_END_DECLS
+
+#endif /* __PEAS_PLUGIN_LOADER_LUA_UTILS_H__ */
+
diff --git a/loaders/lua5.1/peas-plugin-loader-lua.c b/loaders/lua5.1/peas-plugin-loader-lua.c
new file mode 100644
index 0000000..ccc0ad0
--- /dev/null
+++ b/loaders/lua5.1/peas-plugin-loader-lua.c
@@ -0,0 +1,404 @@
+/*
+ * peas-plugin-loader-lua.c
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2014 - Garrett Regier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "peas-plugin-loader-lua.h"
+
+#include <string.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#include "peas-plugin-loader-lua-utils.h"
+
+
+struct _PeasPluginLoaderLuaPrivate {
+ lua_State *L;
+};
+
+G_DEFINE_TYPE (PeasPluginLoaderLua, peas_plugin_loader_lua, PEAS_TYPE_PLUGIN_LOADER)
+
+G_MODULE_EXPORT void
+peas_register_types (PeasObjectModule *module)
+{
+ peas_object_module_register_extension_type (module,
+ PEAS_TYPE_PLUGIN_LOADER,
+ PEAS_TYPE_PLUGIN_LOADER_LUA);
+}
+
+static gboolean
+_lua_add_package_path (lua_State *L,
+ const gchar *package_path)
+{
+ luaL_checkstack (L, 3, "");
+
+ lua_getglobal (L, "package");
+ lua_getfield (L, -1, "path");
+
+ if (!lua_isstring (L, -1))
+ {
+ g_warning ("Invalid Lua package.path: %s", lua_tostring (L, -1));
+
+ /* Pop path and package */
+ lua_pop (L, 2);
+ return FALSE;
+ }
+
+ /* ";package_path/?.lua;package_path/?/init.lua" */
+ lua_pushliteral (L, ";");
+ lua_pushstring (L, package_path);
+ lua_pushliteral (L, G_DIR_SEPARATOR_S "?.lua;");
+ lua_pushstring (L, package_path);
+ lua_pushliteral (L, G_DIR_SEPARATOR_S "?" G_DIR_SEPARATOR_S "init.lua");
+ lua_concat (L, 5);
+
+ if (strstr (lua_tostring (L, -2), lua_tostring (L, -1)) != NULL)
+ {
+ /* Pop new path and path */
+ lua_pop (L, 2);
+ }
+ else
+ {
+ /* Update package.path */
+ lua_concat (L, 2);
+ lua_setfield (L, -2, "path");
+ }
+
+ /* Pop package */
+ lua_pop (L, 1);
+ return TRUE;
+}
+
+static gboolean
+_lua_pushinstance (lua_State *L,
+ const gchar *namespace_,
+ const gchar *name,
+ GType gtype,
+ gpointer instance)
+{
+ luaL_checkstack (L, 3, "");
+
+ if (!peas_lua_utils_require (L, "lgi"))
+ return FALSE;
+
+ lua_getfield (L, -1, namespace_);
+ lua_getfield (L, -1, name);
+
+ /* Remove the namespace and lgi's module table */
+ lua_replace (L, -2);
+ lua_replace (L, -2);
+
+ lua_pushlightuserdata (L, instance);
+ lua_pushboolean (L, FALSE);
+
+ /* new(addr[, already_own[, no_sink]]) */
+ if (lua_pcall (L, 2, 1, 0) != 0)
+ {
+ g_warning ("Failed to create Lua object of type '%s': %s",
+ g_type_name (gtype), lua_tostring (L, -1));
+
+ /* Pop the error */
+ lua_pop (L, 1);
+ return FALSE;
+ }
+
+ /* Check that the Lua object was created correctly */
+ lua_getfield (L, -1, "_native");
+ g_assert (lua_islightuserdata (L, -1));
+ g_assert (lua_touserdata (L, -1) == instance);
+ lua_pop (L, 1);
+
+ return TRUE;
+}
+
+static GType
+_lua_get_gtype (lua_State *L,
+ int index)
+{
+ GType gtype = G_TYPE_INVALID;
+
+ luaL_checkstack (L, 1, "");
+
+ lua_getfield (L, index, "_gtype");
+
+ if (lua_type (L, -1) == LUA_TLIGHTUSERDATA)
+ gtype = (GType) lua_touserdata (L, -1);
+
+ /* Pop _gtype */
+ lua_pop (L, 1);
+ return gtype;
+}
+
+static GType
+_lua_find_extension_type (lua_State *L,
+ PeasPluginInfo *info,
+ GType exten_type)
+{
+ GType found_type = G_TYPE_INVALID;
+
+ luaL_checkstack (L, 3, "");
+
+ /* Get the module's table */
+ lua_pushlightuserdata (L, info);
+ lua_rawget (L, LUA_REGISTRYINDEX);
+
+ /* Must always have a valid key */
+ lua_pushnil (L);
+ while (lua_next (L, -2) != 0 && found_type == G_TYPE_INVALID)
+ {
+ if (lua_istable (L, -1))
+ {
+ found_type = _lua_get_gtype (L, -1);
+
+ if (found_type != G_TYPE_INVALID &&
+ !g_type_is_a (found_type, exten_type))
+ {
+ found_type = G_TYPE_INVALID;
+ }
+ }
+
+ /* Pop the value but keep the key for the next iteration */
+ lua_pop (L, 1);
+ }
+
+ /* Pop the module's table */
+ lua_pop (L, 1);
+ return found_type;
+}
+
+static gboolean
+peas_plugin_loader_lua_provides_extension (PeasPluginLoader *loader,
+ PeasPluginInfo *info,
+ GType exten_type)
+{
+ PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader);
+ lua_State *L = lua_loader->priv->L;
+ GType extension_type;
+
+ extension_type = _lua_find_extension_type (L, info, exten_type);
+
+ return extension_type != G_TYPE_INVALID;
+}
+
+static PeasExtension *
+peas_plugin_loader_lua_create_extension (PeasPluginLoader *loader,
+ PeasPluginInfo *info,
+ GType exten_type,
+ guint n_parameters,
+ GParameter *parameters)
+{
+ PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader);
+ lua_State *L = lua_loader->priv->L;
+ GType the_type;
+ GObject *object;
+
+ the_type = _lua_find_extension_type (L, info, exten_type);
+ if (the_type == G_TYPE_INVALID)
+ return NULL;
+
+ if (!g_type_is_a (the_type, exten_type))
+ {
+ g_warn_if_fail (g_type_is_a (the_type, exten_type));
+ return NULL;
+ }
+
+ object = g_object_newv (the_type, n_parameters, parameters);
+ if (object == NULL)
+ return NULL;
+
+ /* As we do not instantiate a PeasExtensionWrapper, we have to remember
+ * somehow which interface we are instantiating, to make it possible to use
+ * the deprecated peas_extension_get_extension_type() method.
+ */
+ g_object_set_data (object, "peas-extension-type",
+ GUINT_TO_POINTER (exten_type));
+
+ luaL_checkstack (L, 3, "");
+
+ if (!_lua_pushinstance (L, "GObject", "Object", the_type, object))
+ {
+ g_clear_object (&object);
+ return NULL;
+ }
+
+ lua_getfield (L, -1, "priv");
+
+ if (!_lua_pushinstance (L, "Peas", "PluginInfo",
+ PEAS_TYPE_PLUGIN_INFO, info))
+ {
+ g_clear_object (&object);
+ }
+ else
+ {
+ /* Set the plugin info as self.priv.plugin_info */
+ lua_setfield (L, -2, "plugin_info");
+ }
+
+ /* Pop priv and object */
+ lua_pop (L, 2);
+
+ return object;
+}
+
+static gboolean
+peas_plugin_loader_lua_load (PeasPluginLoader *loader,
+ PeasPluginInfo *info)
+{
+ PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader);
+ lua_State *L = lua_loader->priv->L;
+ gboolean success;
+
+ luaL_checkstack (L, 2, "");
+
+ /* Get the module's table */
+ lua_pushlightuserdata (L, info);
+ lua_rawget (L, LUA_REGISTRYINDEX);
+
+ if (!lua_isnil (L, -1))
+ {
+ success = lua_istable (L, -1);
+ }
+ else
+ {
+ const gchar *module_dir, *module_name;
+
+ module_dir = peas_plugin_info_get_module_dir (info);
+ module_name = peas_plugin_info_get_module_name (info);
+
+ /* Must push the key back onto the stack */
+ lua_pushlightuserdata (L, info);
+
+ if (!_lua_add_package_path (L, module_dir) ||
+ !peas_lua_utils_require (L, module_name))
+ {
+ /* Push something that isn't a table */
+ lua_pushboolean (L, FALSE);
+ }
+
+ success = lua_istable (L, -1);
+ lua_rawset (L, LUA_REGISTRYINDEX);
+ }
+
+ /* Pop the module's table */
+ lua_pop (L, 1);
+
+ return success;
+}
+
+static void
+peas_plugin_loader_lua_unload (PeasPluginLoader *loader,
+ PeasPluginInfo *info)
+{
+ /* Lua always keeps a reference anyways */
+}
+
+static void
+peas_plugin_loader_lua_garbage_collect (PeasPluginLoader *loader)
+{
+ PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader);
+
+ lua_gc (lua_loader->priv->L, LUA_GCCOLLECT, 0);
+}
+
+static int
+atpanic_handler (lua_State *L)
+{
+ G_BREAKPOINT ();
+ return 0;
+}
+
+static gboolean
+peas_plugin_loader_lua_initialize (PeasPluginLoader *loader)
+{
+ PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader);
+ lua_State *L;
+
+ L = luaL_newstate ();
+ if (L == NULL)
+ {
+ g_critical ("Failed to allocate lua_State");
+ return FALSE;
+ }
+
+ luaL_openlibs (L);
+
+ if (!peas_lua_utils_require (L, "lgi") ||
+ !peas_lua_utils_check_version (L,
+ LGI_MAJOR_VERSION,
+ LGI_MINOR_VERSION,
+ LGI_MICRO_VERSION))
+ {
+ /* Already warned */
+ lua_close (L);
+ return FALSE;
+ }
+
+ /* Pop lgi's module table */
+ lua_pop (L, 1);
+
+ if (g_getenv ("PEAS_LUA_DEBUG") != NULL)
+ {
+ lua_atpanic (L, atpanic_handler);
+ }
+
+ lua_loader->priv->L = L;
+ return TRUE;
+}
+
+static void
+peas_plugin_loader_lua_init (PeasPluginLoaderLua *lua_loader)
+{
+ lua_loader->priv = G_TYPE_INSTANCE_GET_PRIVATE (lua_loader,
+ PEAS_TYPE_PLUGIN_LOADER_LUA,
+ PeasPluginLoaderLuaPrivate);
+}
+
+static void
+peas_plugin_loader_lua_finalize (GObject *object)
+{
+ PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (object);
+
+ g_clear_pointer (&lua_loader->priv->L, (GDestroyNotify) lua_close);
+
+ G_OBJECT_CLASS (peas_plugin_loader_lua_parent_class)->finalize (object);
+}
+
+static void
+peas_plugin_loader_lua_class_init (PeasPluginLoaderLuaClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ PeasPluginLoaderClass *loader_class = PEAS_PLUGIN_LOADER_CLASS (klass);
+
+ object_class->finalize = peas_plugin_loader_lua_finalize;
+
+ loader_class->initialize = peas_plugin_loader_lua_initialize;
+ loader_class->load = peas_plugin_loader_lua_load;
+ loader_class->unload = peas_plugin_loader_lua_unload;
+ loader_class->create_extension = peas_plugin_loader_lua_create_extension;
+ loader_class->provides_extension = peas_plugin_loader_lua_provides_extension;
+ loader_class->garbage_collect = peas_plugin_loader_lua_garbage_collect;
+
+ g_type_class_add_private (object_class, sizeof (PeasPluginLoaderLuaPrivate));
+}
diff --git a/loaders/lua5.1/peas-plugin-loader-lua.h b/loaders/lua5.1/peas-plugin-loader-lua.h
new file mode 100644
index 0000000..efb64a1
--- /dev/null
+++ b/loaders/lua5.1/peas-plugin-loader-lua.h
@@ -0,0 +1,60 @@
+/*
+ * peas-plugin-loader-lua.h
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2014 - Garrett Regier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __PEAS_PLUGIN_LOADER_LUA_H__
+#define __PEAS_PLUGIN_LOADER_LUA_H__
+
+#include <libpeas/peas-plugin-loader.h>
+#include <libpeas/peas-object-module.h>
+
+G_BEGIN_DECLS
+
+#define PEAS_TYPE_PLUGIN_LOADER_LUA (peas_plugin_loader_lua_get_type ())
+#define PEAS_PLUGIN_LOADER_LUA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PEAS_TYPE_PLUGIN_LOADER_LUA, PeasPluginLoaderLua))
+#define PEAS_PLUGIN_LOADER_LUA_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PEAS_TYPE_PLUGIN_LOADER_LUA, PeasPluginLoaderLua const))
+#define PEAS_PLUGIN_LOADER_LUA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PEAS_TYPE_PLUGIN_LOADER_LUA, PeasPluginLoaderLuaClass))
+#define PEAS_IS_PLUGIN_LOADER_LUA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PEAS_TYPE_PLUGIN_LOADER_LUA))
+#define PEAS_IS_PLUGIN_LOADER_LUA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PEAS_TYPE_PLUGIN_LOADER_LUA))
+#define PEAS_PLUGIN_LOADER_LUA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PEAS_TYPE_PLUGIN_LOADER_LUA, PeasPluginLoaderLuaClass))
+
+typedef struct _PeasPluginLoaderLua PeasPluginLoaderLua;
+typedef struct _PeasPluginLoaderLuaClass PeasPluginLoaderLuaClass;
+typedef struct _PeasPluginLoaderLuaPrivate PeasPluginLoaderLuaPrivate;
+
+struct _PeasPluginLoaderLua {
+ PeasPluginLoader parent;
+
+ PeasPluginLoaderLuaPrivate *priv;
+};
+
+struct _PeasPluginLoaderLuaClass {
+ PeasPluginLoaderClass parent_class;
+};
+
+GType peas_plugin_loader_lua_get_type (void) G_GNUC_CONST;
+
+/* All the loaders must implement this function */
+G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module);
+
+G_END_DECLS
+
+#endif /* __PEAS_PLUGIN_LOADER_LUA_H__ */
+
diff --git a/peas-demo/peas-demo.c b/peas-demo/peas-demo.c
index b1154f7..6a91eaf 100644
--- a/peas-demo/peas-demo.c
+++ b/peas-demo/peas-demo.c
@@ -128,6 +128,7 @@ main (int argc,
/* We don't care about leaking memory */
g_setenv ("PEAS_ALLOW_ALL_LOADERS", "1", TRUE);
+ peas_engine_enable_loader (engine, "lua5.1");
peas_engine_enable_loader (engine, "python3");
if (run_from_build_dir)
diff --git a/peas-demo/plugins/Makefile.am b/peas-demo/plugins/Makefile.am
index 273b32b..3c5d222 100644
--- a/peas-demo/plugins/Makefile.am
+++ b/peas-demo/plugins/Makefile.am
@@ -1,5 +1,9 @@
SUBDIRS = helloworld secondtime
+if ENABLE_LUA51
+SUBDIRS += luahello
+endif
+
if ENABLE_PYTHON3
SUBDIRS += pythonhello
endif
diff --git a/peas-demo/plugins/luahello/Makefile.am b/peas-demo/plugins/luahello/Makefile.am
new file mode 100644
index 0000000..e6aef72
--- /dev/null
+++ b/peas-demo/plugins/luahello/Makefile.am
@@ -0,0 +1,8 @@
+plugindir = $(libdir)/peas-demo/plugins/luahello
+
+plugin_lua = \
+ luahello.py
+
+plugin_DATA = luahello.plugin
+
+EXTRA_DIST = $(plugin_DATA)
diff --git a/peas-demo/plugins/luahello/luahello.lua b/peas-demo/plugins/luahello/luahello.lua
new file mode 100644
index 0000000..8d50bc9
--- /dev/null
+++ b/peas-demo/plugins/luahello/luahello.lua
@@ -0,0 +1,50 @@
+local lgi = require 'lgi'
+
+local GObject = lgi.GObject
+local Gtk = lgi.Gtk
+local Peas = lgi.Peas
+local PeasGtk = lgi.PeasGtk
+
+
+LuaHelloPlugin = GObject.Object:derive('LuaHelloPlugin', {
+ Peas.Activatable
+})
+
+LuaHelloPlugin._property.object =
+ GObject.ParamSpecObject('object', 'object', 'object',
+ GObject.Object._gtype,
+ { GObject.ParamFlags.READABLE,
+ GObject.ParamFlags.WRITABLE })
+
+function LuaHelloPlugin:do_activate()
+ window = self.priv.object
+ print('LuaHelloPlugin:do_activate', tostring(window))
+ self.priv.label = Gtk.Label.new('Lua Says Hello!')
+ self.priv.label:show()
+ window:get_child():pack_start(self.priv.label, true, true, 0)
+end
+
+function LuaHelloPlugin:do_deactivate()
+ window = self.priv.object
+ print('LuaHelloPlugin:do_deactivate', tostring(window))
+ window:get_child():remove(self.priv.label)
+ self.priv.label:destroy()
+end
+
+function LuaHelloPlugin:do_update_state()
+ window = self.priv.object
+ print('LuaHelloPlugin:do_update_state', tostring(window))
+end
+
+
+LuaHelloConfigurable = GObject.Object:derive('LuaHelloConfigurable', {
+ PeasGtk.Configurable
+})
+
+function LuaHelloConfigurable:do_create_configure_widget()
+ return Gtk.Label.new('Lua Hello configure widget')
+end
+
+return { LuaHelloPlugin, LuaHelloConfigurable }
+
+-- ex:set ts=4 et sw=4 ai:
diff --git a/peas-demo/plugins/luahello/luahello.plugin b/peas-demo/plugins/luahello/luahello.plugin
new file mode 100644
index 0000000..dddfe21
--- /dev/null
+++ b/peas-demo/plugins/luahello/luahello.plugin
@@ -0,0 +1,7 @@
+[Plugin]
+Module=luahello
+Loader=lua5.1
+Name=Lua Says Hello
+Description=Inserts a box containing "Lua Says Hello" in every windows.
+Authors=Garrett Regier <garrettregier@gmail.com>
+Copyright=Copyright © 2014 Garrett Regier
diff --git a/tests/libpeas/Makefile.am b/tests/libpeas/Makefile.am
index 0015ff0..6d6696f 100644
--- a/tests/libpeas/Makefile.am
+++ b/tests/libpeas/Makefile.am
@@ -25,6 +25,13 @@ TEST_PROGS += \
extension-set \
plugin-info
+if ENABLE_LUA51
+TEST_PROGS += extension-lua51
+extension_lua51_SOURCES = extension-lua.c
+extension_lua51_CFLAGS = $(LUA51_CFLAGS)
+extension_lua51_LDADD = $(LDADD) $(LUA51_LIBS)
+endif
+
if ENABLE_PYTHON2
TEST_PROGS += extension-python
extension_python_SOURCES = extension-py.c
diff --git a/tests/libpeas/extension-lua.c b/tests/libpeas/extension-lua.c
new file mode 100644
index 0000000..6cfd97a
--- /dev/null
+++ b/tests/libpeas/extension-lua.c
@@ -0,0 +1,213 @@
+/*
+ * extension-lua.c
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2014 - Garrett Regier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#include <libpeas/peas-activatable.h>
+#include "libpeas/peas-engine-priv.h"
+
+#include "testing/testing-extension.h"
+#include "introspection/introspection-base.h"
+
+
+/* We must stop and start the garbage collector
+ * when testing reference counts otherwise issues
+ * will occur if the garbage collector runs preemptively.
+ */
+static void
+set_garbage_collector_state (PeasEngine *engine,
+ PeasPluginInfo *info,
+ gboolean running)
+{
+ PeasExtension *extension;
+
+ extension = peas_engine_create_extension (engine, info,
+ PEAS_TYPE_ACTIVATABLE,
+ NULL);
+
+ if (running)
+ {
+ /* collectgarbage('restart') */
+ peas_activatable_activate (PEAS_ACTIVATABLE (extension));
+ }
+ else
+ {
+ /* collectgarbage('stop') */
+ peas_activatable_deactivate (PEAS_ACTIVATABLE (extension));
+ }
+
+ g_object_unref (extension);
+}
+
+static void
+test_extension_lua_instance_refcount (PeasEngine *engine,
+ PeasPluginInfo *info)
+{
+ PeasExtension *extension;
+
+ set_garbage_collector_state (engine, info, FALSE);
+
+ extension = peas_engine_create_extension (engine, info,
+ PEAS_TYPE_ACTIVATABLE,
+ NULL);
+ g_object_add_weak_pointer (extension, (gpointer *) &extension);
+
+ g_assert (PEAS_IS_EXTENSION (extension));
+
+ /* The Lua wrapper created around the extension
+ * object should have increased its refcount by 1.
+ */
+ g_assert_cmpint (extension->ref_count, ==, 2);
+
+ /* The Lua wrapper around the extension has been garbage collected */
+ peas_engine_garbage_collect (engine);
+ g_assert_cmpint (G_OBJECT (extension)->ref_count, ==, 1);
+
+ /* Create a new Lua wrapper around the extension */
+ peas_activatable_update_state (PEAS_ACTIVATABLE (extension));
+ g_assert_cmpint (G_OBJECT (extension)->ref_count, ==, 2);
+
+ /* The Lua wrapper still exists */
+ g_object_unref (extension);
+ g_assert_cmpint (extension->ref_count, ==, 1);
+
+ /* The Lua wrapper around the extension has been garbage collected */
+ peas_engine_garbage_collect (engine);
+ g_assert (extension == NULL);
+
+ set_garbage_collector_state (engine, info, TRUE);
+}
+
+static void
+test_extension_lua_activatable_subject_refcount (PeasEngine *engine,
+ PeasPluginInfo *info)
+{
+ PeasExtension *extension;
+ GObject *object;
+
+ set_garbage_collector_state (engine, info, FALSE);
+
+ /* Create the 'object' property value, to be similar to a GtkWindow
+ * instance: a sunk GInitiallyUnowned object.
+ */
+ object = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL);
+ g_object_add_weak_pointer (object, (gpointer *) &object);
+ g_object_ref_sink (object);
+ g_assert_cmpint (object->ref_count, ==, 1);
+
+ /* We pre-create the wrapper to make it easier to check reference count */
+ extension = peas_engine_create_extension (engine, info,
+ PEAS_TYPE_ACTIVATABLE,
+ "object", object,
+ NULL);
+ g_object_add_weak_pointer (extension, (gpointer *) &extension);
+
+ g_assert (PEAS_IS_EXTENSION (extension));
+
+ /* The Lua wrapper created around our dummy
+ * object should have increased its refcount by 1.
+ */
+ peas_engine_garbage_collect (engine);
+ g_assert_cmpint (object->ref_count, ==, 2);
+
+ g_object_unref (extension);
+ g_assert (extension == NULL);
+
+ /* We unreffed the extension, so it should have been
+ * destroyed and our dummy object's refcount should be back to 1.
+ */
+ peas_engine_garbage_collect (engine);
+ g_assert_cmpint (object->ref_count, ==, 1);
+
+ g_object_unref (object);
+ g_assert (object == NULL);
+
+ set_garbage_collector_state (engine, info, TRUE);
+}
+
+#if GLIB_CHECK_VERSION (2, 38, 0)
+static void
+test_extension_lua_nonexistent (void)
+{
+ g_test_trap_subprocess (EXTENSION_TEST_NAME (lua5.1,
+ "nonexistent/subprocess"),
+ 0, G_TEST_SUBPROCESS_INHERIT_STDERR);
+ g_test_trap_assert_passed ();
+ g_test_trap_assert_stderr ("");
+}
+
+static void
+test_extension_lua_nonexistent_subprocess (PeasEngine *engine)
+{
+ PeasPluginInfo *info;
+
+ testing_util_push_log_hook ("Error failed to load Lua module "
+ "'extension-lua51-nonexistent'*");
+ testing_util_push_log_hook ("Error loading plugin "
+ "'extension-lua51-nonexistent'");
+
+ info = peas_engine_get_plugin_info (engine, "extension-lua51-nonexistent");
+
+ g_assert (!peas_engine_load_plugin (engine, info));
+}
+#endif
+
+int
+main (int argc,
+ char *argv[])
+{
+ testing_init (&argc, &argv);
+
+ /* Only test the basics */
+ testing_extension_basic ("lua5.1");
+
+ /* We still need to add the callable tests
+ * because of peas_extension_call()
+ */
+ testing_extension_callable ("lua5.1");
+
+#undef EXTENSION_TEST
+#undef EXTENSION_TEST_FUNC
+
+#define EXTENSION_TEST(loader, path, func) \
+ testing_extension_add (EXTENSION_TEST_NAME (loader, path), \
+ (gpointer) test_extension_lua_##func)
+
+#define EXTENSION_TEST_FUNC(loader, path, func) \
+ g_test_add_func (EXTENSION_TEST_NAME (loader, path), \
+ (gpointer) test_extension_lua_##func)
+
+ EXTENSION_TEST (lua5.1, "instance-refcount", instance_refcount);
+ EXTENSION_TEST (lua5.1, "activatable-subject-refcount",
+ activatable_subject_refcount);
+
+#if GLIB_CHECK_VERSION (2, 38, 0)
+ EXTENSION_TEST_FUNC (lua5.1, "nonexistent", nonexistent);
+ EXTENSION_TEST (lua5.1, "nonexistent/subprocess", nonexistent_subprocess);
+#endif
+
+ return testing_extension_run_tests ();
+}
diff --git a/tests/libpeas/plugins/Makefile.am b/tests/libpeas/plugins/Makefile.am
index db49e17..2dfddb2 100644
--- a/tests/libpeas/plugins/Makefile.am
+++ b/tests/libpeas/plugins/Makefile.am
@@ -2,6 +2,10 @@ include $(top_srcdir)/tests/Makefile.plugin
SUBDIRS = extension-c
+if ENABLE_LUA51
+SUBDIRS += extension-lua
+endif
+
if ENABLE_PYTHON3
SUBDIRS += extension-python
else
@@ -12,6 +16,7 @@ endif
noinst_PLUGIN = \
extension-c-nonexistent.plugin \
+ extension-lua51-nonexistent.plugin \
extension-python-nonexistent.plugin \
extension-python3-nonexistent.plugin \
info-missing-module.plugin \
diff --git a/tests/libpeas/plugins/extension-lua/Makefile.am b/tests/libpeas/plugins/extension-lua/Makefile.am
new file mode 100644
index 0000000..722ba7e
--- /dev/null
+++ b/tests/libpeas/plugins/extension-lua/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/tests/Makefile.plugin
+
+noinst_DATA = \
+ extension-lua51.gschema.xml \
+ extension-lua51.plugin \
+ extension-lua51.lua
+
diff --git a/tests/libpeas/plugins/extension-lua/extension-lua51.gschema.xml b/tests/libpeas/plugins/extension-lua/extension-lua51.gschema.xml
new file mode 100644
index 0000000..d6e9a76
--- /dev/null
+++ b/tests/libpeas/plugins/extension-lua/extension-lua51.gschema.xml
@@ -0,0 +1,9 @@
+<schemalist>
+ <schema id="extension-lua51" path="/org/gnome/libpeas/tests/extension-lua51/">
+ <key name="a-setting" type="s">
+ <default>'Blah'</default>
+ <summary>Just a setting.</summary>
+ <description>Just a setting.</description>
+ </key>
+ </schema>
+</schemalist>
diff --git a/tests/libpeas/plugins/extension-lua/extension-lua51.lua b/tests/libpeas/plugins/extension-lua/extension-lua51.lua
new file mode 100644
index 0000000..3bb6acf
--- /dev/null
+++ b/tests/libpeas/plugins/extension-lua/extension-lua51.lua
@@ -0,0 +1,91 @@
+local lgi = require 'lgi'
+
+local GObject = lgi.GObject
+local Introspection = lgi.Introspection
+local Peas = lgi.Peas
+
+
+local ExtensionLuaPlugin = GObject.Object:derive('ExtensionLuaPlugin', {
+ Peas.Activatable,
+ Introspection.Base,
+ Introspection.Callable,
+ Introspection.HasPrerequisite,
+ Introspection.PropertiesPrerequisite,
+ Introspection.Properties
+})
+
+ExtensionLuaPlugin._property.object =
+ GObject.ParamSpecObject('object', 'object', 'object',
+ GObject.Object._gtype,
+ { GObject.ParamFlags.READABLE,
+ GObject.ParamFlags.WRITABLE })
+
+ExtensionLuaPlugin._property.construct_only =
+ GObject.ParamSpecString('construct-only', 'construct-only',
+ 'construct-only',
+ '',
+ { GObject.ParamFlags.CONSTRUCT_ONLY,
+ GObject.ParamFlags.READABLE,
+ GObject.ParamFlags.WRITABLE })
+
+ExtensionLuaPlugin._property.read_only =
+ GObject.ParamSpecString('read-only', 'read-only', 'read-only',
+ '',
+ { GObject.ParamFlags.READABLE })
+
+ExtensionLuaPlugin._property.write_only =
+ GObject.ParamSpecString('write-only', 'write-only', 'write-only',
+ '',
+ { GObject.ParamFlags.WRITABLE })
+
+ExtensionLuaPlugin._property.readwrite =
+ GObject.ParamSpecString('readwrite', 'readwrite', 'readwrite',
+ '',
+ { GObject.ParamFlags.READABLE,
+ GObject.ParamFlags.WRITABLE })
+
+ExtensionLuaPlugin._property.prerequisite =
+ GObject.ParamSpecString('prerequisite', 'prerequisite', 'prerequisite',
+ '',
+ { GObject.ParamFlags.CONSTRUCT_ONLY,
+ GObject.ParamFlags.READABLE,
+ GObject.ParamFlags.WRITABLE })
+
+function ExtensionLuaPlugin:do_activate()
+ collectgarbage('restart')
+end
+
+function ExtensionLuaPlugin:do_deactivate()
+ collectgarbage('stop')
+end
+
+function ExtensionLuaPlugin:do_update_state()
+end
+
+function ExtensionLuaPlugin:do_get_plugin_info()
+ return self.priv.plugin_info
+end
+
+function ExtensionLuaPlugin:do_get_settings()
+ return self.priv.plugin_info:get_settings(nil)
+end
+
+function ExtensionLuaPlugin:do_call_no_args()
+end
+
+function ExtensionLuaPlugin:do_call_with_return()
+ return 'Hello, World!'
+end
+
+function ExtensionLuaPlugin:do_call_single_arg()
+ return true
+end
+
+function ExtensionLuaPlugin:do_call_multi_args(in_, inout)
+ return inout, in_
+end
+
+ExtensionLuaPlugin()
+return { ExtensionLuaPlugin }
+
+-- ex:set ts=4 et sw=4 ai:
diff --git a/tests/libpeas/plugins/extension-lua/extension-lua51.plugin b/tests/libpeas/plugins/extension-lua/extension-lua51.plugin
new file mode 100644
index 0000000..ff4b51a
--- /dev/null
+++ b/tests/libpeas/plugins/extension-lua/extension-lua51.plugin
@@ -0,0 +1,7 @@
+[Plugin]
+Module=extension-lua51
+Loader=lua5.1
+Name=Extension lua5.1
+Description=This plugin is for the lua5.1 PeasExtension tests.
+Authors=Garrett Regier
+Copyright=Copyright © 2014 Garrett Regier
diff --git a/tests/libpeas/plugins/extension-lua51-nonexistent.plugin b/tests/libpeas/plugins/extension-lua51-nonexistent.plugin
new file mode 100644
index 0000000..0294240
--- /dev/null
+++ b/tests/libpeas/plugins/extension-lua51-nonexistent.plugin
@@ -0,0 +1,7 @@
+[Plugin]
+Module=extension-lua51-nonexistent
+Loader=lua5.1
+Name=Extension lua5.1 Nonexistent
+Description=This plugin is nonexistent.
+Authors=Garrett Regier
+Copyright=Copyright © 2014 Garrett Regier
diff --git a/tests/libpeas/testing/testing-extension.c b/tests/libpeas/testing/testing-extension.c
index 12f1db3..e1f6a59 100644
--- a/tests/libpeas/testing/testing-extension.c
+++ b/tests/libpeas/testing/testing-extension.c
@@ -171,6 +171,7 @@ test_extension_create_invalid (PeasEngine *engine,
/* This cannot be tested in PyGI and Seed's log handler messes this up */
if (g_strcmp0 (extension_plugin, "extension-c") != 0 &&
+ g_strcmp0 (extension_plugin, "extension-lua51") != 0 &&
g_strcmp0 (extension_plugin, "extension-python") != 0 &&
g_strcmp0 (extension_plugin, "extension-python3") != 0)
{
@@ -387,9 +388,19 @@ test_extension_call_multi_args (PeasEngine *engine,
void
testing_extension_basic (const gchar *loader)
{
+ gint i, j;
+ gchar *loader_name;
PeasEngine *engine;
- extension_plugin = g_strdup_printf ("extension-%s", loader);
+ loader_name = g_new0 (gchar, strlen (loader));
+ for (i = 0, j = 0; loader[i] != '\0'; ++i)
+ {
+ if (loader[i] != '.')
+ loader_name[j++] = loader[i];
+ }
+
+ extension_plugin = g_strdup_printf ("extension-%s", loader_name);
+ g_free (loader_name);
engine = testing_engine_new ();
peas_engine_enable_loader (engine, loader);