Skip to content

Commit

Permalink
Lua API for Mutt's config and commandline
Browse files Browse the repository at this point in the history
* adds the following to Mutt's API:
 * `:lua` to execute a line of Lua
 * `:lua-source` to load and run a Lua source file
* exposes the following Mutt API in Lua:
 * `mutt.message()` To write a message on Mutt's command line
 * `mutt.error()` To write an error message on Mutt's command line
 * `mutt.enter()` run an arbitrary Mutt command, like with `:enter-command`
 * `mutt.get()` get a variable from Mutt
 * `mutt.set()` sets a variable from Mutt (with type enforcement)
 * `mutt.call()` calls a command available in mutt, with arguments
 * `mutt.command.*` exposes all the commands from within Mutt
* For some technical details:
 * proper error handling of the Lua interpreter
 * exposed mutt_option_set and mutt_option_get from init

fixes: #153

Signed-off-by: Guyzmo <guyzmo+github+pub@m0g.net>
  • Loading branch information
guyzmo committed Mar 1, 2017
1 parent 791e289 commit 7ca16ac
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 39 deletions.
18 changes: 16 additions & 2 deletions contrib/lua/test_lua-api_spec.lua
Expand Up @@ -34,8 +34,22 @@ describe('lua API', function()
test_config_type("visual", "vim", "fubar")
end)

it('works with DT_NUM', function()
test_config_type("connect_timeout",69,42)
it('works with DT_NUM and positive ints', function()
test_config_type("connect_timeout", 69, 42)
test_config_type("connect_timeout", 42, 69)
end)

it('works with DT_NUM and negative ints', function()
test_config_type("connect_timeout", 69, -42)
test_config_type("connect_timeout", -42, 69)
end)

it('works with DT_NUM and does not accept positive int overflow', function()
assert.has_error(function() test_config_type("connect_timeout", 69, 33000) end)
end)

it('works with DT_NUM and does not accept negative int overflow', function()
assert.has_error(function() test_config_type("connect_timeout", 69, -33000) end)
end)

it('works with DT_BOOL', function()
Expand Down
72 changes: 35 additions & 37 deletions mutt_lua.c
Expand Up @@ -25,11 +25,12 @@
#include <lualib.h>

#include <stdbool.h>
#include <limits.h>

#include "mutt.h"
#include "mutt_commands.h"
#include "mutt_options.h"
#include "mutt_lua.h"
#include "mutt.h"
#include "mutt_options.h"
#include "mx.h"

static int _handle_panic(lua_State *l)
Expand All @@ -46,7 +47,6 @@ static int _handle_error(lua_State *l)
lua_pop(l, 1);
return -1;
}
// #define protect_call(CALL, L, RV) if (CALL) RV = _handle_error(L);

static int _lua_mutt_call(lua_State *l)
{
Expand All @@ -61,7 +61,7 @@ static int _lua_mutt_call(lua_State *l)
mutt_buffer_init(&err);

err.dsize = STRING;
err.data = safe_malloc(err.dsize);
err.data = safe_malloc(err.dsize);

if (lua_gettop(l) == 0)
{
Expand All @@ -85,7 +85,7 @@ static int _lua_mutt_call(lua_State *l)
}

expn.data = expn.dptr = buffer;
expn.dsize = mutt_strlen(buffer);
expn.dsize = mutt_strlen(buffer);

if (command->func(&token, &expn, command->data, &err))
{
Expand All @@ -112,7 +112,7 @@ static int _lua_mutt_set(lua_State *l)
BUFFER err;
const char *param = lua_tostring(l, -2);
mutt_debug(2, " * _lua_mutt_set(%s)\n", param);
struct option_t *value = safe_malloc(sizeof(struct option_t));
struct option_t *value = safe_malloc(sizeof(struct option_t));
const struct option_t *tmp = mutt_option_get(param);
if (tmp == NULL)
{
Expand All @@ -132,12 +132,10 @@ static int _lua_mutt_set(lua_State *l)
case DT_PATH:
case DT_SORT:
case DT_STR:
{
value->data = (long) safe_strdup(lua_tostring(l, -1));
rv = mutt_option_set(value, &err);
rv = mutt_option_set(value, &err);
FREE(&value->data);
break;
}
case DT_QUAD:
value->data = (long) lua_tointeger(l, -1);
if ((value->data != MUTT_YES) && (value->data != MUTT_NO) &&
Expand All @@ -160,12 +158,22 @@ static int _lua_mutt_set(lua_State *l)
}
break;
case DT_NUM:
value->data = (long) lua_tointeger(l, -1);
rv = mutt_option_set(value, &err);
break;
{
lua_Integer i = lua_tointeger(l, -1);
if ((i > SHRT_MIN) && (i < SHRT_MAX)) {
value->data = lua_tointeger(l, -1);
rv = mutt_option_set(value, &err);
}
else
{
luaL_error(l, "Integer overflow of %d, not in %d-%d", i, SHRT_MIN, SHRT_MAX);
rv = -1;
}
break;
}
case DT_BOOL:
value->data = (long) lua_toboolean(l, -1);
rv = mutt_option_set(value, &err);
rv = mutt_option_set(value, &err);
break;
default:
luaL_error(l, "Unsupported Mutt parameter type %d for %s", value->type, param);
Expand Down Expand Up @@ -209,7 +217,7 @@ static int _lua_mutt_get(lua_State *l)
if (!mutt_strncmp("my_", param, 3))
{
char *option = (char *) opt->option;
char *value = (char *) opt->data;
char *value = (char *) opt->data;
lua_pushstring(l, value);
FREE(&option);
FREE(&value);
Expand Down Expand Up @@ -238,7 +246,7 @@ static int _lua_mutt_get(lua_State *l)
return 1;
}
case DT_NUM:
lua_pushinteger(l, *((long *) opt->data));
lua_pushinteger(l, (signed short)*((unsigned long *) opt->data));
return 1;
case DT_BOOL:
lua_pushboolean(l, option(opt->data));
Expand All @@ -257,13 +265,13 @@ static int _lua_mutt_enter(lua_State *l)
mutt_debug(2, " * _lua_mutt_enter()\n");
BUFFER token, err;
char *buffer = safe_strdup(lua_tostring(l, -1));
int rv = 0;
int rv = 0;

mutt_buffer_init(&err);
mutt_buffer_init(&token);

err.dsize = STRING;
err.data = safe_malloc(err.dsize);
err.data = safe_malloc(err.dsize);

if (mutt_parse_rc_line(buffer, &token, &err))
{
Expand Down Expand Up @@ -313,23 +321,22 @@ static void _lua_expose_command(void *p, const struct command_t *cmd)
}

static const luaL_Reg luaMuttDecl[] = {
{ "set", _lua_mutt_set }, { "get", _lua_mutt_get },
{ "call", _lua_mutt_call }, { "enter", _lua_mutt_enter },
{ "print", _lua_mutt_message }, { "message", _lua_mutt_message },
{ "error", _lua_mutt_error }, { NULL, NULL }
};
{"set", _lua_mutt_set}, {"get", _lua_mutt_get},
{"call", _lua_mutt_call}, {"enter", _lua_mutt_enter},
{"print", _lua_mutt_message}, {"message", _lua_mutt_message},
{"error", _lua_mutt_error}, {NULL, NULL}};

#define lua_add_lib_member(L, T, K, V, DT) \
lua_pushstring(L, K); \
DT(L, V); \
lua_settable(L, T);
#define lua_add_lib_member(LUA, TABLE, KEY, VALUE, DATATYPE_HANDLER) \
lua_pushstring(LUA, KEY); \
DATATYPE_HANDLER(LUA, VALUE); \
lua_settable(LUA, TABLE);

static int luaopen_mutt_decl(lua_State *l)
{
mutt_debug(2, " * luaopen_mutt()\n");
luaL_newlib(l, luaMuttDecl);
int lib_idx = lua_gettop(l);
/* table_idx, key value, value's type */
/* table_idx, key value, value's type */
lua_add_lib_member(l, lib_idx, "VERSION", mutt_make_version(), lua_pushstring);
lua_add_lib_member(l, lib_idx, "QUAD_YES", MUTT_YES, lua_pushinteger);
lua_add_lib_member(l, lib_idx, "QUAD_NO", MUTT_NO, lua_pushinteger);
Expand Down Expand Up @@ -368,12 +375,6 @@ static bool _lua_init(lua_State **l)
return true;
}

// static void _lua_close(void)
// {
// printf(" * lua_close()");
// lua_close(Lua);
// }

// Public API -------------------------------------------------------------------

lua_State *Lua = NULL;
Expand All @@ -382,19 +383,16 @@ int mutt_lua_parse(BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
{
_lua_init(&Lua);
mutt_debug(2, " * mutt_lua_parse(%s)\n", tmp->data);
// printf(" * mutt_lua_parse(%s)\n", s->dptr);

if (luaL_dostring(Lua, s->dptr))
{
mutt_debug(2, " * mutt_lua_parse(%s) → failure\n", s->dptr);
// printf(" * mutt_lua_parse(%s) → failure\n", s->dptr);
snprintf(err->data, err->dsize, _("%s: %s"), s->dptr, lua_tostring(Lua, -1));
lua_pop(Lua, 1);
/* pop error message from the stack */
lua_pop(Lua, 1);
return -1;
}
mutt_debug(2, " * mutt_lua_parse(%s) → success\n", s->dptr);
// printf(" * mutt_lua_parse(%s) → success\n", tmp->data);
return 2;
}

Expand Down

0 comments on commit 7ca16ac

Please sign in to comment.