So, I've decided to make an attempt at some form of (minimal) autocompletion on-demand. And since the linenoise library is already include, I said... why not?.
However, I keep having issues and I have no idea if it has to do with the linenoise library per se, its Nim version or my use of it.
So... here's what I'm trying (perfectly working example code):
import linenoise, rdstdin, strutils
when isMainModule:
var cback : CompletionCallback =
proc (a2: cstring; a3: ptr Completions) {.cdecl.}=
if a2[0]=='h':
addCompletion(a3, $("hi"))
addCompletion(a3, $("hello"))
setCompletionCallback(cback.addr)
var got: string = ""
while got.strip != "quit":
got = readLineFromStdin("$: ")
echo "got: " & got
The problem is: when I trigger the autocompletion (by typing h and then pressing TAB) the whole thing goes wrong:
Traceback (most recent call last)
/../test9.nim(15) test9
/Users/drkameleon/.choosenim/toolchains/nim-1.4.4/lib/impure/rdstdin.nim(56) readLineFromStdin
SIGBUS: Illegal storage access. (Attempt to read from nil?)
What am I messing up?
Common mistake when interfacing with C libraries from Nim. A proc in Nim is already a pointer behind the scenes, so when you use cback.addr you're essentially getting a linenoiseCompletionCallback ** and not a linenoiseCompletionCallback *. What you need to do is cast the callback to a ptr CompletionCallback, this also means you don't have to store it in a variable (although you could if you wanted to):
nim
import linenoise, rdstdin, strutils
when isMainModule:
proc cback(a2: cstring; a3: ptr Completions) {.cdecl.}=
if a2[0]=='h':
addCompletion(a3, $("hi"))
addCompletion(a3, $("hello"))
setCompletionCallback(cast[ptr CompletionCallback](cback))
var got: string = ""
while got.strip != "quit":
got = readLineFromStdin("$: ")
echo "got: " & got
Awesomeness! Thanks a lot!
I knew I was messing something with the pointers, but wasn't really sure what exactly.
Re: the wrapper, given that I'll also give a shot to hints (linenoiseSetHintsCallback, etc), I'm simply thinking of re-implementing the wrapper.
In any case, thanks again! :D
IMO this is a bug in setCompletionCallback declaration that should be fixed; requiring cast[ptr CompletionCallback] is a bad API.
I'm simply thinking of re-implementing the wrapper.
alternatively, PR's welcome to improve lib/wrappers/linenoise/linenoise.nim so that all existing clients benefit from this.
see related PR's that refer to linenoise for intended future directions