Isocline is a pure C library that can be used as an alternative to the GNU readline library

Related tags

Utilities isocline
Overview

Isocline: a portable readline alternative.

Isocline is a pure C library that can be used as an alternative to the GNU readline library (latest release v1.0.2, 2021-08-23).

  • Small: less than 8k lines and can be compiled as a single C file without any dependencies or configuration (e.g. gcc -c src/isocline.c).

  • Portable: works on Unix, Windows, and macOS, and uses a minimal subset of ANSI escape sequences.

  • Features: extensive multi-line editing mode (shift-tab), (24-bit) color, history, completion, unicode, undo/redo, incremental history search, inline hints, syntax highlighting, brace matching, closing brace insertion, auto indentation, graceful fallback, support for custom allocators, etc.

  • License: MIT.

  • Comes with a Haskell binding (System.Console.Isocline.

Enjoy, Daan

Demo

recording

Shows in order: unicode, syntax highlighting, brace matching, jump to matching brace, auto indent, multiline editing, 24-bit colors, inline hinting, filename completion, and incremental history search.
(screen capture was made with termtosvg by Nicolas Bedos)

Usage

Include the isocline header in your C or C++ source:

#include <include/isocline.h>

and call ic_readline to get user input with rich editing abilities:

char* input;
while( (input = ic_readline("prompt")) != NULL ) { // ctrl+d/c or errors return NULL
  printf("you typed:\n%s\n", input); // use the input
  free(input);  
}

See the example for a full example with completion, syntax highligting, history, etc.

Run the Example

You can compile and run the example as:

$ gcc -o example -Iinclude test/example.c src/isocline.c
$ ./example

or, the Haskell example:

$ ghc -ihaskell test/Example.hs src/isocline.c
$ ./test/Example

Editing with Isocline

Isocline tries to be as compatible as possible with standard GNU Readline key bindings.

Overview:

       home/ctrl-a       cursor     end/ctrl-e
         ┌─────────────────┼───────────────┐    (navigate)
         │     ctrl-leftctrl-right   │
         │         ┌───────┼──────┐        │    ctrl-r   : search history
         ▼         ▼       ▼      ▼        ▼    tab      : complete word
  prompt> it is the quintessential language     shift-tab: insert new line
         ▲         ▲              ▲        ▲    esc      : delete input, done
         │         └──────────────┘        │    ctrl-z   : undoalt-backsp        alt-d      │
         └─────────────────────────────────┘    (delete)
       ctrl-u                          ctrl-k

Note: on macOS, the meta (alt) key is not directly available in most terminals. Terminal/iTerm2 users can activate the meta key through TerminalPreferencesSettingsUse option as meta key.

Key Bindings

These are also shown when pressing F1 on a Isocline prompt. We use ^ as a shorthand for ctrl-:

Navigation
left,^b go one character to the left
right,^f go one character to the right
up go one row up, or back in the history
down go one row down, or forward in the history
^left go to the start of the previous word
^right go to the end the current word
home,^a go to the start of the current line
end,^e go to the end of the current line
pgup,^home go to the start of the current input
pgdn,^end go to the end of the current input
alt-m jump to matching brace
^p go back in the history
^n go forward in the history
^r,^s search the history starting with the current word
Deletion
del,^d delete the current character
backsp,^h delete the previous character
^w delete to preceding white space
alt-backsp delete to the start of the current word
alt-d delete to the end of the current word
^u delete to the start of the current line
^k delete to the end of the current line
esc delete the current input, or done with empty input
Editing
enter accept current input
^enter,^j,shift-tab create a new line for multi-line input
^l clear screen
^t swap with previous character (move character backward)
^z,^_ undo
^y redo
tab try to complete the current input
Completion menu
enter,left use the currently selected completion
1 - 9 use completion N from the menu
tab, down select the next completion
shift-tab, up select the previous completion
esc exit menu without completing
pgdn,^enter,^j show all further possible completions
Incremental history search
enter use the currently found history entry
backsp,^z go back to the previous match (undo)
tab,^r,up find the next match
shift-tab,^s,down find an earlier match
esc exit search

Build the Library

Build as a Single Source

Copy the sources (in include and src) into your project, or add the library as a submodule:

$ git submodule add https://github.com/daanx/isocline

and add isocline/src/isocline.c to your build rules -- no configuration is needed.

Build with CMake

Clone the repository and run cmake to build a static library (.a/.lib):

$ git clone https://github.com/daanx/isocline
$ cd isocline
$ mkdir -p build/release
$ cd build/release
$ cmake ../..
$ cmake --build .

This builds a static library libisocline.a (or isocline.lib on Windows) and the example program:

$ ./example

Build the Haskell Library

See the Haskell readme for instructions to build and use the Haskell library.

API Reference

Motivation

Isocline was created for use in the Koka interactive compiler. This required: pure C (no dependency on a C++ runtime or other libraries), portable (across Linux, macOS, and Windows), unicode support, a BSD-style license, and good functionality for completion and multi-line editing.

Some other excellent libraries that we considered: GNU readline, editline, linenoise, replxx, and Haskeline.

Formatted Output

Isocline also exposes functions for rich terminal output as ic_print (and ic_println and ic_printf). Inspired by the (Python) Rich library, this supports a form of bbcode's to format the output:

ic_println( "[b]bold [red]and red[/red][/b]" );

Each print automatically closes any open tags that were not yet closed. Also, you can use a general close tag as [/] to close the innermost tag, so the following print is equivalent to the earlier one:

ic_println( "[b]bold [red]and red[/]" );

There can be multiple styles in one tag (where the first name is used for the closing tag):

ic_println( "[u #FFD700]underlined gold[/]" );

Sometimes, you need to display arbitrary messages that may contain sequences that you would not like to be interpreted as bbcode tags. One way to do this is the [!tag] which ignores formatting up to a close tag of the form [/tag].

ic_printf( "[red]red? [!pre]%s[/pre].\n", "[blue]not blue!" );

Predefined styles include b (bold), u (underline), i (italic), and r (reverse video), but you can (re)define any style yourself as:

ic_style_def("warning", "crimson u");

and use them like any builtin style or property:

ic_println( "[warning]this is a warning![/]" );

which is great for adding themes to your application.

Each ic_print function always closes any unclosed tags automatically. To open a style persistently, use ic_style_open with a matching ic_style_close which scopes over any ic_print statements in between.

ic_style_open("warning");
ic_println("[b]crimson underlined and bold[/]");
ic_style_close();

Advanced

BBCode Format

An open tag can have multiple white space separated entries that are either a style name, or a primitive property[=value].

Styles

Isocline provides the following builtin styles as property shorthands: b (bold), u (underline), i (italic), r (reverse video), and some builtin styles for syntax highlighting: keyword, control (control-flow keywords), string, comment, number, type, constant.

Predefined styles used by Isocline itself are:

  • ic-prompt: prompt style, e.g. ic_style_def("ic-prompt", "yellow on blue").
  • ic-info: information (like the numbers in a completion menu).
  • ic-diminish: dim text (used for example in history search).
  • ic-emphasis: emphasized text (also used in history search).
  • ic-hint: color of an inline hint.
  • ic-error: error color (like an unmatched brace).
  • ic-bracematch: color of matching parenthesis.

Properties

Boolean properties are by default on:

  • bold [=(on|off)]
  • italic [=(on|off)]
  • underline [=(on|off)]
  • reverse [=(on|off)]

Color properties can be assigned a color:

  • color=color
  • bgcolor=color
  • color: equivalent to color=color.
  • on color: equivalent to bgcolor=color.

A color value can be specified in many ways:

  • any standard HTML color name.
  • any of the 16 standard ANSI color names by prefixing ansi- (like ansi-black or ansi-maroon).
    The actual color value of these depend on the a terminal theme.
  • #rrggbb or #rgb for a specific 24-bit color.
  • ansi-color=idx: where 0 <= idx <= 256 specifies an entry in the standard ANSI 256 color palette, where 256 is used for the ANSI default color.

Environment Variables

  • NO_COLOR: if present no colors are displayed.
  • CLICOLOR=1: if set, the LSCOLORS or LS_COLORS environment variables are used to colorize filename completions.
  • COLORTERM=(truecolor|256color|16color|8color|monochrome): enable a certain color palette, see the next section.
  • TERM: used on some systems to determine the color

Colors

Isocline supports 24-bit colors and any RGB colors are automatically mapped to a reduced palette on older terminals if these do not support true color. Detection of full color support is not always possible to do automatically and you can set the COLORTERM environment variable expicitly to force Isocline to use a specific palette:

  • COLORTERM=truecolor: use 24-bit colors.
  • COLORTERM=256color: use the ANSI 256 color palette.
  • COLORTERM=16color : use the regular ANSI 16 color palette (8 normal and 8 bright colors).
  • COLORTERM=8color: use bold for bright colors.
  • COLORTERM=monochrome: use no color.

The above screenshots are made with the test_colors.c program. You can test your own terminal as:

$ gcc -o test_colors -Iinclude test/test_colors.c src/isocline.c
$ ./test_colors
$ COLORTERM=truecolor ./test_colors
$ COLORTERM=16color ./test_colors

ANSI Escape Sequences

Isocline uses just few ANSI escape sequences that are widely supported:

  • ESC[nA, ESC[nB, ESC[nC, and ESC[nD, for moving the cursor n places up, down, right, and left.
  • ESC[K to clear the line from the cursor.
  • ESC[nm for colors, with n one of: 0 (reset), 1,22 (bold), 3,23 (italic), 4,24 (underline), 7,27 (reverse), 30-37,40-47,90-97,100-107 (color), and 39,49 (select default color).
  • ESC[38;5;nm, ESC[48;5;nm, ESC[38;2;r;g;bm, ESC[48;2;r;g;bm: on terminals that support it, select entry n from the 256 color ANSI palette (used with XTERM=xterm-256color for example), or directly specify any 24-bit rgb color (used with COLORTERM=truecolor) for the foreground or background.

On Windows the above functionality is implemented using the Windows console API (except if running in the new Windows Terminal which supports these escape sequences natively).

Async and Threads

Isocline is not thread-safe and ic_readlinexxx and ic_printxxx should be used from one thread only.

The best way to use ic_readline asynchronously is to run it in a (blocking) dedicated thread and deliver results from there to the async event loop. Isocline has the

bool ic_async_stop(void)

function that is thread-safe and can deliver an asynchronous event to Isocline that unblocks a current ic_readline and makes it behave as if the user pressed ctrl-c (which returns NULL from the read line call).

Color Mapping

To map full RGB colors to an ANSI 256 or 16-color palette Isocline finds a palette color with the minimal "color distance" to the original color. There are various ways of calculating this: one way is to take the euclidean distance in the sRGB space (simple-rgb), a slightly better way is to take a weighted distance where the weight distribution is adjusted according to how big the red component is (redmean, denoted as delta-rgb in the figure), this is used by Isocline), and finally, we can first translate into a perceptually uniform color space (CIElab) and calculate the distance there using the CIEDE2000 algorithm (ciede2000). Here are these three methods compared on some colors:

color space comparison

Each top row is the true 24-bit RGB color. Surprisingly, the sophisticated CIEDE2000 distance seems less good here compared to the simpler methods (as in the upper left block for example) (perhaps because this algorithm was created to find close perceptual colors in images where lightness differences may be given less weight?). CIEDE2000 also leads to more "outliers", for example as seen in column 5. Given these results, Isocline uses redmean for color mapping. We also add a gray correction that makes it less likely to substitute a color for a gray value (and the other way around).

Possible Future Extensions

  • Vi key bindings.
  • kill buffer.
  • make the ic_printxxx functions thread-safe.
  • extended low-level terminal functions.
  • status and progress bars.
  • prompt variants: confirm, etc.
  • ...

Contact me if you are interested in doing any of these :-)

Releases

  • 2021-08-23: v1.0.2: fix windows eol wrapping
  • 2021-08-21: v1.0.1: fix line-buffering
  • 2021-08-20: v1.0.0: initial release
Comments
  • How to turn off all funky stuff... no brace matching, no auto-completion, just want basic mode

    How to turn off all funky stuff... no brace matching, no auto-completion, just want basic mode

    Title says it all. I can't find anything.

    Also, on a light themed terminal the default grays are just unreadable. I can't find any documentation on how to chnage that.

    opened by infradig 4
  • testsuite hanging on Linux

    testsuite hanging on Linux

    I tried to build 1.0.5 and run the testsuite on Fedora Linux 35 x86_64 (ghc-8.10.5 and LTS 18), but it seems to hang for me. Then after interrupting it, test-example grabs a cpu... any ideas? Is there any more information I can provide? (Same thing happened with 1.0.4.)

    opened by juhp 3
  • Segfault on Stackage build server when running test suite

    Segfault on Stackage build server when running test suite

    On the Stackage build server:

    Test suite failure for package isocline-1.0.1
        test-example:  exited with: ExitFailure (-11)
    Full log available at /var/stackage/work/unpack-dir/.stack-work/logs/isocline-1.0.1-test.log
    

    The log file itself is empty. I tested on my local Linux machine, and everything passed correctly, so I'm not sure what the issue is.

    I'm going to disable the isocline test suite for Stackage for now.

    opened by snoyberg 3
  • Haskell: 100 % cpu usage using: putFmtLn ““

    Haskell: 100 % cpu usage using: putFmtLn ““

    Hi.

    Using the Haskell command

    putFmtLn ““

    (Parameter is an empty String) my cpu usage goes up to 100 % and I have to kill the programm using another terminal. My intention was to write an empty line to the terminal.

    Tested with: ghc 8.8.4 (debian, PPC64 cpu) ghc 8.4.4 (debian, x86-64 cpu)

    Thank you for reading this.

    Edit: Corrected ghc versions.

    opened by rpxrpxrpx 2
  • Fix MSVC warnings on level 4

    Fix MSVC warnings on level 4

    This change fixes the warning in isatty():

    term.c(335,31): warning C4996: 'isatty': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _isatty. See online help for details. [D:\a\luau\luau\isocline.vcxproj]

    As well as making sure to define these conditionally to avoid this warning when they are set externally as part of the build process:

    isocline.c(16,1): warning C4005: '_CRT_SECURE_NO_WARNINGS': macro redefinition [D:\a\luau\luau\isocline.vcxproj]

    opened by zeux 1
  • ic_completion_arg is declared but not defined

    ic_completion_arg is declared but not defined

    I recently ran into a linker error trying to call ic_completion_arg, it is declared in isocline.h, but it doesn't appear to be defined anywhere in the library. Is it intended to be defined?

    opened by dave-cope 1
  • Auto complete seems to fail for strings beginning with `:`

    Auto complete seems to fail for strings beginning with `:`

    I'm using the library as a submodule, with a snapshot at commit c9310ae.

    It works great for completing regular words, but I recently added some commands that start with : (e.g., :toggle-tracing), and I noticed that the auto completion doesn't seem to work for those words. For example, after configuring as follows:

    static char* const TOGGLE_TRACING = ":toggle-tracing";
    static char* const EXIT = "exit";
    
    static const char* COMMANDS[] = {TOGGLE_TRACING, EXIT, NULL};
    
    static void
    word_completer(ic_completion_env_t* input_until_cursor, const char* word)
    {
      ic_add_completions(input_until_cursor, word, COMMANDS);
    }
    
    static void
    completer(ic_completion_env_t* input_until_cursor, const char* input)
    {
      ic_complete_word(
          input_until_cursor, input, &word_completer,
          NULL /* from default word boundary; whitespace or separator */
      );
    }
    
    static void setup_line_reader()
    {
      setlocale(LC_ALL, "C.UTF-8");
    
      ic_style_def("kbd", "gray underline");
      ic_style_def("ic-prompt", "ansi-maroon");
      ic_enable_hint(false);
    
      // enable completion with a default completion function
      ic_set_default_completer(&completer, NULL);
      ic_enable_auto_tab(true);
    }
    

    If I type : followed by TAB, I get:

    >>> :
     1 exit
     2 :toggle-tracing
    

    However, if I type: :t followed by TAB, I don't get any completions.

    Is this expected behavior, a bug, or am I doing something wrong?

    Thanks!

    opened by zxul767 0
  • Change completer argument in ic_complete_qword_ex to a pointer

    Change completer argument in ic_complete_qword_ex to a pointer

    This makes the definition match declaration as well as other functions, and avoids this warning:

    isocline\src\completers.c(125): warning C4028: formal parameter 3 different from declaration

    opened by zeux 0
  • Long lines copy / pasted in have Unicode left-arrow

    Long lines copy / pasted in have Unicode left-arrow

    Enter a long line that causes terminal wrap-around and it shows a ←character. This is not a problem as it just seems to be echoed, not actually input. However if you want to copy/paste it in, then it certainly becomes a problem as it messes up input.

    opened by infradig 1
Owner
Daan
Daan
GPU Task Spooler - A SLURM alternative/job scheduler for a single simulation machine

GPU Task Spooler - A SLURM alternative/job scheduler for a single simulation machine

Duc Nguyen 103 Jan 6, 2023
GNU project's implementation of the standard C library(with Xuantie RISC-V CPU support).

GNU project's implementation of the standard C library(with Xuantie RISC-V CPU support).

T-Head Semiconductor Co., Ltd. 5 Mar 17, 2022
A LKM rootkit targeting 4.x and 5.x kernel versions which opens a backdoor that can be used to spawn a reverse shell to a remote host and more.

Umbra Umbra (/ˈʌmbrə/) is an experimental LKM rootkit for kernels 4.x and 5.x (up to 5.7) which opens a network backdoor that spawns reverse shells to

Marcos S. Bajo 93 Dec 10, 2022
Thor is a DoS(slowloris) tool which can be used against a target.

Thor is a DoS(slowloris) tool which can be used against a target. It does this by continuously sending partial HTTP requests, none of which are completed.

AnonabdulJ 1 Nov 6, 2021
A few standalones demodulators replacing GNU Radio flowcharts

Standalone-Demodulators A few standalones demodulators replacing GNU Radio flowcharts. Still WIP! But usable. QPSK Demodulator Simple QPSK demodulator

Altillimity 41 Dec 5, 2022
A pure C implementation of the Geohash algorithm.

libgeohash Derek Smith [email protected] A static library used for encoding/decoding geohashes. To use libgeohash just run make. Link libgeohash.a a

Urban Airship 97 Oct 10, 2022
provide SFML Time utilities in pure C++20, no dependencies

SFML-Time-utilities-without-SFML provide SFML Time utilities in pure C++20, no dependencies Example int main() { Clock clock; Sleep(1000);

null 1 Apr 28, 2022
Panda - is a set of utilities used to research how PsExec encrypts its traffic.

Panda Panda - is a set of utilities used to research how PsExec encrypts its traffic. Shared library used to inject into lsass.exe process to log NTLM

Pavel 11 Jul 17, 2022
parse sql statements as strings to be used/modified in cpp.

parse sql statements as strings to be used/modified in cpp.

null 1 Mar 28, 2022
SIDKick -- the first complete SID 6581/8580-drop-in-replacement that you can build yourself

.- the first complete SID-drop-in-replacement that you can build yourself -. SIDKick is a drop-in replacement for the SID sound chips used in C64s and

null 103 Jan 4, 2023
A interpreter that runs the script which is programmed in the language of FF0 script (or you can call it as Warfarin)

ff0-script A interpreter that runs the script which is programmed in the language of FF0 script (or you can call it as Warfarin) You can do it, unders

null 24 Apr 27, 2022
A docker image where you can run a judge program and a converter for multiple sequence alignment

genocon2021-docker 本リポジトリでは、ジャッジプログラム(eval.c)と Multiple Sequence Alignment (MSA) 変換プログラム(decode_cigar.py)を同梱した Docker イメージを提供しています。 また、サンプル解答プログラム(sam

Sakamoto, Kazunori 4 Sep 20, 2021
A c++ file just to show how can we change color of Background and Text in C++...

A c++ file just to show how can we change color of Background and Text in C++...

null 1 Nov 2, 2021
A linux library to get the file path of the currently running shared library. Emulates use of Win32 GetModuleHandleEx/GetModuleFilename.

whereami A linux library to get the file path of the currently running shared library. Emulates use of Win32 GetModuleHandleEx/GetModuleFilename. usag

Blackle Morisanchetto 3 Sep 24, 2022
Command-line arguments parsing library.

argparse argparse - A command line arguments parsing library in C (compatible with C++). Description This module is inspired by parse-options.c (git)

Yecheng Fu 533 Dec 26, 2022
A cross platform C99 library to get cpu features at runtime.

cpu_features A cross-platform C library to retrieve CPU features (such as available instructions) at runtime. Table of Contents Design Rationale Code

Google 2.2k Dec 22, 2022
Library that solves the exact cover problem using Dancing Links, also known as DLX.

The DLX Library The DLX library The DLX library solves instances of the exact cover problem, using Dancing Links (Knuth’s Algorithm X). Also included

Ben Lynn 44 Dec 18, 2022
Standards compliant, fast, secure markdown processing library in C

Hoedown Hoedown is a revived fork of Sundown, the Markdown parser based on the original code of the Upskirt library by Natacha Porté. Features Fully s

Hoedown 923 Dec 27, 2022
CommonMark parsing and rendering library and program in C

cmark cmark is the C reference implementation of CommonMark, a rationalized version of Markdown syntax with a spec. (For the JavaScript reference impl

CommonMark 1.4k Jan 4, 2023