Showing with 192 additions and 11 deletions.
  1. +32 −0 src/lib/readline/c/chardefs.d
  2. +17 −0 src/lib/readline/c/keymaps.d
  3. +12 −2 src/lib/readline/c/readline.d
  4. +43 −1 src/lib/readline/c/rltypedefs.d
  5. +35 −0 src/lib/readline/readline.d
  6. +4 −2 src/ohm/interactive.d
  7. +49 −6 src/ohm/io.d
@@ -0,0 +1,32 @@
module lib.readline.c.chardefs;


bool whitespace(T)(T c) { return (c == ' ') || (c == '\t'); }


enum control_character_threshold = 0x020; /* Smaller than this is control. */
enum control_character_mask = 0x1f; /* 0x20 - 1 */
enum meta_character_threshold = 0x07f; /* Larger than this is Meta. */
enum control_character_bit = 0x40; /* 0x000000, must be off. */
enum meta_character_bit = 0x080; /* x0000000, must be on. */
enum largest_char = 255; /* Largest character value. */

bool CTRL_CHAR(T)(T c) { return (c < control_character_threshold) && ((c & 0x80) == 0); }
bool META_CHAR(T)(T c) { return (c > meta_character_threshold) && (c <= largest_char); }


T CTRL(T)(T x) { return x & control_character_mask; }
T META(T)(T x) { return x | meta_character_bit; }

T UNMETA(T)(T x) { return x & (~meta_character_bit); }
// doesn't match the C header
T UNCTRL(T)(T x) { return x + 64; }

enum NEWLINE = '\n';
enum RETURN = CTRL('M');
enum RUBOUT = 0x7f;
enum TAB = '\t';
enum ABORT_CHAR = CTRL('G');
enum PAGE = CTRL('L');
enum SPACE = ' '; /* XXX - was 0x20 */
enum ESC = CTRL('[');
@@ -0,0 +1,17 @@
module lib.readline.c.keymap;


public import lib.readline.c.rltypedefs;


extern (C):


struct KEYMAP_ENTRY {
char type;
rl_command_func_t func;
}

alias Keymap = KEYMAP_ENTRY*;

enum KEYMAP_SIZE = 257;
@@ -2,6 +2,7 @@ module lib.readline.c.readline;


public import lib.readline.c.rltypedefs;
public import lib.readline.c.keymaps;

// This is very incomplete at the moment.

@@ -10,14 +11,23 @@ extern (C):

char* readline(const(char)*);


/* Modifying text. */
void rl_replace_line(const(char)*, int);
int rl_insert_text(const(char)*);
int rl_delete_text(int, int);
int rl_kill_text(int, int);
char *rl_copy_text(int, int);

/* Utility functions to bind keys to readline commands. */
int rl_bind_key(int, rl_command_func_t);
int rl_bind_keyseq(const(char)*, rl_command_func_t);
int rl_unbind_key(int);

Keymap rl_get_keymap();

void rl_tty_unset_default_bindings(Keymap);

/* Variables */
extern __gshared rl_hook_func_t rl_startup_hook;
extern __gshared rl_hook_func_t rl_startup_hook;

extern __gshared int rl_done;
@@ -1,6 +1,48 @@
module lib.readline.c.rltypedefs;


public import core.stdc.stdio : FILE;


extern (C):

alias rl_hook_func_t = int function();
/* Bindable functions */
alias rl_command_func_t = int function(int, int);

/* Typedefs for the completion system */
alias rl_compentry_func_t = char * function(const char *, int);
alias rl_completion_func_t = char ** function(const char *, int, int);

alias rl_quote_func_t = char * function(char *, int, char *);
alias rl_dequote_func_t = char * function(char *, int);

alias rl_compignore_func_t = int function(char **);

alias rl_compdisp_func_t = void function(char **, int, int);

/* Type for input and pre-read hook functions like rl_event_hook */
alias rl_hook_func_t = int function();

/* Input function type */
alias rl_getc_func_t = int function(FILE *);

/* Generic function that takes a character buffer (which could be the readline
line buffer) and an index into it (which could be rl_point) and returns
an int. */
alias rl_linebuf_func_t = int function(char *, int);

/* `Generic' function pointer typedefs */
alias rl_intfunc_t = int function(int);
alias rl_ivoidfunc_t = rl_hook_func_t;
alias rl_icpfunc_t = int function(char *);
alias rl_icppfunc_t = int function(char **);

alias rl_voidfunc_t = void function();
alias rl_vintfunc_t = void function(int);
alias rl_vcpfunc_t = void function(char *);
alias rl_vcppfunc_t = void function(char **);

alias rl_cpvfunc_t = char * function();
alias rl_cpifunc_t = char * function(int);
alias rl_cpcpfunc_t = char * function(char *);
alias rl_cpcppfunc_t = char * function(char **);
@@ -7,11 +7,14 @@ private {
import std.conv : to;
}
public import lib.readline.c.readline;
public import lib.readline.c.chardefs;
public import lib.readline.c.keymaps;


alias readline = lib.readline.c.readline.readline;
alias rl_replace_line = lib.readline.c.readline.rl_replace_line;
alias rl_insert_text = lib.readline.c.readline.rl_insert_text;
alias rl_bind_key = lib.readline.c.readline.rl_bind_key;


string readline(const(char)[] prompt)
@@ -34,4 +37,36 @@ void rl_replace_line(const(char)[] text, int clear_undo)
int rl_insert_text(const(char)[] text)
{
return rl_insert_text(toStringz(text));
}


private __gshared void delegate(int, int)[KEYMAP_SIZE] _rl_bind_key_dgs;
extern(C) int _rl_bind_key_cb(int x, int key)
{
// you can only bind to keys which are in range
auto dg = _rl_bind_key_dgs[key];
if (dg !is null) {
dg(x, key);
}
return 0;
}


int rl_bind_key(int key, void delegate(int, int) dg)
{
auto r = lib.readline.c.readline.rl_bind_key(key, &_rl_bind_key_cb);
if (r == 0) {
// rl_bind_key alread checks if the key is in range
_rl_bind_key_dgs[key] = dg;
}
return r;
}

int rl_unbind_key(int key)
{
auto r = rl_unbind_key(key);
if (r == 0) {
_rl_bind_key_dgs[key] = null;
}
return r;
}
@@ -39,7 +39,7 @@ public:

void run()
{
for (;; location.line++) {
for (;;) {
try {
repl();
} catch (ContinueException e) {
@@ -51,6 +51,8 @@ public:
settings.showStackTraces ? e.toString() : e.msg
);
}

location.line++;
}
}

@@ -86,6 +88,6 @@ protected:

@property string outputPrompt()
{
return format("Out [%d]: ", location.line + 1);
return format("Out[%d]: ", location.line + 1);
}
}
@@ -2,14 +2,15 @@ module ohm.io;


import std.stdio : writeln, stdout;
import std.string : format, strip;
import std.string : format, strip, toStringz;
import std.array : replicate;

import lib.readline.readline;
import lib.readline.history;

import ohm.interfaces : Reader, Writer;
import ohm.settings : Settings;
import ohm.exceptions : ExitException;
import ohm.exceptions : ExitException, ContinueException;
import ohm.util : balancedParens;


@@ -18,8 +19,13 @@ enum Parens {
Close = [')', ']', '}'],
}

extern(C) int _indentSpaces() {
rl_insert_text(" \0".ptr);
private size_t indentNum = 0;
private string indentStr = " ";
private extern(C) int indentSpaces()
{
if (indentNum > 0) {
rl_insert_text(toStringz(replicate(indentStr, indentNum)));
}
return 0;
}

@@ -29,12 +35,25 @@ class StdinReadlineReader : Reader
public:
Settings settings;

protected:
bool ctrlcPressed;

public:
this(Settings settings)
{
this.settings = settings;

read_history(settings.historyFile);

rl_tty_unset_default_bindings(rl_get_keymap());
rl_bind_key(CTRL('c'), &this.ctrlc);
rl_startup_hook = &indentSpaces;
}

~this()
{
rl_unbind_key(CTRL('c'));
rl_startup_hook = null;
}

string getInput(string prompt)
@@ -46,12 +65,13 @@ public:
input = getLine(prompt);
} while (strip(input).length == 0);

setIndent(4);
scope(exit) resetIndent();

prompt = format(format("%%%ds", prompt.length), "...: ");
rl_startup_hook = &_indentSpaces;
while (!balancedParens(input, Parens.Open, Parens.Close)) {
input = input ~ "\n" ~ getLine(prompt);
}
rl_startup_hook = null;

saveInput(input);

@@ -68,9 +88,32 @@ protected:
string getLine(string prompt)
{
auto line = readline(prompt);
if (ctrlcPressed) {
ctrlcPressed = false;
throw new ContinueException();
}
if (line is null) throw new ExitException();
return line;
}

void ctrlc(int a, int key)
{
writeln("\nControl-C");
rl_done = 1;
ctrlcPressed = true;
}

void setIndent(size_t num, string what = " ")
{
indentNum = num;
indentStr = what;
}

void resetIndent()
{
indentNum = 0;
indentStr = " ";
}
}