[gjs/ewlsh/nova-repl] WIP - Add multiline input
- From: Evan Welsh <ewlsh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/ewlsh/nova-repl] WIP - Add multiline input
- Date: Wed, 1 Sep 2021 07:42:25 +0000 (UTC)
commit ad0fa71cc1c5a1cfbc0b2b0217e8f4dca97da775
Author: Evan Welsh <contact evanwelsh com>
Date: Wed Sep 1 00:41:52 2021 -0700
WIP - Add multiline input
modules/console.cpp | 26 +++++++++++++++++++++++++-
modules/esm/repl.js | 51 ++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 65 insertions(+), 12 deletions(-)
---
diff --git a/modules/console.cpp b/modules/console.cpp
index 46da5cfb..228055f3 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -320,6 +320,27 @@ static bool gjs_console_eval_js(JSContext* cx, unsigned argc, JS::Value* vp) {
return ok;
}
+GJS_JSAPI_RETURN_CONVENTION
+static bool gjs_console_is_valid_js(JSContext* cx, unsigned argc,
+ JS::Value* vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ JS::RootedString str(cx);
+
+ if (!gjs_parse_call_args(cx, "isValid", args, "S", "code", &str))
+ return false;
+
+ JS::UniqueChars code;
+ size_t code_len;
+ if (!gjs_string_to_utf8_n(cx, str, &code, &code_len))
+ return false;
+
+ JS::RootedObject global(cx, gjs_get_import_global(cx));
+
+ args.rval().setBoolean(
+ JS_Utf8BufferIsCompilableUnit(cx, global, code.get(), code_len));
+ return true;
+}
+
bool gjs_console_get_terminal_size(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
@@ -362,7 +383,10 @@ bool gjs_define_console_private_stuff(JSContext* context,
return JS_DefineFunction(context, module, "enable_raw_mode",
gjs_console_enable_raw_mode, 0,
GJS_MODULE_PROP_FLAGS) &&
- JS_DefineFunction(context, module, "eval", gjs_console_eval_js, 0,
+ JS_DefineFunction(context, module, "eval", gjs_console_eval_js, 2,
+ GJS_MODULE_PROP_FLAGS) &&
+ JS_DefineFunction(context, module, "isValid",
+ gjs_console_is_valid_js, 1,
GJS_MODULE_PROP_FLAGS) &&
JS_DefineFunction(context, module, "get_size",
gjs_console_get_terminal_size, 0,
diff --git a/modules/esm/repl.js b/modules/esm/repl.js
index f8b72bfd..d365938a 100644
--- a/modules/esm/repl.js
+++ b/modules/esm/repl.js
@@ -1,6 +1,6 @@
import Gio from 'gi://Gio';
-import { Ansi, AnsiColors, Keycode, Figures } from '_cliffy';
+import { Ansi, AnsiColors, Keycode, Figures } from './_cliffy.js';
const stdin = Gio.UnixInputStream.new(0, false);
const stdout = Gio.UnixOutputStream.new(1, false);
@@ -33,10 +33,12 @@ class ReplInput {
this.history = [];
this.inputChars = [];
this.inputIndex = 0;
+
+ this.lines = [];
}
-
+
/**
- * @returns {readonly string[]}
+ * @returns {string}
*/
getValue() {
if (this.historyIndex >= 0) {
@@ -50,18 +52,20 @@ class ReplInput {
*/
getEditableValue() {
if (this.historyIndex > -1) {
+ // TODO(ewlsh): This allows editing each history entry
+ // 'in place'.
return this.history[this.historyIndex];
}
return this.inputChars;
}
validate(input) {
- return true;
+ return Console.isValid(input);
}
- clear() {
+ clear(lines = 1) {
this.writeSync(Ansi.cursorLeft);
- this.writeSync(Ansi.eraseLine);
+ this.writeSync(Ansi.eraseDown(lines));
}
historyUp() {
@@ -113,14 +117,30 @@ class ReplInput {
processLine() {
const value = this.getValue();
- this.writeSync('\n');
- this.flush();
+ // Rebuild the input...
+ const js = [...this.lines, value].join('\n');
+
+ // Reset state...
this.history.unshift(value.split(''));
this.historyIndex = -1;
this.inputChars = [];
this.inputIndex = 0;
- this._input?.(value);
+ // Append the new line...
+ this.writeSync('\n');
+ this.flush();
+
+ // Only trigger input if this is a compilable unit...
+ if (this.validate(js)) {
+ // Reset lines before input is triggered
+ this.lines = [];
+ this._input?.(js);
+ } else {
+ // Buffer the input until a compilable unit is found...
+ this.lines.push(value);
+ }
+
+
}
handleEvent(key) {
@@ -177,10 +197,19 @@ class ReplInput {
render() {
const value = this.getValue();
+ // Prevent the cursor from flashing while we render...
this.writeSync(Ansi.cursorHide);
this.clear();
-
- this.writeSync(this.$prompt + value);
+
+ if (this.lines.length > 0) {
+ // Create a prefix like '... ' that matches the current
+ // prompt length...
+ const prefix = ' '.padStart(this.$promptLength, '.');
+ this.writeSync(prefix + value);
+ } else {
+ this.writeSync(this.$prompt + value);
+ }
+
this.updateInputIndex(value);
this.writeSync(Ansi.cursorTo(this.$promptLength + this.inputIndex + 1));
this.writeSync(Ansi.cursorShow);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]