bundled isocline
This commit is contained in:
473
bin/isocline/readme.md
Normal file
473
bin/isocline/readme.md
Normal file
@ -0,0 +1,473 @@
|
||||
<!-- <img align="right" width="350px" src="doc/completion-macos.png"/> -->
|
||||
|
||||
<img align="left" src="doc/isocline-inline.svg"/>
|
||||
|
||||
# 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.9, 2022-01-15).
|
||||
|
||||
- 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`][hdoc].
|
||||
|
||||
Enjoy,
|
||||
Daan
|
||||
|
||||
<!-- <img align="right" width="350px" src="doc/history-win.png"/> -->
|
||||
|
||||
# Demo
|
||||
|
||||

|
||||
|
||||
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.
|
||||
<sub>(screen capture was made with [termtosvg] by Nicolas Bedos)</sub>
|
||||
|
||||
# Usage
|
||||
|
||||
Include the isocline header in your C or C++ source:
|
||||
```C
|
||||
#include <include/isocline.h>
|
||||
```
|
||||
|
||||
and call `ic_readline` to get user input with rich editing abilities:
|
||||
```C
|
||||
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][HaskellExample]:
|
||||
```
|
||||
$ 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:
|
||||
```apl
|
||||
home/ctrl-a cursor end/ctrl-e
|
||||
┌─────────────────┼───────────────┐ (navigate)
|
||||
│ ctrl-left │ ctrl-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 : undo
|
||||
│ alt-backsp alt-d │
|
||||
└─────────────────────────────────┘ (delete)
|
||||
ctrl-u ctrl-k
|
||||
```
|
||||
|
||||
<sub>Note: on macOS, the meta (alt) key is not directly available in most terminals.
|
||||
Terminal/iTerm2 users can activate the meta key through
|
||||
`Terminal` → `Preferences` → `Settings` → `Use option as meta key`.</sub>
|
||||
|
||||
### 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][Haskell] for instructions to build and use the Haskell library.
|
||||
|
||||
|
||||
# API Reference
|
||||
|
||||
* See the [C API reference][docapi] and the [example] for example usage of history, completion, etc.
|
||||
|
||||
* See the [Haskell API reference][hdoc] on Hackage and the Haskell [example][HaskellExample].
|
||||
|
||||
|
||||
# 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](https://github.com/troglobit/editline),
|
||||
[linenoise](https://github.com/antirez/linenoise),
|
||||
[replxx](https://github.com/AmokHuginnsson/replxx), and
|
||||
[Haskeline](https://github.com/judah/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][RichBBcode] library,
|
||||
this supports a form of [bbcode]'s to format the output:
|
||||
```c
|
||||
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:
|
||||
```c
|
||||
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):
|
||||
```c
|
||||
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_`]`.
|
||||
```c
|
||||
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:
|
||||
```c
|
||||
ic_style_def("warning", "crimson u");
|
||||
```
|
||||
|
||||
and use them like any builtin style or property:
|
||||
```c
|
||||
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.
|
||||
```c
|
||||
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][htmlcolors].
|
||||
- any of the 16 standard ANSI [color names][ansicolors] 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_ or `ansi-bgcolor=`_idx_, where _idx_ specifies an entry in the
|
||||
standard ANSI 256 [color palette][ansicolor256] (between 0 and 255).
|
||||
Use _idx_ 256 for the ANSI default color.
|
||||
|
||||
The `width` property makes the text at least _width_ long:
|
||||
|
||||
- `width=`_width_ [`;`_align_ [`;`_fill_] ]
|
||||
|
||||
where _width_ is the column with, _align_ is `left`, `center`, or `right`,
|
||||
and _fill_ the fill character (`' '`).
|
||||
|
||||
The _maxwidth_ property makes text at most _width_ long; when the content
|
||||
it is wider, the left- or right side (depending on the alignment)
|
||||
will have three dots (`...`) to visualize that content is cut off.
|
||||
|
||||
- `maxwidth=`_width_ [`;`_align_]
|
||||
|
||||
|
||||
## 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.
|
||||
<img width="500px" src="doc/color/ansi-truecolor.png"/>
|
||||
- `COLORTERM=256color`: use the ANSI 256 color palette.
|
||||
<img width="500px" src="doc/color/ansi-256color.png"/>
|
||||
- `COLORTERM=16color` : use the regular ANSI 16 color
|
||||
palette (8 normal and 8 bright colors).
|
||||
<img width="500px" src="doc/color/ansi-16color.png"/>
|
||||
- `COLORTERM=8color`: use bold for bright colors.
|
||||
- `COLORTERM=monochrome`: use no color.
|
||||
|
||||
The above screenshots are made with the
|
||||
[`test_colors.c`](https://github.com/daanx/isocline/blob/main/test/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[`_n_`A`, `ESC[`_n_`B`, `ESC[`_n_`C`, and `ESC[`_n_`D`,
|
||||
for moving the cursor _n_ places up, down, right, and left.
|
||||
- `ESC[K` to clear the line from the cursor.
|
||||
- `ESC[`_n_`m` 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;`_n_`m`, `ESC[48;5;`_n_`m`, `ESC[38;2;`_r_`;`_g_`;`_b_`m`, `ESC[48;2;`_r_`;`_g_`;`_b_`m`:
|
||||
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_readline`_xxx_ and `ic_print`_xxx_ 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
|
||||
```C
|
||||
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](https://en.wikipedia.org/wiki/Color_difference),
|
||||
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](https://en.wikipedia.org/wiki/Color_difference)
|
||||
algorithm (_ciede2000_). Here are these three methods compared on
|
||||
some colors:
|
||||
|
||||

|
||||
|
||||
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_print`_xxx_ 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
|
||||
|
||||
* `2022-01-15`: v1.0.9: fix missing `ic_completion_arg` (issue #6),
|
||||
fix null ptr check in ic_print (issue #7), fix crash when using /dev/null as both input and output.
|
||||
* `2021-09-05`: v1.0.5: use our own wcwidth for consistency;
|
||||
thanks to Hans-Georg Breunig for helping with testing on NetBSD.
|
||||
* `2021-08-28`: v1.0.4: fix color query on Ubuntu/Gnome
|
||||
* `2021-08-27`: v1.0.3: fix duplicates in completions
|
||||
* `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
|
||||
|
||||
|
||||
|
||||
[GNU readline]: https://tiswww.case.edu/php/chet/readline/rltop.html
|
||||
[koka]: http://www.koka-lang.org
|
||||
[submodule]: https://git-scm.com/book/en/v2/Git-Tools-Submodules
|
||||
[Haskell]: https://github.com/daanx/isocline/tree/main/haskell
|
||||
[HaskellExample]: https://github.com/daanx/isocline/blob/main/test/Example.hs
|
||||
[example]: https://github.com/daanx/isocline/blob/main/test/example.c
|
||||
[termtosvg]: https://github.com/nbedos/termtosvg
|
||||
[Rich]: https://github.com/willmcgugan/rich
|
||||
[RichBBcode]: https://rich.readthedocs.io/en/latest/markup.html
|
||||
[bbcode]: https://en.wikipedia.org/wiki/BBCode
|
||||
[htmlcolors]: https://en.wikipedia.org/wiki/Web_colors#HTML_color_names
|
||||
[ansicolors]: https://en.wikipedia.org/wiki/Web_colors#Basic_colors
|
||||
[ansicolor256]: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
|
||||
[docapi]: https://daanx.github.io/isocline
|
||||
[hdoc]: https://hackage.haskell.org/package/isocline/docs/System-Console-Isocline.html
|
Reference in New Issue
Block a user