As an interlude from talking about Elixir and sound generation, I thought I’d mention something I’ve been hacking on.

If you remember from the article Elixir + AMY = BEEP!, I made a CLI tool to use for learning AMY’s wire protocol that lets you type in a string, hit enter, and have AMY make sound from that string.

That CLI tool was using C’s standard I/O library, which if you didn’t already know, doesn’t have cursor handling or text editing abilities at all.

In the open source world, the well-known option to enable editing is GNU Readline, which is perfectly capabile, but as is with many GNU libraries, is a bit large for what it does.

Another option is antirez’ linenoise library, which in character for many things antirez has created is minimal, and beautiful.

The option I wound up working with is jart’s bestline library, which is inspired by anterez’ but with jart’s extraordinary eye for completeness and minimal resulting binary size.

There’s not much to say with regards to how I use bestline in my code, as it’s a straightforward pattern like this:

#include <stdio.h>
#include "bestline.h"
int main(int argc, char *argv[]) {
    char *l;
    while (1) {
        l = bestline("r> ");
        if (l == NULL) break;
        printf("YOU TYPED -> %s\n", l);
        free(l);
    }
    return 0;
}

It’s notable that this pattern, at least in single process / single-threaded programs, means the code it’s linked with can’t respond to events while it’s in the bestline function.

I chatted with jart about this and she suggested an elegant way to add this functionality to bestline that would allow appearingly parallel functions, but in the end I chose to add a function pointer / callback style to allow use of a custom read function that’s responsible for demultiplexing input.

The new functions I’ve added to bestline are: