lua-users home
lua-l archive

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


First of all, completionCallbackWrapper should be
static void completionCallbackWrapper(lua_State*L,int ref,const char *line, linenoiseCompletions *completions)
and you should bind { lua_State, ref, completionCallbackWrapper } as a function pass to linenoise.
Second, at the end of coroutine, you should call ln.clearcompletion()
and before 'co = nil' you should call ln.clearcompletion(co)
I suppose there is no automate way to handle this.

2011/10/21 Rob Hoelz <rob@hoelz.ro>
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