bundled isocline
This commit is contained in:
97
bin/isocline/test/Example.hs
Normal file
97
bin/isocline/test/Example.hs
Normal file
@ -0,0 +1,97 @@
|
||||
{- ----------------------------------------------------------------------------
|
||||
Copyright (c) 2021, Daan Leijen
|
||||
This is free software; you can redistribute it and/or modify it
|
||||
under the terms of the MIT License. A copy of the license can be
|
||||
found in the "LICENSE" file at the root of this distribution.
|
||||
---------------------------------------------------------------------------- -}
|
||||
|
||||
import System.Console.Isocline
|
||||
import Data.List (isPrefixOf)
|
||||
import Data.Char
|
||||
import Control.Monad( when )
|
||||
|
||||
main :: IO ()
|
||||
main
|
||||
= do styleDef "kbd" "gray underline" -- define a style
|
||||
styleDef "ic-prompt" "#00A060" -- or redefine a system style
|
||||
putFmtLn welcome
|
||||
setHistory "history.txt" 200 -- history
|
||||
enableAutoTab True -- complete as far as possible
|
||||
interaction
|
||||
where
|
||||
welcome = "\n[b]Isocline[/b] sample program:\n" ++
|
||||
"- Type 'exit' to quit. (or use [kbd]ctrl-d[/]).\n" ++
|
||||
"- Press [kbd]F1[/] for help on editing commands.\n" ++
|
||||
"- Use [kbd]shift-tab[/] for multiline input. (or [kbd]ctrl-enter[/], or [kbd]ctrl-j[/])\n" ++
|
||||
"- Type 'p' (or 'id', 'f', or 'h') followed by tab for completion.\n" ++
|
||||
"- Type 'fun' or 'int' to see syntax highlighting\n" ++
|
||||
"- Use [kbd]ctrl-r[/] to search the history.\n"
|
||||
|
||||
interaction :: IO ()
|
||||
interaction
|
||||
= do s <- readlineEx "hαskell" (Just completer) (Just highlighter)
|
||||
putStrLn $ unlines ["--------",s,"--------"]
|
||||
if (s == "" || s == "exit")
|
||||
then return ()
|
||||
else interaction
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Tab Completion
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
completer :: CompletionEnv -> String -> IO ()
|
||||
completer compl input
|
||||
= do completeFileName compl input Nothing [".","/usr/local"] [] {-any extension-}
|
||||
completeWord compl input Nothing wordCompletions
|
||||
|
||||
wordCompletions :: String -> [Completion]
|
||||
wordCompletions input0
|
||||
= let input = map toLower input0
|
||||
in -- simple completion based on available words
|
||||
(completionsFor input ["print","printer","println","printsln","prompt"])
|
||||
++
|
||||
-- with display versus replacement
|
||||
(if (input == "id")
|
||||
then map (\(d,r) -> Completion r d "") $ -- Completion replacement display help
|
||||
[ ("D — (x) => x", "(x) => x")
|
||||
, ("Haskell — \\x -> x", "\\x -> x")
|
||||
, ("Idris — \\x => x", "\\x => x")
|
||||
, ("Ocaml — fun x -> x", "fun x -> x")
|
||||
, ("Koka — fn(x) x", "fn(x) x")
|
||||
, ("Rust — |x| x", "|x| x") ]
|
||||
else [])
|
||||
++
|
||||
-- add many hello isocline completions; we should generate these lazily!
|
||||
(if (not (null input) && input `isPrefixOf` "hello_isocline_")
|
||||
then map (\i -> completion ("hello_isocline_" ++ show i)) [1..100000]
|
||||
else [])
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Syntax highlighting
|
||||
-- uses a simple tokenizer but a full fledged one probably needs
|
||||
-- Parsec or regex's for syntax highlighting
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
highlighter :: String -> Fmt
|
||||
highlighter input
|
||||
= tokenize input
|
||||
where
|
||||
tokenize [] = []
|
||||
tokenize s@('/':'/':_) -- comment
|
||||
= let (t,ds) = span (/='\n') s in style "#408700" (plain t) ++ tokenize ds
|
||||
tokenize s@(c:cs)
|
||||
| isAlpha c = let (t,ds) = span isAlpha s
|
||||
in (if (t `elem` ["fun","struct","var","val"])
|
||||
then style "keyword" t -- builtin style
|
||||
else if (t `elem` ["return","if","then","else"])
|
||||
then style "control" t -- builtin style
|
||||
else if (t `elem` ["int","double","char","void"])
|
||||
then style "#00AFAF" t -- or use specific colors
|
||||
else plain t) -- never lose input, all original characters must be present!
|
||||
++ tokenize ds
|
||||
| isDigit c = let (t,ds) = span isDigit s
|
||||
in style "number" t ++ tokenize ds
|
||||
| otherwise = plain [c] ++ tokenize cs -- never lose input
|
||||
|
169
bin/isocline/test/example.c
Normal file
169
bin/isocline/test/example.c
Normal file
@ -0,0 +1,169 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
Copyright (c) 2021, Daan Leijen
|
||||
This is free software; you can redistribute it and/or modify it
|
||||
under the terms of the MIT License. A copy of the license can be
|
||||
found in the "LICENSE" file at the root of this distribution.
|
||||
|
||||
Example use of the Isocline API.
|
||||
-----------------------------------------------------------------------------*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
#include "isocline.h"
|
||||
|
||||
// completion function defined below
|
||||
static void completer(ic_completion_env_t* cenv, const char* prefix );
|
||||
|
||||
// highlighter function defined below
|
||||
static void highlighter(ic_highlight_env_t* henv, const char* input, void* arg);
|
||||
|
||||
// main example
|
||||
int main()
|
||||
{
|
||||
setlocale(LC_ALL,"C.UTF-8"); // we use utf-8 in this example
|
||||
|
||||
// use `ic_print` functions to use bbcode's for markup
|
||||
ic_style_def("kbd","gray underline"); // you can define your own styles
|
||||
ic_style_def("ic-prompt","ansi-maroon"); // or re-define system styles
|
||||
|
||||
ic_printf( "[b]Isocline[/b] sample program:\n"
|
||||
"- Type 'exit' to quit. (or use [kbd]ctrl-d[/]).\n"
|
||||
"- Press [kbd]F1[/] for help on editing commands.\n"
|
||||
"- Use [kbd]shift-tab[/] for multiline input. (or [kbd]ctrl-enter[/], or [kbd]ctrl-j[/])\n"
|
||||
"- Type 'p' (or 'id', 'f', or 'h') followed by tab for completion.\n"
|
||||
"- Type 'fun' or 'int' to see syntax highlighting\n"
|
||||
"- Use [kbd]ctrl-r[/] to search the history.\n\n" );
|
||||
|
||||
// enable history; use a NULL filename to not persist history to disk
|
||||
ic_set_history("history.txt", -1 /* default entries (= 200) */);
|
||||
|
||||
// enable completion with a default completion function
|
||||
ic_set_default_completer(&completer, NULL);
|
||||
|
||||
// enable syntax highlighting with a highlight function
|
||||
ic_set_default_highlighter(highlighter, NULL);
|
||||
|
||||
// try to auto complete after a completion as long as the completion is unique
|
||||
ic_enable_auto_tab(true );
|
||||
|
||||
// inline hinting is enabled by default
|
||||
// ic_enable_hint(false);
|
||||
|
||||
// run until empty input
|
||||
char* input;
|
||||
while((input = ic_readline("isoclinε")) != NULL) // ctrl-d returns NULL (as well as errors)
|
||||
{
|
||||
bool stop = (strcmp(input,"exit") == 0 || strcmp(input,"") == 0);
|
||||
ic_printf("[gray]-----[/]\n" // echo the input
|
||||
"%s\n"
|
||||
"[gray]-----[/]\n", input );
|
||||
free(input); // do not forget to free the returned input!
|
||||
if (stop) break;
|
||||
}
|
||||
ic_println("done");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Completion
|
||||
// -------------------------------------------------------------------------------
|
||||
|
||||
// A custom completer function.
|
||||
// Use `ic_add_completion( env, replacement, display, help)` to add actual completions.
|
||||
static void word_completer(ic_completion_env_t* cenv, const char* word )
|
||||
{
|
||||
// complete with list of words; only if the input is a word it will be a completion candidate
|
||||
static const char* completions[] = { "print", "println", "printer", "printsln", "prompt", NULL };
|
||||
ic_add_completions(cenv, word, completions);
|
||||
|
||||
// examples of more customized completions
|
||||
if (strcmp(word,"f") == 0) {
|
||||
// test unicode, and replace "f" with something else completely (useful for templating)
|
||||
ic_add_completion(cenv, "banana 🍌 etc.");
|
||||
ic_add_completion(cenv, "〈pear〉with brackets");
|
||||
ic_add_completion(cenv, "猕猴桃 wide");
|
||||
ic_add_completion(cenv, "apples 🍎");
|
||||
ic_add_completion(cenv, "zero\xE2\x80\x8Dwidth-joiner");
|
||||
}
|
||||
else if (strcmp(word, "id") == 0) {
|
||||
// replacement, display, and help
|
||||
ic_add_completion_ex(cenv, "(x) => x", "D — (x) => x", "identity function in D");
|
||||
ic_add_completion_ex(cenv, "\\x -> x", "Haskell — \\x -> x", "identity_bot function in Haskell");
|
||||
ic_add_completion_ex(cenv, "\\x => x", "Idris — \\x => x", "dependent identity function in Idris");
|
||||
ic_add_completion_ex(cenv, "fn(x){ x }", "Koka — fn(x){ x }", "total identity function in Koka");
|
||||
ic_add_completion_ex(cenv, "fun x -> x", "Ocaml — fun x -> x", "identity lambda in OCaml");
|
||||
}
|
||||
else if (word[0] != 0 && ic_istarts_with("hello isocline ",word)) {
|
||||
// many completions for hello isocline
|
||||
for(int i = 0; i < 100000; i++) {
|
||||
char buf[32];
|
||||
snprintf(buf,32,"hello isocline %03d", i+1);
|
||||
if (!ic_add_completion(cenv, buf)) break; // break early if not all completions are needed (for better latency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A completer function is called by isocline to complete. The input parameter is the input up to the cursor.
|
||||
// We use `ic_complete_word` to only consider the final token on the input.
|
||||
// (almost all user defined completers should use this)
|
||||
static void completer(ic_completion_env_t* cenv, const char* input )
|
||||
{
|
||||
// try to complete file names from the roots "." and "/usr/local"
|
||||
ic_complete_filename(cenv, input, 0, ".;/usr/local;c:\\Program Files" , NULL /* any extension */);
|
||||
|
||||
// and also use our custom completer
|
||||
ic_complete_word( cenv, input, &word_completer, NULL /* from default word boundary; whitespace or separator */ );
|
||||
|
||||
// ic_complete_word( cenv, input, &word_completer, &ic_char_is_idletter );
|
||||
// ic_complete_qword( cenv, input, &word_completer, &ic_char_is_idletter );
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Syntax highlighting
|
||||
// -------------------------------------------------------------------------------
|
||||
|
||||
// A highlight function is called by isocline when input can be highlighted.
|
||||
// Use `ic_highlight_color` (or `bgcolor`, `underline`) to highlight characters from
|
||||
// a given position until another attribute is set.
|
||||
// Here we use some convenience functions to easily highlight
|
||||
// simple tokens but a full-fledged highlighter probably needs regular expressions.
|
||||
static void highlighter(ic_highlight_env_t* henv, const char* input, void* arg) {
|
||||
(void)(arg); // unused
|
||||
// for all characters in the input..
|
||||
long len = (long)strlen(input);
|
||||
for (long i = 0; i < len; ) {
|
||||
static const char* keywords[] = { "fun", "static", "const", "struct", NULL };
|
||||
static const char* controls[] = { "return", "if", "then", "else", NULL };
|
||||
static const char* types[] = { "int", "double", "char", "void", NULL };
|
||||
long tlen; // token length
|
||||
if ((tlen = ic_match_any_token(input, i, &ic_char_is_idletter, keywords)) > 0) {
|
||||
ic_highlight(henv, i, tlen, "keyword");
|
||||
i += tlen;
|
||||
}
|
||||
else if ((tlen = ic_match_any_token(input, i, &ic_char_is_idletter, controls)) > 0) {
|
||||
ic_highlight(henv, i, tlen, "plum"); // html color (or use the `control` style)
|
||||
i += tlen;
|
||||
}
|
||||
else if ((tlen = ic_match_any_token(input, i, &ic_char_is_idletter, types)) > 0) {
|
||||
ic_highlight(henv, i, tlen, "type");
|
||||
i += tlen;
|
||||
}
|
||||
else if ((tlen = ic_is_token(input, i, &ic_char_is_digit)) > 0) { // digits
|
||||
ic_highlight(henv, i, tlen, "number");
|
||||
i += tlen;
|
||||
}
|
||||
else if (ic_starts_with(input + i,"//")) { // line comment
|
||||
tlen = 2;
|
||||
while (i+tlen < len && input[i+tlen] != '\n') { tlen++; }
|
||||
ic_highlight(henv, i, tlen, "comment"); // or use a spefic color like "#408700"
|
||||
i += tlen;
|
||||
}
|
||||
else {
|
||||
ic_highlight(henv, i, 1, NULL); // anything else (including utf8 continuation bytes)
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
137
bin/isocline/test/test_colors.c
Normal file
137
bin/isocline/test/test_colors.c
Normal file
@ -0,0 +1,137 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
Copyright (c) 2021, Daan Leijen
|
||||
This is free software; you can redistribute it and/or modify it
|
||||
under the terms of the MIT License. A copy of the license can be
|
||||
found in the "LICENSE" file at the root of this distribution.
|
||||
|
||||
Example that shows the color palette of the terminal
|
||||
-----------------------------------------------------------------------------*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <isocline.h>
|
||||
|
||||
static const char* patch = "■";
|
||||
|
||||
typedef enum color_order_e {
|
||||
RGB,
|
||||
BGR,
|
||||
GRB
|
||||
} color_order_t;
|
||||
|
||||
#include "../src/bbcode_colors.c"
|
||||
|
||||
static int color_weight(ic_color_t c) {
|
||||
return (int)(c);
|
||||
}
|
||||
static int html_color_compare(const void* p1, const void* p2) {
|
||||
const style_color_t* s1 = (const style_color_t*)p1;
|
||||
const style_color_t* s2 = (const style_color_t*)p2;
|
||||
int w1 = color_weight(s1->color);
|
||||
int w2 = color_weight(s2->color);
|
||||
return (w1 - w2);
|
||||
}
|
||||
|
||||
static void write_html_colors(void) {
|
||||
qsort(html_colors, IC_HTML_COLOR_COUNT, sizeof(html_colors[0]), &html_color_compare );
|
||||
ic_print("print html colors\n");
|
||||
for(int i = 0; i < IC_HTML_COLOR_COUNT-1; i++) {
|
||||
ic_printf("[width=10][bgcolor=%s]%s[/][/] ", html_colors[i].name, html_colors[i].name);
|
||||
if ((i+1)%8 == 0) ic_print("\n\n");
|
||||
}
|
||||
ic_println("");
|
||||
}
|
||||
|
||||
static void write_palette( int order) {
|
||||
ic_print("\n // ");
|
||||
ic_print(order == RGB ? "17x9x9" : (order == BGR ? "9x9x17" : "9x17x9"));
|
||||
ic_print("colors");
|
||||
for (int x = 0; x <= 256; x += 16) {
|
||||
ic_print("\n ");
|
||||
for (int y = 0; y <= 256; y += 32) {
|
||||
for (int z = 0; z <= 256; z += 32) {
|
||||
int r, g, b;
|
||||
if (order == RGB) {
|
||||
r = x; g = y; b = z;
|
||||
}
|
||||
if (order == BGR) {
|
||||
r = z; g = y; b = x;
|
||||
}
|
||||
else if (order == GRB) {
|
||||
r = y; g = x; b = z;
|
||||
}
|
||||
if (r == 256) r = 255;
|
||||
if (g == 256) g = 255;
|
||||
if (b == 256) b = 255;
|
||||
ic_printf("[#%02x%02x%02x]%s[/]", r, g, b, patch);
|
||||
}
|
||||
ic_print(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void show_ansi_color(const char* name, const char* brightname ) {
|
||||
ic_printf("[ansi-%s]%16s[/] | [ansi-%s bold]bold[/] | [ansi-%s]%s[/]\n", name, name, name, brightname, brightname );
|
||||
}
|
||||
|
||||
// main example
|
||||
int main()
|
||||
{
|
||||
// how many bits has our palette? (24 bits is good :-)
|
||||
ic_printf("terminal color bits: %d\n", ic_term_get_color_bits());
|
||||
|
||||
// Write out a palette
|
||||
ic_println("colors rgb:");
|
||||
write_palette(RGB);
|
||||
write_palette(BGR);
|
||||
write_palette(GRB);
|
||||
|
||||
ic_println("\n\nansi reds:\n [ansi-maroon]ansi8-red[/], [ansi-red]ansi16-bright-red[/], [#D70000]ansi256-red160[/], [#fa1754]ansirgb-cherry[/]");
|
||||
|
||||
// Shades
|
||||
ic_println("\nshades:");
|
||||
for (int i = 0; i <= 64; i++) {
|
||||
ic_printf("[#%02x0000]%s[/]", (i==64 ? 255 : i*4), patch);
|
||||
}
|
||||
ic_println("");
|
||||
for (int i = 0; i <= 64; i++) {
|
||||
ic_printf("[#00%02x00]%s[/]", (i==64 ? 255 : i*4), patch);
|
||||
}
|
||||
ic_println("");
|
||||
for (int i = 0; i <= 64; i++) {
|
||||
ic_printf("[#0000%02x]%s[/]", (i==64 ? 255 : i*4), patch);
|
||||
}
|
||||
ic_println("");
|
||||
for (int i = 0; i <= 64; i++) {
|
||||
int g = (i==64 ? 255 : i*4);
|
||||
ic_printf("[#%02x%02x%02x]%s[/]", g, g, g, patch);
|
||||
}
|
||||
ic_println("\n");
|
||||
|
||||
// html colors
|
||||
write_html_colors();
|
||||
|
||||
// bbcodes
|
||||
ic_println( "\n[b]bold [i]bold and italic[/i] [yellow on blue]yellow on blue in bold[/][/b] default");
|
||||
|
||||
ic_style_def("em", "underline ansi-olive");
|
||||
ic_style_open("i");
|
||||
ic_print( "[em]emphasis[/em]\n" );
|
||||
ic_style_close();
|
||||
|
||||
// direct ANSI escapes
|
||||
ic_println("\ndirect ansi escape sequence colors:\n");
|
||||
show_ansi_color("black","gray");
|
||||
show_ansi_color("maroon","red");
|
||||
show_ansi_color("green","lime");
|
||||
show_ansi_color("olive","yellow");
|
||||
show_ansi_color("navy","blue");
|
||||
show_ansi_color("purple","fuchsia");
|
||||
show_ansi_color("teal","aqua");
|
||||
show_ansi_color("silver","white");
|
||||
show_ansi_color("default","default");
|
||||
|
||||
ic_println("");
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user