I wrote underline when I needed a CLI for an embedded system without operating system and a very limited (and horribly outdated) libc support. My original thought was to port libreadline, the de-facto standard. But in readline’s own words:
“It’s too big and too slow” (man 3 readline – Bugs section).
Underline implements a compatible (although partial) commandline library. The entire implementation is less than 500 lines of code and has some nice features in it:
- Standard synchronic readline API for basic usage
- Fully asynchronous API
- History support (although quite limited)
- Hotkeys support (for home/end etc.)
- Basic VT-100 compatibility. Support standard termios library or custom VT implementation.
- Fits embeeded systems – No memory allocations, small code size
The asynchronous API is suitable for systems requiring high performance. It was tested on Posix AIO, Arduino and RTOS like systems.
Clone the code from the github repo at: https://github.com/achayun/underline
The implementation is, well, minimal. There’s lots to do, especially if you have special needs.
Custom hotkey mapping – At the moment all hotkeys are hardcoded. Should be user override-able.
Command completion – Hitting TAB should call a user defined callback with the partial current word (and the full line).
Dynamic history buffer – The history buffer is static and not optimized. You could change the defines to get more history or implement a custom memory allocator or an arena if you need dynamic history size.
Dynamic prompt – Prompt can be used for fun stuff like showing the current path, Git branch or number of unread emails. Functionality to update the prompt with some helpers is a nice feature.
Terminal width/multiline support – Receive resize events from terminal and support multiline prompt (like bash’s ‘\’ or iPython’s Shift+Enter)
Thread safety – completely not written to be thread safe. The synchrous API has a static context and none of the functions was tested to be reentrant. If you want, make the context struct TLS or protect it and check the functions.
More modular code – History should probably be a module