[gjs/ewlsh/nova-repl] WIP - Round out keyboard shortcut support
- From: Evan Welsh <ewlsh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/ewlsh/nova-repl] WIP - Round out keyboard shortcut support
- Date: Wed, 1 Sep 2021 16:16:01 +0000 (UTC)
commit b0a4bec8e88236d0d637e993ea5fa718835ad46a
Author: Evan Welsh <contact evanwelsh com>
Date: Wed Sep 1 07:25:00 2021 -0700
WIP - Round out keyboard shortcut support
Let's not reinvent the wheel for word detection
modules/esm/repl.js | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 151 insertions(+), 1 deletion(-)
---
diff --git a/modules/esm/repl.js b/modules/esm/repl.js
index d365938a..c1442eaa 100644
--- a/modules/esm/repl.js
+++ b/modules/esm/repl.js
@@ -44,6 +44,7 @@ class ReplInput {
if (this.historyIndex >= 0) {
return this.history[this.historyIndex].join('');
}
+
return this.inputChars.join('');
}
@@ -59,6 +60,14 @@ class ReplInput {
return this.inputChars;
}
+ editValue(editor) {
+ if (this.historyIndex > -1) {
+ return this.history[this.historyIndex] = editor(this.history[this.historyIndex]);
+ }
+
+ return this.inputChars = editor(this.inputChars);
+ }
+
validate(input) {
return Console.isValid(input);
}
@@ -115,6 +124,94 @@ class ReplInput {
this.moveCursorLeft();
}
+ deleteCharRightOrClose() {
+ const editableValue = this.getEditableValue();
+ if (this.inputIndex < editableValue.length - 1) {
+ editableValue.splice(this.inputIndex, 1);
+ } else {
+ this.stop();
+ }
+ }
+
+ deleteToBeginning() {
+ const editableValue = this.getEditableValue();
+
+ editableValue.splice(0, this.inputIndex);
+ }
+
+ deleteToEnd() {
+ const editableValue = this.getEditableValue();
+
+ editableValue.splice(this.inputIndex);
+ }
+
+ /**
+ * Adapted from lib/readline.js in Node.js
+ */
+ _deleteWordLeft() {
+ this.editValue((value) => {
+ if (this.inputIndex > 0) {
+ // Reverse the string and match a word near beginning
+ // to avoid quadratic time complexity
+ let leading = value.slice(0, this.inputIndex);
+ const reversed = [...leading].reverse().join('');
+ const match = reversed.match(/^\s*(?:[^\w\s]+|\w+)?/);
+ leading = leading.slice(0,
+ leading.length - match[0].length);
+ value = leading.concat(value.slice(this.inputIndex));
+ this.inputIndex = leading.length;
+
+ return value;
+ }
+ });
+ }
+
+ /**
+ * Adapted from lib/readline.js in Node.js
+ */
+ _deleteWordRight() {
+ this.editValue((value) => {
+ if (this.inputChars.length > 0 && this.inputIndex < value.length) {
+ const trailing = value.slice(this.inputIndex).join('');
+ const match = trailing.match(/^(?:\s+|\W+|\w+)\s*/);
+ value = value.slice(0, this.inputIndex).concat(
+ trailing.slice(match[0].length));
+ return value;
+ }
+ });
+ }
+
+ /**
+ * Adapted from lib/readline.js in Node.js
+ */
+ _wordLeft() {
+ if (this.inputIndex > 0) {
+ const value = this.getValue();
+ // Reverse the string and match a word near beginning
+ // to avoid quadratic time complexity
+ const leading = value.slice(0, this.inputIndex);
+ const reversed = Array.from(leading).reverse().join('');
+ const match = reversed.match(/^\s*(?:[^\w\s]+|\w+)?/);
+
+ this.inputIndex -= match[0].length;
+ this.inputIndex = Math.max(0, this.inputIndex);
+ }
+ }
+
+ /**
+ * Adapted from lib/readline.js in Node.js
+ */
+ _wordRight() {
+ const value = this.getValue();
+
+ if (this.inputIndex < value.length) {
+ const trailing = value.slice(this.inputIndex);
+ const match = trailing.match(/^(?:\s+|[^\w\s]+|\w+)\s*/);
+
+ this.inputIndex += match[0].length;
+ }
+ }
+
processLine() {
const value = this.getValue();
// Rebuild the input...
@@ -144,8 +241,20 @@ class ReplInput {
}
handleEvent(key) {
- if (key.ctrl) {
+ if (key.ctrl && !key.meta && !key.shift) {
switch (key.name) {
+ case 'h':
+ this.deleteChar();
+ return;
+ case 'd':
+ this.deleteCharRightOrClose();
+ return;
+ case 'u':
+ this.deleteToBeginning();
+ return;
+ case 'k':
+ this.deleteToEnd();
+ return;
case 'a':
this.moveCursorToBeginning();
return;
@@ -158,6 +267,47 @@ class ReplInput {
case 'f':
this.moveCursorRight();
return;
+ case 'l':
+ // TODO(ewlsh): Use internal API instead...
+ console.clear();
+ return;
+ case 'n':
+ this.historyDown();
+ return;
+ case 'p':
+ this.historyUp();
+ return;
+ case 'z':
+ // Pausing is unsupported.
+ return;
+ case 'w':
+ case 'backspace':
+ this._deleteWordLeft();
+ return;
+ case 'delete':
+ this._deleteWordRight();
+ return;
+ case 'left':
+ this._wordLeft();
+ return;
+ case 'right':
+ this._wordRight();
+ return;
+ }
+ } else if (key.meta && !key.shift) {
+ switch (key.name) {
+ case 'd':
+ this._deleteWordRight();
+ return;
+ case 'backspace':
+ this._deleteWordLeft();
+ return;
+ case 'b':
+ this._wordLeft();
+ return;
+ case 'f':
+ this._wordRight();
+ return;
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]