lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hello list,

I'm currently writing a binding for linenoise
(https://github.com/antirez/linenoise), and I'm trying to make sure and
do things the "right way" when it comes to binding its completion
callbacks.

The signature for the callback setting function is this:

void linenoiseSetCompletionCallback(void (*callback)(const char *, linenoiseCompletions *));

and this is what my wrapper looks like:

static int completionFuncRef;
static lua_State *completionState;

static void completionCallbackWrapper(const char *line, linenoiseCompletions *completions)
{
    lua_State *L = completionState;
    int status;

    lua_rawgeti(L, LUA_REGISTRYINDEX, completionFuncRef);
    lua_pushlightuserdata(L, completions);
    lua_pushstring(L, line);

    /* XXX error handling */
    status = lua_pcall(L, 2, 0, 0); 
}

static int l_setcompletion(lua_State *L)
{
    luaL_checktype(L, 1, LUA_TFUNCTION);

    lua_pushvalue(L, 1);
    completionFuncRef = luaL_ref(L, LUA_REGISTRYINDEX);
    linenoiseSetCompletionCallback(completionCallbackWrapper);
    completionState = L;

    return 0;
}

Obviously, this implementation has some holes; for instance, this example will crash:

local ln = require 'linenoise'

local co = coroutine.create(function()
  ln.setcompletion(function(completions, line)
    ln.addcompletion(completions, 'foo')
    ln.addcompletion(completions, 'bar')
    ln.addcompletion(completions, 'baz')
  end)
end)

coroutine.resume(co)

co = nil 

collectgarbage 'collect'

local line = ln.linenoise '> '
print(line)

Can someone give me some pointers on the proper way to bind a library that uses callbacks, especially one that doesn't
allow you to thread your own userdata through the callbacks?  Coroutines make it tricky, and my understanding is that
storing things in global variables in the binding are a faux pas.

Thanks,
Rob

Attachment: signature.asc
Description: PGP signature