add support for several line editing approaches (pure stdin, linenoise, libedit, readline)
parent
3ca2a397dd
commit
9672a1091e
|
@ -1,5 +1,5 @@
|
||||||
libcubescript is provided under the zlib license. Originally by Lee "eihrul"
|
libcubescript is provided under the zlib license. Originally by Lee "eihrul"
|
||||||
Salzman and Wouter van Oortmerssen, it was modified by Daniel "q66" Kolesa.
|
Salzman and Wouter van Oortmerssen, it was mostly rewritten by Daniel "q66" Kolesa.
|
||||||
|
|
||||||
The Cube 2 license:
|
The Cube 2 license:
|
||||||
|
|
||||||
|
@ -21,3 +21,7 @@ freely, subject to the following restrictions:
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
misrepresented as being the original software.
|
misrepresented as being the original software.
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
Libcubescript bundles the linenoise line editing library for REPL usage.
|
||||||
|
This library is available under the BSD 3-clause license, which is available
|
||||||
|
within its source code.
|
8
Makefile
8
Makefile
|
@ -1,7 +1,7 @@
|
||||||
OSTD_PATH = ../octastd
|
OSTD_PATH = ../octastd
|
||||||
|
|
||||||
LIBCS_CXXFLAGS = \
|
LIBCS_CXXFLAGS = \
|
||||||
-std=c++14 -Wall -Wextra -Wshadow -Wold-style-cast -I. \
|
-std=c++14 -Wall -Wextra -Wshadow -Wold-style-cast -I. -g \
|
||||||
-fvisibility=hidden -I$(OSTD_PATH)
|
-fvisibility=hidden -I$(OSTD_PATH)
|
||||||
|
|
||||||
LIBCS_LDFLAGS = -shared
|
LIBCS_LDFLAGS = -shared
|
||||||
|
@ -27,8 +27,10 @@ library: $(LIBCS_LIB)
|
||||||
$(LIBCS_LIB): $(LIBCS_OBJ)
|
$(LIBCS_LIB): $(LIBCS_OBJ)
|
||||||
ar rcs $(LIBCS_LIB) $(LIBCS_OBJ)
|
ar rcs $(LIBCS_LIB) $(LIBCS_OBJ)
|
||||||
|
|
||||||
repl: $(LIBCS_LIB) repl.cc
|
repl: $(LIBCS_LIB) tools/repl.cc tools/linenoise.cc tools/linenoise.hh
|
||||||
$(CXX) $(CXXFLAGS) $(LIBCS_CXXFLAGS) $(LDFLAGS) repl.cc -o repl $(LIBCS_LIB)
|
$(CXX) $(CXXFLAGS) $(LIBCS_CXXFLAGS) $(LDFLAGS) \
|
||||||
|
-Itools -DCS_REPL_USE_LINENOISE tools/linenoise.cc \
|
||||||
|
tools/repl.cc -o repl $(LIBCS_LIB)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(LIBCS_LIB) $(LIBCS_OBJ)
|
rm -f $(LIBCS_LIB) $(LIBCS_OBJ)
|
||||||
|
|
|
@ -34,6 +34,11 @@ https://github.com/OctaForge/OctaSTD
|
||||||
If OctaSTD can work on your system, so can libcubescript.
|
If OctaSTD can work on your system, so can libcubescript.
|
||||||
|
|
||||||
The supplied Makefile builds a static library on Unix-like OSes. Link this
|
The supplied Makefile builds a static library on Unix-like OSes. Link this
|
||||||
library together with your application and everything should just work.
|
library together with your application and everything should just work. It also
|
||||||
|
builds the REPL.
|
||||||
|
|
||||||
|
The project also bundles the linenoise line editing library which has been modified
|
||||||
|
to compile cleanly as C++ (with the same flags as libcubescript). It's used strictly
|
||||||
|
for the REPL only (you don't need it to build libcubescript itself).
|
||||||
|
|
||||||
See COPYING.md for licensing information.
|
See COPYING.md for licensing information.
|
||||||
|
|
|
@ -18,7 +18,9 @@ CsString floatstr(CsFloat v) {
|
||||||
|
|
||||||
char *cs_dup_ostr(ostd::ConstCharRange s) {
|
char *cs_dup_ostr(ostd::ConstCharRange s) {
|
||||||
char *r = new char[s.size() + 1];
|
char *r = new char[s.size() + 1];
|
||||||
memcpy(r, s.data(), s.size());
|
if (s.data()) {
|
||||||
|
memcpy(r, s.data(), s.size());
|
||||||
|
}
|
||||||
r[s.size()] = 0;
|
r[s.size()] = 0;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +101,7 @@ Command::Command(
|
||||||
ostd::Uint32 amask, int nargs, CmdFunc f
|
ostd::Uint32 amask, int nargs, CmdFunc f
|
||||||
):
|
):
|
||||||
CsIdent(CsIdentType::command, name, 0),
|
CsIdent(CsIdentType::command, name, 0),
|
||||||
cargs(!args.empty() ? cs_dup_ostr(args) : nullptr),
|
cargs(cs_dup_ostr(args)),
|
||||||
argmask(amask), numargs(nargs), cb_cftv(ostd::move(f))
|
argmask(amask), numargs(nargs), cb_cftv(ostd::move(f))
|
||||||
{
|
{
|
||||||
p_type = tp;
|
p_type = tp;
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
--- linenoise.c 2016-09-01 13:45:57.027318000 +0100
|
||||||
|
+++ linenoise.cc 2016-09-01 17:42:43.681873000 +0100
|
||||||
|
@@ -115,11 +115,11 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
-#include "linenoise.h"
|
||||||
|
+#include "linenoise.hh"
|
||||||
|
|
||||||
|
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
|
||||||
|
#define LINENOISE_MAX_LINE 4096
|
||||||
|
-static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
|
||||||
|
+static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
|
||||||
|
static linenoiseCompletionCallback *completionCallback = NULL;
|
||||||
|
static linenoiseHintsCallback *hintsCallback = NULL;
|
||||||
|
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
|
||||||
|
@@ -430,10 +430,10 @@
|
||||||
|
size_t len = strlen(str);
|
||||||
|
char *copy, **cvec;
|
||||||
|
|
||||||
|
- copy = malloc(len+1);
|
||||||
|
+ copy = static_cast<char *>(malloc(len+1));
|
||||||
|
if (copy == NULL) return;
|
||||||
|
memcpy(copy,str,len+1);
|
||||||
|
- cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
|
||||||
|
+ cvec = static_cast<char **>(realloc(lc->cvec,sizeof(char*)*(lc->len+1)));
|
||||||
|
if (cvec == NULL) {
|
||||||
|
free(copy);
|
||||||
|
return;
|
||||||
|
@@ -459,11 +459,11 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
static void abAppend(struct abuf *ab, const char *s, int len) {
|
||||||
|
- char *new = realloc(ab->b,ab->len+len);
|
||||||
|
+ char *newb = static_cast<char *>(realloc(ab->b,ab->len+len));
|
||||||
|
|
||||||
|
- if (new == NULL) return;
|
||||||
|
- memcpy(new+ab->len,s,len);
|
||||||
|
- ab->b = new;
|
||||||
|
+ if (newb == NULL) return;
|
||||||
|
+ memcpy(newb+ab->len,s,len);
|
||||||
|
+ ab->b = newb;
|
||||||
|
ab->len += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -530,7 +530,7 @@
|
||||||
|
snprintf(seq,64,"\x1b[0K");
|
||||||
|
abAppend(&ab,seq,strlen(seq));
|
||||||
|
/* Move cursor to original position. */
|
||||||
|
- snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
|
||||||
|
+ snprintf(seq,64,"\r\x1b[%dC", int(pos+plen));
|
||||||
|
abAppend(&ab,seq,strlen(seq));
|
||||||
|
if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
|
||||||
|
abFree(&ab);
|
||||||
|
@@ -552,7 +552,7 @@
|
||||||
|
struct abuf ab;
|
||||||
|
|
||||||
|
/* Update maxrows if needed. */
|
||||||
|
- if (rows > (int)l->maxrows) l->maxrows = rows;
|
||||||
|
+ if (rows > int(l->maxrows)) l->maxrows = rows;
|
||||||
|
|
||||||
|
/* First step: clear all the lines used before. To do so start by
|
||||||
|
* going to the last row. */
|
||||||
|
@@ -593,7 +593,7 @@
|
||||||
|
snprintf(seq,64,"\r");
|
||||||
|
abAppend(&ab,seq,strlen(seq));
|
||||||
|
rows++;
|
||||||
|
- if (rows > (int)l->maxrows) l->maxrows = rows;
|
||||||
|
+ if (rows > int(l->maxrows)) l->maxrows = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move cursor to right position. */
|
||||||
|
@@ -608,7 +608,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set column. */
|
||||||
|
- col = (plen+(int)l->pos) % (int)l->cols;
|
||||||
|
+ col = (plen+int(l->pos)) % int(l->cols);
|
||||||
|
lndebug("set col %d", 1+col);
|
||||||
|
if (col)
|
||||||
|
snprintf(seq,64,"\r\x1b[%dC", col);
|
||||||
|
@@ -824,7 +824,7 @@
|
||||||
|
refreshLine(&l);
|
||||||
|
hintsCallback = hc;
|
||||||
|
}
|
||||||
|
- return (int)l.len;
|
||||||
|
+ return int(l.len);
|
||||||
|
case CTRL_C: /* ctrl-c */
|
||||||
|
errno = EAGAIN;
|
||||||
|
return -1;
|
||||||
|
@@ -970,7 +970,7 @@
|
||||||
|
if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
|
||||||
|
|
||||||
|
printf("'%c' %02x (%d) (type quit to exit)\n",
|
||||||
|
- isprint(c) ? c : '?', (int)c, (int)c);
|
||||||
|
+ isprint(c) ? c : '?', int(c), int(c));
|
||||||
|
printf("\r"); /* Go left edge manually, we are in raw mode. */
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
@@ -1008,7 +1008,7 @@
|
||||||
|
if (maxlen == 0) maxlen = 16;
|
||||||
|
maxlen *= 2;
|
||||||
|
char *oldval = line;
|
||||||
|
- line = realloc(line,maxlen);
|
||||||
|
+ line = static_cast<char *>(realloc(line,maxlen));
|
||||||
|
if (line == NULL) {
|
||||||
|
if (oldval) free(oldval);
|
||||||
|
return NULL;
|
||||||
|
@@ -1104,7 +1104,7 @@
|
||||||
|
|
||||||
|
/* Initialization on first call. */
|
||||||
|
if (history == NULL) {
|
||||||
|
- history = malloc(sizeof(char*)*history_max_len);
|
||||||
|
+ history = static_cast<char **>(malloc(sizeof(char*)*history_max_len));
|
||||||
|
if (history == NULL) return 0;
|
||||||
|
memset(history,0,(sizeof(char*)*history_max_len));
|
||||||
|
}
|
||||||
|
@@ -1131,14 +1131,14 @@
|
||||||
|
* just the latest 'len' elements if the new history length value is smaller
|
||||||
|
* than the amount of items already inside the history. */
|
||||||
|
int linenoiseHistorySetMaxLen(int len) {
|
||||||
|
- char **new;
|
||||||
|
+ char **newb;
|
||||||
|
|
||||||
|
if (len < 1) return 0;
|
||||||
|
if (history) {
|
||||||
|
int tocopy = history_len;
|
||||||
|
|
||||||
|
- new = malloc(sizeof(char*)*len);
|
||||||
|
- if (new == NULL) return 0;
|
||||||
|
+ newb = static_cast<char **>(malloc(sizeof(char*)*len));
|
||||||
|
+ if (newb == NULL) return 0;
|
||||||
|
|
||||||
|
/* If we can't copy everything, free the elements we'll not use. */
|
||||||
|
if (len < tocopy) {
|
||||||
|
@@ -1147,10 +1147,10 @@
|
||||||
|
for (j = 0; j < tocopy-len; j++) free(history[j]);
|
||||||
|
tocopy = len;
|
||||||
|
}
|
||||||
|
- memset(new,0,sizeof(char*)*len);
|
||||||
|
- memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
|
||||||
|
+ memset(newb,0,sizeof(char*)*len);
|
||||||
|
+ memcpy(newb,history+(history_len-tocopy), sizeof(char*)*tocopy);
|
||||||
|
free(history);
|
||||||
|
- history = new;
|
||||||
|
+ history = newb;
|
||||||
|
}
|
||||||
|
history_max_len = len;
|
||||||
|
if (history_len > history_max_len)
|
|
@ -0,0 +1,22 @@
|
||||||
|
--- linenoise.h 2016-09-01 13:45:57.027428000 +0100
|
||||||
|
+++ linenoise.hh 2016-09-01 17:42:43.681920000 +0100
|
||||||
|
@@ -39,10 +39,6 @@
|
||||||
|
#ifndef __LINENOISE_H
|
||||||
|
#define __LINENOISE_H
|
||||||
|
|
||||||
|
-#ifdef __cplusplus
|
||||||
|
-extern "C" {
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
typedef struct linenoiseCompletions {
|
||||||
|
size_t len;
|
||||||
|
char **cvec;
|
||||||
|
@@ -66,8 +62,4 @@
|
||||||
|
void linenoiseSetMultiLine(int ml);
|
||||||
|
void linenoisePrintKeyCodes(void);
|
||||||
|
|
||||||
|
-#ifdef __cplusplus
|
||||||
|
-}
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
#endif /* __LINENOISE_H */
|
44
repl.cc
44
repl.cc
|
@ -1,44 +0,0 @@
|
||||||
#include <ostd/io.hh>
|
|
||||||
#include <ostd/string.hh>
|
|
||||||
#include <ostd/maybe.hh>
|
|
||||||
|
|
||||||
#include <cubescript.hh>
|
|
||||||
|
|
||||||
using namespace cscript;
|
|
||||||
|
|
||||||
ostd::ConstCharRange version =
|
|
||||||
"CubeScript 0.0.1 (REPL mode) Copyright (C) 2016 Daniel \"q66\" Kolesa";
|
|
||||||
CsSvar *prompt = nullptr;
|
|
||||||
|
|
||||||
static ostd::String read_line() {
|
|
||||||
ostd::write(prompt->get_value());
|
|
||||||
auto app = ostd::appender<ostd::String>();
|
|
||||||
/* i really need to implement some sort of get_line for ostd streams */
|
|
||||||
for (char c = ostd::in.getchar(); c && (c != '\n'); c = ostd::in.getchar()) {
|
|
||||||
app.put(c);
|
|
||||||
}
|
|
||||||
return ostd::move(app.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_tty(CsState &cs) {
|
|
||||||
ostd::writeln(version);
|
|
||||||
for (;;) {
|
|
||||||
auto line = read_line();
|
|
||||||
if (line.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CsValue ret;
|
|
||||||
ret.set_null();
|
|
||||||
cs.run_ret(line, ret);
|
|
||||||
if (ret.get_type() != CsValueType::null) {
|
|
||||||
ostd::writeln(ret.get_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
CsState cs;
|
|
||||||
cs.init_libs();
|
|
||||||
prompt = cs.add_ident<CsSvar>("PROMPT", "> ");
|
|
||||||
do_tty(cs);
|
|
||||||
}
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef CS_REPL_HAS_EDIT
|
||||||
|
/* use nothing (no line editing support) */
|
||||||
|
|
||||||
|
#include <ostd/string.hh>
|
||||||
|
#include <ostd/maybe.hh>
|
||||||
|
|
||||||
|
static void init_lineedit(ostd::ConstCharRange) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static ostd::Maybe<ostd::String> read_line(CsSvar *pr) {
|
||||||
|
ostd::write(pr->get_value());
|
||||||
|
ostd::String ret;
|
||||||
|
/* i really need to implement some sort of get_line for ostd streams */
|
||||||
|
for (char c = ostd::in.getchar(); c && (c != '\n'); c = ostd::in.getchar()) {
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
return ostd::move(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_history(ostd::ConstCharRange) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,57 @@
|
||||||
|
#ifdef CS_REPL_USE_LIBEDIT
|
||||||
|
#ifndef CS_REPL_HAS_EDIT
|
||||||
|
#define CS_REPL_HAS_EDIT
|
||||||
|
/* use the NetBSD libedit library */
|
||||||
|
|
||||||
|
#include <ostd/string.hh>
|
||||||
|
#include <ostd/maybe.hh>
|
||||||
|
|
||||||
|
#include <histedit.h>
|
||||||
|
|
||||||
|
static EditLine *els = nullptr;
|
||||||
|
static History *elh = nullptr;
|
||||||
|
|
||||||
|
static char *el_prompt(EditLine *el) {
|
||||||
|
void *prompt = nullptr;
|
||||||
|
el_get(el, EL_CLIENTDATA, &prompt);
|
||||||
|
if (!prompt) {
|
||||||
|
return const_cast<char *>("");
|
||||||
|
}
|
||||||
|
return const_cast<char *>(static_cast<CsSvar *>(prompt)->get_value().data());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_lineedit(ostd::ConstCharRange progname) {
|
||||||
|
els = el_init(progname.data(), stdin, stdout, stderr);
|
||||||
|
elh = history_init();
|
||||||
|
|
||||||
|
/* init history with reasonable size */
|
||||||
|
HistEvent ev;
|
||||||
|
history(elh, &ev, H_SETSIZE, 1000);
|
||||||
|
el_set(els, EL_HIST, history, elh);
|
||||||
|
|
||||||
|
el_set(els, EL_PROMPT, el_prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ostd::Maybe<ostd::String> read_line(CsSvar *pr) {
|
||||||
|
int count;
|
||||||
|
el_set(els, EL_CLIENTDATA, static_cast<void *>(pr));
|
||||||
|
auto line = el_gets(els, &count);
|
||||||
|
if (count > 0) {
|
||||||
|
ostd::String ret = line;
|
||||||
|
/* libedit keeps the trailing \n */
|
||||||
|
ret.resize(ret.size() - 1);
|
||||||
|
return ostd::move(ret);
|
||||||
|
} else if (!count) {
|
||||||
|
return ostd::String();
|
||||||
|
}
|
||||||
|
return ostd::nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_history(ostd::ConstCharRange line) {
|
||||||
|
HistEvent ev;
|
||||||
|
/* backed by ostd::String so it's terminated */
|
||||||
|
history(elh, &ev, H_ENTER, line.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifdef CS_REPL_USE_LINENOISE
|
||||||
|
#ifndef CS_REPL_HAS_EDIT
|
||||||
|
#define CS_REPL_HAS_EDIT
|
||||||
|
/* use the bundled linenoise library, default */
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <ostd/string.hh>
|
||||||
|
#include <ostd/maybe.hh>
|
||||||
|
|
||||||
|
#include "linenoise.hh"
|
||||||
|
|
||||||
|
static void init_lineedit(ostd::ConstCharRange) {
|
||||||
|
/* sensible default history size */
|
||||||
|
linenoiseHistorySetMaxLen(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ostd::Maybe<ostd::String> read_line(CsSvar *pr) {
|
||||||
|
auto line = linenoise(pr->get_value().data());
|
||||||
|
if (!line) {
|
||||||
|
/* linenoise traps ctrl-c, detect it and let the user exit */
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
return ostd::nothing;
|
||||||
|
}
|
||||||
|
return ostd::String();
|
||||||
|
}
|
||||||
|
ostd::String ret = line;
|
||||||
|
linenoiseFree(line);
|
||||||
|
return ostd::move(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_history(ostd::ConstCharRange line) {
|
||||||
|
/* backed by ostd::String so it's terminated */
|
||||||
|
linenoiseHistoryAdd(line.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifdef CS_REPL_USE_READLINE
|
||||||
|
#ifndef CS_REPL_HAS_EDIT
|
||||||
|
#define CS_REPL_HAS_EDIT
|
||||||
|
/* use the GNU readline library */
|
||||||
|
|
||||||
|
#include <ostd/string.hh>
|
||||||
|
#include <ostd/maybe.hh>
|
||||||
|
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#include <readline/history.h>
|
||||||
|
|
||||||
|
static void init_lineedit(ostd::ConstCharRange) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static ostd::Maybe<ostd::String> read_line(CsSvar *pr) {
|
||||||
|
auto line = readline(pr->get_value().data());
|
||||||
|
if (!line) {
|
||||||
|
return ostd::String();
|
||||||
|
}
|
||||||
|
ostd::String ret = line;
|
||||||
|
free(line);
|
||||||
|
return ostd::move(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_history(ostd::ConstCharRange line) {
|
||||||
|
/* backed by ostd::String so it's terminated */
|
||||||
|
add_history(line.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,65 @@
|
||||||
|
/* linenoise.h -- VERSION 1.0
|
||||||
|
*
|
||||||
|
* Guerrilla line editing library against the idea that a line editing lib
|
||||||
|
* needs to be 20,000 lines of C code.
|
||||||
|
*
|
||||||
|
* See linenoise.c for more information.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||||
|
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINENOISE_H
|
||||||
|
#define __LINENOISE_H
|
||||||
|
|
||||||
|
typedef struct linenoiseCompletions {
|
||||||
|
size_t len;
|
||||||
|
char **cvec;
|
||||||
|
} linenoiseCompletions;
|
||||||
|
|
||||||
|
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
|
||||||
|
typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
|
||||||
|
typedef void(linenoiseFreeHintsCallback)(void *);
|
||||||
|
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
||||||
|
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
||||||
|
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
||||||
|
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
||||||
|
|
||||||
|
char *linenoise(const char *prompt);
|
||||||
|
void linenoiseFree(void *ptr);
|
||||||
|
int linenoiseHistoryAdd(const char *line);
|
||||||
|
int linenoiseHistorySetMaxLen(int len);
|
||||||
|
int linenoiseHistorySave(const char *filename);
|
||||||
|
int linenoiseHistoryLoad(const char *filename);
|
||||||
|
void linenoiseClearScreen(void);
|
||||||
|
void linenoiseSetMultiLine(int ml);
|
||||||
|
void linenoisePrintKeyCodes(void);
|
||||||
|
|
||||||
|
#endif /* __LINENOISE_H */
|
|
@ -0,0 +1,84 @@
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <ostd/platform.hh>
|
||||||
|
#include <ostd/io.hh>
|
||||||
|
#include <ostd/string.hh>
|
||||||
|
#include <ostd/maybe.hh>
|
||||||
|
|
||||||
|
#include <cubescript.hh>
|
||||||
|
|
||||||
|
using namespace cscript;
|
||||||
|
|
||||||
|
ostd::ConstCharRange version = "CubeScript 0.0.1 (REPL mode)";
|
||||||
|
|
||||||
|
/* util */
|
||||||
|
|
||||||
|
#ifdef OSTD_PLATFORM_WIN32
|
||||||
|
#include <io.h>
|
||||||
|
static bool stdin_is_tty() {
|
||||||
|
return _isatty(_fileno(stdin));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
static bool stdin_is_tty() {
|
||||||
|
return isatty(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* line editing support */
|
||||||
|
|
||||||
|
#include "tools/edit_linenoise.hh"
|
||||||
|
#include "tools/edit_libedit.hh"
|
||||||
|
#include "tools/edit_readline.hh"
|
||||||
|
#include "tools/edit_fallback.hh"
|
||||||
|
|
||||||
|
static void do_tty(CsState &cs) {
|
||||||
|
auto prompt = cs.add_ident<CsSvar>("PROMPT", "> ");
|
||||||
|
auto prompt2 = cs.add_ident<CsSvar>("PROMPT2", ">> ");
|
||||||
|
|
||||||
|
bool do_exit = false;
|
||||||
|
cs.add_command("quit", "", [&do_exit](auto, auto &) {
|
||||||
|
do_exit = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
ostd::writeln(version);
|
||||||
|
for (;;) {
|
||||||
|
auto line = read_line(prompt);
|
||||||
|
if (!line) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto lv = ostd::move(line.value());
|
||||||
|
if (lv.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while (lv.back() == '\\') {
|
||||||
|
lv.resize(lv.size() - 1);
|
||||||
|
auto line2 = read_line(prompt2);
|
||||||
|
if (!line2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lv += line2.value();
|
||||||
|
}
|
||||||
|
add_history(lv);
|
||||||
|
CsValue ret;
|
||||||
|
ret.set_null();
|
||||||
|
cs.run_ret(lv, ret);
|
||||||
|
if (ret.get_type() != CsValueType::null) {
|
||||||
|
ostd::writeln(ret.get_str());
|
||||||
|
}
|
||||||
|
if (do_exit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char **argv) {
|
||||||
|
CsState cs;
|
||||||
|
cs.init_libs();
|
||||||
|
if (stdin_is_tty()) {
|
||||||
|
init_lineedit(argv[0]);
|
||||||
|
do_tty(cs);
|
||||||
|
} else {
|
||||||
|
ostd::err.writeln("Only interactive mode is supported for now.");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue