Merge pull request #912 from andreasb242/scripting

Working on scripting / lua API
presentation
andreasb242 7 years ago committed by GitHub
commit cb81180eac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      plugins/Example/main.lua
  2. 33
      plugins/Example/var_dump.lua
  3. 81
      src/plugin/Plugin.cpp
  4. 22
      src/plugin/Plugin.h
  5. 13
      src/plugin/PluginController.cpp
  6. 75
      src/plugin/luapi_application.h

@ -1,11 +1,19 @@
-- This is an example Xournal++ Plugin - copy this to get started
print("Hello from Lua Plugin\n");
var_dump = require "var_dump"
-- Register all Toolbar actions and intialize all UI stuff
-- Register all Toolbar actions and intialize all UI stuff
function initUi()
print("Plugin initUi called\n");
end
print("Hello from Example: Plugin initUi called\n");
ref = app.registerUi({["menu"] = "Test123", ["callback"] = "exampleCallback"});
print("Menu reference:");
var_dump(ref);
app.msgbox("Test123", "yes,no")
print("Example plugin registered\n");
end
-- Callback if the menu item is executed
function exampleCallback()
app.msgbox("Test123", "yes,no");
end

@ -0,0 +1,33 @@
-- Source: https://gist.github.com/lunixbochs/5b0bb27861a396ab7a86#file-var_dump-lua-L1
local function string(o)
return '"' .. tostring(o) .. '"'
end
local function recurse(o, indent)
if indent == nil then indent = '' end
local indent2 = indent .. ' '
if type(o) == 'table' then
local s = indent .. '{' .. '\n'
local first = true
for k,v in pairs(o) do
if first == false then s = s .. ', \n' end
if type(k) ~= 'number' then k = string(k) end
s = s .. indent2 .. '[' .. k .. '] = ' .. recurse(v, indent2)
first = false
end
return s .. '\n' .. indent .. '}'
else
return string(o)
end
end
local function var_dump(...)
local args = {...}
if #args > 1 then
var_dump(args)
else
print(recurse(args[1]))
end
end
return var_dump

@ -86,18 +86,26 @@ void Plugin::registerToolbar()
return;
}
// TODO Errorhandling etc.
// lua_register
// lua_atpanic
inInitUi = true;
if (callFunction("initUi"))
lua_getglobal(lua, "initUi");
if (lua_isfunction (lua, -1) == 1)
{
g_message("Plugin «%s» UI initialized", name.c_str());
if (callFunction("initUi"))
{
g_message("Plugin «%s» UI initialized", name.c_str());
}
else
{
g_warning("Plugin «%s» init failed!", name.c_str());
}
}
else
{
g_message("Plugin «%s» has no UI init", name.c_str());
}
inInitUi = false;
}
/**
@ -110,6 +118,27 @@ string Plugin::getName()
return name;
}
/**
* @return Flag to check if init ui is currently running
*/
bool Plugin::isInInitUi()
{
XOJ_CHECK_TYPE(Plugin);
return inInitUi;
}
/**
* Register a menu item
*
* @return Internal ID, can e.g. be used to disable the menu
*/
int Plugin::registerMenu(string menu, string callback)
{
// TODO
return 0;
}
/**
* Load ini file
*/
@ -150,10 +179,43 @@ void Plugin::registerXournalppLibs(lua_State* lua)
for (const luaL_Reg* lib = loadedlibs; lib->func; lib++)
{
luaL_requiref(lua, lib->name, lib->func, 1);
lua_pop(lua, 1); /* remove lib */
// remove lib
lua_pop(lua, 1);
}
}
/**
* Add the plugin folder to the lua path
*/
void Plugin::addPluginToLuaPath()
{
lua_getglobal(lua, "package");
// get field "path" from table at top of stack (-1)
lua_getfield(lua, -1, "path");
// For now: limit the include path to the current plugin folder, for security and compatibility reasons
// grab path string from top of stack
// string curPath = lua_tostring(lua, -1);
// curPath.append(";");
string curPath;
curPath.append(path);
curPath.append("/?.lua");
// get rid of the string on the stack we just pushed on line 5
lua_pop(lua, 1);
// push the new one
lua_pushstring(lua, curPath.c_str());
// set the field "path" in table at -2 with value at top of stack
lua_setfield(lua, -2, "path");
// get rid of package table from top of stack
lua_pop(lua, 1);
}
/**
* Load the plugin script
*/
@ -196,6 +258,8 @@ void Plugin::loadScript()
registerXournalppLibs(lua);
addPluginToLuaPath();
// Run the loaded Lua script
if (lua_pcall(lua, 0, 0, 0) != LUA_OK)
{
@ -218,7 +282,10 @@ bool Plugin::callFunction(string fnc)
// Run the function
if (lua_pcall(lua, 0, 0, 0))
{
// Failed
const char* errMsg = lua_tostring(lua, -1);
XojMsgBox::showPluginMessage(name, errMsg, MSG_BT_OK, true);
g_warning("Error in Plugin: «%s», error: «%s»", name.c_str(), errMsg);
return false;
}

@ -41,6 +41,18 @@ public:
*/
string getName();
/**
* @return Flag to check if init ui is currently running
*/
bool isInInitUi();
/**
* Register a menu item
*
* @return Internal ID, can e.g. be used to disable the menu
*/
int registerMenu(string menu, string callback);
private:
/**
* Load ini file
@ -62,6 +74,11 @@ private:
*/
void registerXournalppLibs(lua_State* lua);
/**
* Add the plugin folder to the lua path
*/
void addPluginToLuaPath();
public:
/**
* Get Plugin from lua engine
@ -101,6 +118,11 @@ private:
*/
lua_State* lua = NULL;
/**
* Flag to check if init ui is currently running
*/
bool inInitUi = false;
/**
* Flag if the plugin is valid / correct loaded
*/

@ -4,6 +4,8 @@
#include "control/Control.h"
#include "gui/GladeSearchpath.h"
#include <StringUtils.h>
#include <config-features.h>
@ -13,7 +15,16 @@ PluginController::PluginController(Control* control)
XOJ_INIT_TYPE(PluginController);
#ifdef ENABLE_PLUGINS
loadPluginsFrom(control->getGladeSearchPath()->getFirstSearchPath() + "/../plugins/");
string path = control->getGladeSearchPath()->getFirstSearchPath();
if (StringUtils::endsWith(path, "ui"))
{
path = path.substr(0, path.length() - 2) + "plugins";
}
else
{
path += "/../plugins";
}
loadPluginsFrom(path);
#endif
}

@ -54,16 +54,77 @@ static int applib_msgbox(lua_State* L)
}
/**
* Allow to register menupoints or toolbar icons, this needs to be called from initUi
*/
static int applib_registerUi(lua_State* L)
{
Plugin* plugin = Plugin::getPluginFromLua(L);
if (!plugin->isInInitUi())
{
luaL_error(L, "registerUi needs to be called within initUi()");
}
// discard any extra arguments passed in
lua_settop(L, 1);
luaL_checktype(L, 1, LUA_TTABLE);
// Now to get the data out of the table
// 'unpack' the table by putting the values onto
// the stack first. Then convert those stack values
// into an appropriate C type.
lua_getfield(L, 1, "menu");
lua_getfield(L, 1, "callback");
// stack now has following:
// 1 = {"menu"="MenuName", callback="functionName"}
// -2 = "MenuName"
// -1 = "functionName"
const char* menu = luaL_optstring(L, -2, NULL);
const char* callback = luaL_optstring(L, -1, NULL);
if (callback == NULL)
{
luaL_error(L, "Missing callback function!");
}
int menuId = -1;
int toolbarId = -1;
if (menu)
{
plugin->registerMenu(menu, callback);
}
// Make sure to remove all vars which are put to the stack before!
lua_pop(L, 2);
// Add return value to the Stack
lua_createtable(L, 0, 2);
lua_pushstring(L, "menuId");
lua_pushinteger(L, menuId);
lua_settable(L, -3); /* 3rd element from the stack top */
lua_pushstring(L, "toolbarId");
lua_pushinteger(L, toolbarId);
lua_settable(L, -3);
return 1;
}
static const luaL_Reg applib[] = {
{"msgbox", applib_msgbox},
{ "msgbox", applib_msgbox },
{ "registerUi", applib_registerUi },
// Placeholder
{"MSG_BT_OK", NULL},
{"MSG_BT_YES", NULL},
{"MSG_BT_NO", NULL},
{"MSG_BT_CANCEL", NULL},
// Placeholder
{"MSG_BT_OK", NULL},
{"MSG_BT_YES", NULL},
{"MSG_BT_NO", NULL},
{"MSG_BT_CANCEL", NULL},
{NULL, NULL}
{NULL, NULL}
};
/**

Loading…
Cancel
Save