From 5da3026546acdf3157f6431d039a3f478744db49 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 15 Sep 2013 13:51:23 +0100 Subject: [PATCH] Added basic empty lua api and hooks --- Makefile.am | 14 +- configure.ac | 12 +- src/plugins/lua_api.c | 386 ++++++++++++++++++++++++++++++++++++++ src/plugins/lua_api.h | 36 ++++ src/plugins/lua_plugins.c | 218 +++++++++++++++++++++ src/plugins/lua_plugins.h | 49 +++++ src/plugins/plugins.c | 25 +++ src/plugins/plugins.h | 1 + 8 files changed, 737 insertions(+), 4 deletions(-) create mode 100644 src/plugins/lua_api.c create mode 100644 src/plugins/lua_api.h create mode 100644 src/plugins/lua_plugins.c create mode 100644 src/plugins/lua_plugins.h diff --git a/Makefile.am b/Makefile.am index 39af6917..8aa4e09e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,6 +39,10 @@ ruby_sources = \ src/plugins/ruby_plugins.h src/plugins/ruby_plugins.c \ src/plugins/ruby_api.h src/plugins/ruby_api.c +lua_sources = \ + src/plugins/lua_plugins.h src/plugins/lua_plugins.c \ + src/plugins/lua_api.h src/plugins/lua_api.c + test_sources = \ tests/test_roster.c tests/test_common.c tests/test_history.c \ tests/test_autocomplete.c tests/testsuite.c tests/test_parser.c \ @@ -56,8 +60,14 @@ else with_ruby_sources = $(with_python_sources) endif +if BUILD_LUA_API +with_lua_sources = $(with_ruby_sources) $(lua_sources) +else +with_lua_sources = $(with_ruby_sources) +endif + bin_PROGRAMS = profanity -profanity_SOURCES = $(main_source) $(with_ruby_sources) +profanity_SOURCES = $(main_source) $(with_lua_sources) lib_LTLIBRARIES = libprofanity.la libprofanity_la_LDFLAGS=-module -avoid-version -shared @@ -68,7 +78,7 @@ library_include_HEADERS = src/plugins/profapi.h TESTS = tests/testsuite check_PROGRAMS = tests/testsuite -tests_testsuite_SOURCES = $(with_ruby_sources) $(test_sources) +tests_testsuite_SOURCES = $(with_lua_sources) $(test_sources) tests_testsuite_LDADD = -lheadunit -lstdc++ man_MANS = docs/profanity.1 diff --git a/configure.ac b/configure.ac index 76f8087d..81a5bf8b 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,14 @@ else AC_MSG_NOTICE([Python development package not found, Python plugin support disabled.]) fi +AX_PROG_LUA +AX_LUA_HEADERS +AX_LUA_LIBS +LUA_INCLUDE="-I/usr/include/lua5.1" +LUA_LIB="-llua5.1" +AM_CONDITIONAL([BUILD_LUA_API], [true]) +AC_DEFINE([HAVE_LUA], [1], [Lua support]) + # Checks for programs. AC_PROG_CC @@ -129,8 +137,8 @@ if test "x$PACKAGE_STATUS" = xdevelopment; then fi LIBS="$LIBS $DEPS_LIBS $NOTIFY_LIBS" -AM_LDFLAGS="$AM_LDFLAGS $PYTHON_LDFLAGS $RUBY_LDFLAGS" -AM_CPPFLAGS="$DEPS_CFLAGS $NOTIFY_CFLAGS $PYTHON_CPPFLAGS $RUBY_CPPFLAGS" +AM_LDFLAGS="$AM_LDFLAGS $PYTHON_LDFLAGS $RUBY_LDFLAGS $LUA_LIB" +AM_CPPFLAGS="$DEPS_CFLAGS $NOTIFY_CFLAGS $PYTHON_CPPFLAGS $RUBY_CPPFLAGS $LUA_INCLUDE" AC_SUBST(AM_LDFLAGS) AC_SUBST(AM_CFLAGS) diff --git a/src/plugins/lua_api.c b/src/plugins/lua_api.c new file mode 100644 index 00000000..0cb325f7 --- /dev/null +++ b/src/plugins/lua_api.c @@ -0,0 +1,386 @@ +/* + * lua_api.c + * + * Copyright (C) 2012, 2013 James Booth + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + */ + +#include + +#include + +#include "plugins/api.h" +#include "plugins/lua_api.h" +#include "plugins/callbacks.h" + +static int +lua_api_cons_alert(lua_State *L) +{ + api_cons_alert(); + return 0; +} + +static int +lua_api_cons_show(lua_State *L) +{ + const char *message = lua_tostring(L, 1); + api_cons_show(message); + return 0; +} + +static int +lua_api_register_command(lua_State *L) +{ +/* + const char *command_name = NULL; + int min_args = 0; + int max_args = 0; + const char *usage = NULL; + const char *short_help = NULL; + const char *long_help = NULL; + PyObject *p_callback = NULL; + + if (!PyArg_ParseTuple(args, "siisssO", &command_name, &min_args, &max_args, + &usage, &short_help, &long_help, &p_callback)) { + return Py_BuildValue(""); + } + + if (p_callback && PyCallable_Check(p_callback)) { + api_register_command(command_name, min_args, max_args, usage, + short_help, long_help, p_callback, python_command_callback); + } + + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_register_timed(lua_State *L) +{ +/* + PyObject *p_callback = NULL; + int interval_seconds = 0; + + if (!PyArg_ParseTuple(args, "Oi", &p_callback, &interval_seconds)) { + return Py_BuildValue(""); + } + + if (p_callback && PyCallable_Check(p_callback)) { + api_register_timed(p_callback, interval_seconds, python_timed_callback); + } + + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_notify(lua_State *L) +{ +/* + const char *message = NULL; + const char *category = NULL; + int timeout_ms = 5000; + + if (!PyArg_ParseTuple(args, "sis", &message, &timeout_ms, &category)) { + return Py_BuildValue(""); + } + + api_notify(message, category, timeout_ms); + + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_send_line(lua_State *L) +{ +/* + char *line = NULL; + if (!PyArg_ParseTuple(args, "s", &line)) { + return Py_BuildValue(""); + } + + api_send_line(line); + + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_get_current_recipient(lua_State *L) +{ +/* + char *recipient = api_get_current_recipient(); + if (recipient != NULL) { + return Py_BuildValue("s", recipient); + } else { + return Py_BuildValue(""); + } +*/ + return 0; +} + +static int +lua_api_log_debug(lua_State *L) +{ +/* + const char *message = NULL; + if (!PyArg_ParseTuple(args, "s", &message)) { + return Py_BuildValue(""); + } + api_log_debug(message); + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_log_info(lua_State *L) +{ +/* + const char *message = NULL; + if (!PyArg_ParseTuple(args, "s", &message)) { + return Py_BuildValue(""); + } + api_log_info(message); + return Py_BuildValue(""); +*/ +} + +static int +lua_api_log_warning(lua_State *L) +{ +/* + const char *message = NULL; + if (!PyArg_ParseTuple(args, "s", &message)) { + return Py_BuildValue(""); + } + api_log_warning(message); + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_log_error(lua_State *L) +{ +/* + const char *message = NULL; + if (!PyArg_ParseTuple(args, "s", &message)) { + return Py_BuildValue(""); + } + api_log_error(message); + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_win_exists(lua_State *L) +{ +/* + char *tag = NULL; + if (!PyArg_ParseTuple(args, "s", &tag)) { + return Py_BuildValue(""); + } + + if (api_win_exists(tag)) { + return Py_BuildValue("i", 1); + } else { + return Py_BuildValue("i", 0); + } +*/ + return 0; +} + +static int +lua_api_win_create(lua_State *L) +{ +/* + char *tag = NULL; + PyObject *p_callback = NULL; + + if (!PyArg_ParseTuple(args, "sO", &tag, &p_callback)) { + return Py_BuildValue(""); + } + + if (p_callback && PyCallable_Check(p_callback)) { + api_win_create(tag, p_callback, python_window_callback); + } + + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_win_focus(lua_State *L) +{ +/* + char *tag = NULL; + + if (!PyArg_ParseTuple(args, "s", &tag)) { + return Py_BuildValue(""); + } + + api_win_focus(tag); + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_win_process_line(lua_State *L) +{ +/* + char *tag = NULL; + char *line = NULL; + + if (!PyArg_ParseTuple(args, "ss", &tag, &line)) { + return Py_BuildValue(""); + } + + api_win_process_line(tag, line); + return Py_BuildValue(""); +*/ + return 0; +} + +static int +lua_api_win_show(lua_State *L) +{ +/* + char *tag = NULL; + char *line = NULL; + + if (!PyArg_ParseTuple(args, "ss", &tag, &line)) { + return Py_BuildValue(""); + } + + api_win_show(tag, line); + return Py_BuildValue(""); +*/ + return 0; +} + +void +lua_command_callback(PluginCommand *command, gchar **args) +{ +/* + PyObject *p_args = NULL; + int num_args = g_strv_length(args); + if (num_args == 0) { + if (command->max_args == 1) { + p_args = Py_BuildValue("(O)", Py_BuildValue("")); + PyObject_CallObject(command->callback, p_args); + Py_XDECREF(p_args); + } else { + PyObject_CallObject(command->callback, p_args); + } + } else if (num_args == 1) { + p_args = Py_BuildValue("(s)", args[0]); + PyObject_CallObject(command->callback, p_args); + Py_XDECREF(p_args); + } else if (num_args == 2) { + p_args = Py_BuildValue("ss", args[0], args[1]); + PyObject_CallObject(command->callback, p_args); + Py_XDECREF(p_args); + } else if (num_args == 3) { + p_args = Py_BuildValue("sss", args[0], args[1], args[2]); + PyObject_CallObject(command->callback, p_args); + Py_XDECREF(p_args); + } else if (num_args == 4) { + p_args = Py_BuildValue("ssss", args[0], args[1], args[2], args[3]); + PyObject_CallObject(command->callback, p_args); + Py_XDECREF(p_args); + } else if (num_args == 5) { + p_args = Py_BuildValue("sssss", args[0], args[1], args[2], args[3], args[4]); + PyObject_CallObject(command->callback, p_args); + Py_XDECREF(p_args); + } + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } +*/ +} + +void +lua_timed_callback(PluginTimedFunction *timed_function) +{ +/* + PyObject_CallObject(timed_function->callback, NULL); +*/ +} + +void +lua_window_callback(PluginWindowCallback *window_callback, char *tag, char *line) +{ +/* + PyObject *p_args = NULL; + p_args = Py_BuildValue("ss", tag, line); + PyObject_CallObject(window_callback->callback, p_args); + Py_XDECREF(p_args); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } +*/ +} +void +lua_api_init(lua_State *L) +{ + lua_pushcfunction(L, lua_api_cons_alert); + lua_setglobal(L, "prof_cons_alert"); + lua_pushcfunction(L, lua_api_cons_show); + lua_setglobal(L, "prof_cons_show"); + lua_pushcfunction(L, lua_api_register_command); + lua_setglobal(L, "prof_register_command"); + lua_pushcfunction(L, lua_api_register_timed); + lua_setglobal(L, "prof_register_timed"); + lua_pushcfunction(L, lua_api_send_line); + lua_setglobal(L, "prof_send_line"); + lua_pushcfunction(L, lua_api_notify); + lua_setglobal(L, "prof_notify"); + lua_pushcfunction(L, lua_api_get_current_recipient); + lua_setglobal(L, "prof_get_current_recipient"); + lua_pushcfunction(L, lua_api_log_debug); + lua_setglobal(L, "prof_log_debug"); + lua_pushcfunction(L, lua_api_log_info); + lua_setglobal(L, "prof_log_info"); + lua_pushcfunction(L, lua_api_log_warning); + lua_setglobal(L, "prof_log_warning"); + lua_pushcfunction(L, lua_api_log_error); + lua_setglobal(L, "prof_log_error"); + lua_pushcfunction(L, lua_api_win_exists); + lua_setglobal(L, "prof_win_exists"); + lua_pushcfunction(L, lua_api_win_create); + lua_setglobal(L, "prof_win_create"); + lua_pushcfunction(L, lua_api_win_focus); + lua_setglobal(L, "prof_win_focus"); + lua_pushcfunction(L, lua_api_win_show); + lua_setglobal(L, "prof_win_show"); + lua_pushcfunction(L, lua_api_win_process_line); + lua_setglobal(L, "prof_win_process_line"); +} diff --git a/src/plugins/lua_api.h b/src/plugins/lua_api.h new file mode 100644 index 00000000..6363e452 --- /dev/null +++ b/src/plugins/lua_api.h @@ -0,0 +1,36 @@ +/* + * lua_api.h + * + * Copyright (C) 2012, 2013 James Booth + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + */ + +#ifndef LUA_API_H +#define LUA_API_H + +#include + +void lua_env_init(void); +void lua_api_init(lua_State *L); +void lua_shutdown(void); + +void lua_command_callback(PluginCommand *command, gchar **args); +void lua_timed_callback(PluginTimedFunction *timed_function); +void lua_window_callback(PluginWindowCallback *window_callback, char *tag, char *line); + +#endif diff --git a/src/plugins/lua_plugins.c b/src/plugins/lua_plugins.c new file mode 100644 index 00000000..4a5f7ff3 --- /dev/null +++ b/src/plugins/lua_plugins.c @@ -0,0 +1,218 @@ +/* + * lua_plugins.c + * + * Copyright (C) 2012, 2013 James Booth + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + */ + +#include +#include + +#include +#include +#include + +#include "config/preferences.h" +#include "plugins/api.h" +#include "plugins/callbacks.h" +#include "plugins/plugins.h" +#include "plugins/lua_api.h" +#include "plugins/lua_plugins.h" +#include "ui/ui.h" + +static lua_State *L; + +void +lua_env_init(void) +{ + L = luaL_newstate(); + luaL_openlibs(L); + lua_api_init(L); +} + +ProfPlugin * +lua_plugin_create(const char * const filename) +{ + gchar *plugins_dir = plugins_get_dir(); + GString *abs_path = g_string_new(plugins_dir); + g_string_append(abs_path, "/"); + g_string_append(abs_path, filename); + + int load_result = luaL_loadfile(L, abs_path->str); + lua_check_error(load_result); + + // first call returns function + int call_result = lua_pcall(L, 0, 0, 0); + lua_check_error(call_result); + + // store reference to function table + int r = luaL_ref(L, LUA_REGISTRYINDEX); + + gchar *module_name = g_strndup(filename, strlen(filename) - 4); + + if (load_result == 0 && call_result == 0) { + cons_debug("LOADING PLUGIN"); + + ProfPlugin *plugin = malloc(sizeof(ProfPlugin)); + plugin->name = strdup(module_name); + plugin->lang = LANG_LUA; + plugin->module = &r; + plugin->init_func = lua_init_hook; + plugin->on_start_func = lua_on_start_hook; + plugin->on_connect_func = lua_on_connect_hook; + plugin->on_disconnect_func = lua_on_disconnect_hook; + plugin->on_message_received_func = lua_on_message_received_hook; + plugin->on_room_message_received_func = lua_on_room_message_received_hook; + plugin->on_private_message_received_func = lua_on_private_message_received_hook; + plugin->on_message_send_func = lua_on_message_send_hook; + plugin->on_private_message_send_func = lua_on_private_message_send_hook; + plugin->on_room_message_send_func = lua_on_room_message_send_hook; + plugin->on_shutdown_func = lua_on_shutdown_hook; + g_free(module_name); + g_free(plugins_dir); + g_string_free(abs_path, TRUE); + return plugin; + } else { + g_free(plugins_dir); + g_string_free(abs_path, TRUE); + g_free(module_name); + return NULL; + } +} + +void +lua_init_hook(ProfPlugin *plugin, const char * const version, const char * const status) +{ +/* + int *p_ref = (int *)plugin->module; + cons_debug("OK 1"); + + // push function table + lua_rawgeti(L, LUA_REGISTRYINDEX, *p_ref); + cons_debug("OK 2"); + + int res1 = lua_pcall(L, 0, 0, 0); + lua_check_error(res1); + cons_debug("OK 2.1"); + + // push key + lua_pushstring(L, "prof_init"); + cons_debug("OK 3"); + + // push args + lua_pushstring(L, version); + lua_pushstring(L, status); + cons_debug("OK 4"); + + // push function + lua_gettable(L, -2); + cons_debug("OK 5"); + + int res2 = lua_pcall(L, 0, 0, 0); + lua_check_error(res2); + cons_debug("OK 6"); +*/ +} + +void +lua_on_start_hook(ProfPlugin *plugin) +{ +} + +void +lua_on_connect_hook(ProfPlugin *plugin, const char * const account_name, + const char * const fulljid) +{ +} + +void +lua_on_disconnect_hook(ProfPlugin *plugin, const char * const account_name, + const char * const fulljid) +{ +} + +char * +lua_on_message_received_hook(ProfPlugin *plugin, const char * const jid, + const char *message) +{ + return NULL; +} + +char * +lua_on_private_message_received_hook(ProfPlugin *plugin, const char * const room, + const char * const nick, const char *message) +{ + return NULL; +} + +char * +lua_on_room_message_received_hook(ProfPlugin *plugin, const char * const room, + const char * const nick, const char *message) +{ + return NULL; +} + +char * +lua_on_message_send_hook(ProfPlugin *plugin, const char * const jid, + const char *message) +{ + return NULL; +} + +char * +lua_on_private_message_send_hook(ProfPlugin *plugin, const char * const room, + const char * const nick, const char *message) +{ + return NULL; +} + +char * +lua_on_room_message_send_hook(ProfPlugin *plugin, const char * const room, + const char *message) +{ + return NULL; +} + +void +lua_on_shutdown_hook(ProfPlugin *plugin) +{ +} + +void +lua_check_error(int value) +{ + if (value) { + cons_debug("%s", lua_tostring(L, -1)); + lua_pop(L, 1); + } else { + cons_debug("Success"); + } +} + +void +lua_plugin_destroy(ProfPlugin *plugin) +{ + free(plugin->name); + free(plugin); +} + +void +lua_shutdown(void) +{ + lua_close(L); +} diff --git a/src/plugins/lua_plugins.h b/src/plugins/lua_plugins.h new file mode 100644 index 00000000..efee50c0 --- /dev/null +++ b/src/plugins/lua_plugins.h @@ -0,0 +1,49 @@ +/* + * lua_plugins.h + * + * Copyright (C) 2012, 2013 James Booth + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + */ + +#ifndef LUA_PLUGINS_H +#define LUA_PLUGINS_H + +#include "plugins/plugins.h" + +ProfPlugin* lua_plugin_create(const char * const filename); + +void lua_init_hook(ProfPlugin *plugin, const char * const version, const char * const status); +void lua_on_start_hook(ProfPlugin *plugin); +void lua_on_connect_hook(ProfPlugin *plugin, const char * const account_name, const char * const fulljid); +void lua_on_disconnect_hook(ProfPlugin *plugin, const char * const account_name, const char * const fulljid); +char * lua_on_message_received_hook(ProfPlugin *plugin, const char * const jid, const char *message); +char * lua_on_private_message_received_hook(ProfPlugin *plugin, const char * const room, + const char * const nick, const char *message); +char * lua_on_room_message_received_hook(ProfPlugin *plugin, const char * const room, + const char * const nick, const char *message); +char * lua_on_message_send_hook(ProfPlugin *plugin, const char * const jid, const char *message); +char * lua_on_private_message_send_hook(ProfPlugin *plugin, const char * const room, + const char * const nick, const char *message); +char * lua_on_room_message_send_hook(ProfPlugin *plugin, const char * const room, + const char *message); +void lua_on_shutdown_hook(ProfPlugin *plugin); + +void lua_plugin_destroy(ProfPlugin *plugin); +void lua_check_error(int value); + +#endif diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 2423caf4..2b517cb0 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -40,6 +40,11 @@ #include "plugins/ruby_api.h" #endif +#ifdef PROF_HAVE_LUA +#include "plugins/lua_plugins.h" +#include "plugins/lua_api.h" +#endif + #include "plugins/c_plugins.h" #include "plugins/c_api.h" #include "ui/ui.h" @@ -56,6 +61,9 @@ plugins_init(void) #endif #ifdef PROF_HAVE_RUBY ruby_env_init(); +#endif +#ifdef PROF_HAVE_LUA + lua_env_init(); #endif c_env_init(); @@ -84,6 +92,15 @@ plugins_init(void) loaded = TRUE; } } +#endif +#ifdef PROF_HAVE_LUA + if (g_str_has_suffix(filename, ".lua")) { + ProfPlugin *plugin = lua_plugin_create(filename); + if (plugin != NULL) { + plugins = g_slist_append(plugins, plugin); + loaded = TRUE; + } + } #endif if (g_str_has_suffix(filename, ".so")) { ProfPlugin *plugin = c_plugin_create(filename); @@ -326,6 +343,11 @@ plugins_shutdown(void) if (plugin->lang == LANG_RUBY) { ruby_plugin_destroy(plugin); } +#endif +#ifdef PROF_HAVE_LUA + if (plugin->lang == LANG_LUA) { + lua_plugin_destroy(plugin); + } #endif if (plugin->lang == LANG_C) { c_plugin_destroy(plugin); @@ -338,6 +360,9 @@ plugins_shutdown(void) #endif #ifdef PROF_HAVE_RUBY ruby_shutdown(); +#endif +#ifdef PROF_HAVE_LUA + lua_shutdown(); #endif c_shutdown(); } diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index 7873ab87..a1526e5c 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -26,6 +26,7 @@ typedef enum { LANG_PYTHON, LANG_RUBY, + LANG_LUA, LANG_C } lang_t;