-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
gh-136251: Improvements to WASM demo REPL #136252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
af4aa0d
394815e
aab9ccc
bd52abe
77cc952
4cfa3f1
b688663
43a47dc
6d5f698
16cfea2
faf2ba4
70d4a17
ce5ebca
66cf49d
8fe92d6
25fd7fc
9a26d70
c477e30
4dcc6fb
e06a7b2
3e76313
26ddd07
7d33525
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,7 @@ | |
margin: 0 auto; | ||
} | ||
#editor { | ||
padding:5px; | ||
padding: 5px; | ||
border: 1px solid black; | ||
width: 100%; | ||
height: 300px; | ||
|
@@ -139,7 +139,7 @@ | |
|
||
class WasmTerminal { | ||
constructor() { | ||
this.reset() | ||
this.reset(); | ||
|
||
this.xterm = new Terminal({ | ||
scrollback: 10000, | ||
|
@@ -158,7 +158,7 @@ | |
this.xterm.onData(this.handleTermData); | ||
} | ||
|
||
reset(){ | ||
reset() { | ||
this.inputBuffer = new BufferQueue(); | ||
this.input = ""; | ||
this.resolveInput = null; | ||
|
@@ -203,29 +203,29 @@ | |
if (!(ord === 0x1b || ord == 0x7f || ord < 32)) { | ||
this.inputBuffer.addData(data); | ||
} | ||
// TODO: Handle more escape sequences? | ||
// TODO: Handle more escape sequences? | ||
} else if (ord === 0x1b) { | ||
// Handle special characters | ||
switch(data.slice(1)){ | ||
case '[A': // up | ||
switch (data.slice(1)) { | ||
case "[A": // up | ||
this.historyBack(); | ||
break; | ||
case '[B': // down | ||
case "[B": // down | ||
this.historyForward(); | ||
break; | ||
case '[C': // right | ||
case "[C": // right | ||
this.cursorRight(); | ||
break; | ||
case '[D': // left | ||
case "[D": // left | ||
this.cursorLeft(); | ||
break; | ||
case '[H': // home key | ||
case "[H": // home key | ||
this.cursorHome(true); | ||
break; | ||
case '[F': // end key | ||
case "[F": // end key | ||
this.cursorEnd(true); | ||
break; | ||
case '[3~': // delete key | ||
case "[3~": // delete key | ||
this.deleteAtCursor(); | ||
break; | ||
default: | ||
|
@@ -248,10 +248,12 @@ | |
break; | ||
case "\x03": // CTRL+C | ||
this.input = ""; | ||
this.xterm.write("\n") | ||
this.xterm.write('\x1b[' + (this.cursorPosition + 4) + 'D'); | ||
this.xterm.write("\n"); | ||
this.xterm.write( | ||
"\x1b[" + (this.cursorPosition + 4) + "D", | ||
); | ||
this.cursorPosition = 0; | ||
this.resolveInput("" + '\n'); | ||
this.resolveInput("" + "\n"); | ||
break; | ||
case "\x09": // TAB | ||
this.handleTab(); | ||
|
@@ -274,8 +276,8 @@ | |
} | ||
}; | ||
|
||
clearLine(){ | ||
this.xterm.write('\x1b[K') | ||
clearLine() { | ||
this.xterm.write("\x1b[K"); | ||
} | ||
|
||
writeLine(line) { | ||
|
@@ -286,12 +288,15 @@ | |
|
||
handleCursorInsert(data) { | ||
const trailing = this.input.slice(this.cursorPosition); | ||
this.input = this.input.slice(0, this.cursorPosition) + data + trailing; | ||
this.input = | ||
this.input.slice(0, this.cursorPosition) + | ||
data + | ||
trailing; | ||
this.cursorPosition += data.length; | ||
this.xterm.write(data); | ||
if (trailing.length !== 0){ | ||
if (trailing.length !== 0) { | ||
this.xterm.write(trailing); | ||
this.xterm.write('\x1b[' + trailing.length + 'D'); | ||
this.xterm.write("\x1b[" + trailing.length + "D"); | ||
} | ||
this.updateHistory(); | ||
} | ||
|
@@ -303,12 +308,12 @@ | |
const suffix = this.input.slice(this.cursorPosition); | ||
const count = 4 - (this.cursorPosition % 4); | ||
const toAdd = " ".repeat(count); | ||
this.input = prefix + toAdd + suffix | ||
this.input = prefix + toAdd + suffix; | ||
this.cursorHome(false); | ||
this.clearLine(); | ||
this.xterm.write(this.input); | ||
if (suffix){ | ||
this.xterm.write('\x1b[' + suffix.length + 'D'); | ||
if (suffix) { | ||
this.xterm.write("\x1b[" + suffix.length + "D"); | ||
} | ||
this.cursorPosition += count; | ||
this.updateHistory(false); | ||
|
@@ -323,77 +328,85 @@ | |
return; | ||
} | ||
const trailing = this.input.slice(this.cursorPosition); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's this change do? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is part of the backspace handler (though there's similar code for adding a character, and for the delete key). Now that we have the ability to use the arrow keys to move around within a line, we need something like this to make sure that if we backspace/delete/insert in the middle of a line we can still see all of the characters that come after the one we just deleted. |
||
this.input = this.input.slice(0, this.cursorPosition - 1) + trailing; | ||
this.input = | ||
this.input.slice(0, this.cursorPosition - 1) + trailing; | ||
this.cursorLeft(); | ||
this.clearLine(); | ||
if (trailing.length !== 0){ | ||
if (trailing.length !== 0) { | ||
this.xterm.write(trailing); | ||
this.xterm.write('\x1b[' + trailing.length + 'D'); | ||
this.xterm.write("\x1b[" + trailing.length + "D"); | ||
} | ||
this.updateHistory(); | ||
} | ||
|
||
deleteAtCursor(){ | ||
if (this.cursorPosition < this.input.length){ | ||
const trailing = this.input.slice(this.cursorPosition + 1); | ||
this.input = this.input.slice(0, this.cursorPosition) + trailing; | ||
deleteAtCursor() { | ||
if (this.cursorPosition < this.input.length) { | ||
const trailing = this.input.slice( | ||
this.cursorPosition + 1, | ||
); | ||
this.input = | ||
this.input.slice(0, this.cursorPosition) + trailing; | ||
this.clearLine(); | ||
if (trailing.length !== 0){ | ||
if (trailing.length !== 0) { | ||
this.xterm.write(trailing); | ||
this.xterm.write('\x1b[' + trailing.length + 'D'); | ||
this.xterm.write("\x1b[" + trailing.length + "D"); | ||
} | ||
this.updateHistory(); | ||
} | ||
} | ||
|
||
cursorRight(){ | ||
if (this.cursorPosition < this.input.length){ | ||
this.cursorPosition += 1; | ||
this.xterm.write('\x1b[C'); | ||
} | ||
cursorRight() { | ||
if (this.cursorPosition < this.input.length) { | ||
this.cursorPosition += 1; | ||
this.xterm.write("\x1b[C"); | ||
} | ||
} | ||
|
||
cursorLeft(){ | ||
if (this.cursorPosition > 0){ | ||
cursorLeft() { | ||
if (this.cursorPosition > 0) { | ||
this.cursorPosition -= 1; | ||
this.xterm.write('\x1b[D'); | ||
this.xterm.write("\x1b[D"); | ||
} | ||
} | ||
|
||
cursorHome(updatePosition) { | ||
if (this.cursorPosition > 0){ | ||
this.xterm.write('\x1b[' + this.cursorPosition + 'D'); | ||
if (this.cursorPosition > 0) { | ||
this.xterm.write("\x1b[" + this.cursorPosition + "D"); | ||
if (updatePosition) { | ||
this.cursorPosition = 0; | ||
} | ||
} | ||
} | ||
|
||
cursorEnd() { | ||
if (this.cursorPosition < this.input.length){ | ||
this.xterm.write('\x1b[' + (this.input.length - this.cursorPosition) + 'C'); | ||
if (this.cursorPosition < this.input.length) { | ||
this.xterm.write( | ||
"\x1b[" + | ||
(this.input.length - this.cursorPosition) + | ||
"C", | ||
); | ||
this.cursorPosition = this.input.length; | ||
} | ||
} | ||
|
||
updateHistory(){ | ||
if (this.historyIndex !== -1){ | ||
updateHistory() { | ||
if (this.historyIndex !== -1) { | ||
this.historyBuffer[this.historyIndex] = this.input; | ||
}else{ | ||
} else { | ||
this.beforeHistoryNav = this.input; | ||
} | ||
} | ||
|
||
historyBack(){ | ||
if (this.history.length === 0){ | ||
historyBack() { | ||
if (this.history.length === 0) { | ||
return; | ||
}else if (this.historyIndex === -1){ | ||
} else if (this.historyIndex === -1) { | ||
// we're not currently navigating the history; store | ||
// the current command and then look at the end of our | ||
// history buffer | ||
this.beforeHistoryNav = this.input; | ||
this.historyIndex = this.history.length - 1; | ||
}else if (this.historyIndex > 0){ | ||
} else if (this.historyIndex > 0) { | ||
this.historyIndex -= 1; | ||
} | ||
this.input = this.historyBuffer[this.historyIndex]; | ||
|
@@ -403,14 +416,14 @@ | |
this.cursorPosition = this.input.length; | ||
} | ||
|
||
historyForward(){ | ||
if (this.history.length === 0 || this.historyIndex === -1){ | ||
historyForward() { | ||
if (this.history.length === 0 || this.historyIndex === -1) { | ||
// we're not currently navigating the history; NOP. | ||
return; | ||
}else if (this.historyIndex < this.history.length - 1){ | ||
} else if (this.historyIndex < this.history.length - 1) { | ||
this.historyIndex += 1; | ||
this.input = this.historyBuffer[this.historyIndex]; | ||
}else if (this.historyIndex == this.history.length - 1){ | ||
} else if (this.historyIndex == this.history.length - 1) { | ||
// we're coming back from the last history value; reset | ||
// the input to whatever it was when we started going | ||
// through the history | ||
|
@@ -449,9 +462,10 @@ | |
} | ||
return new Promise((resolve, reject) => { | ||
this.resolveInput = (value) => { | ||
if (value.replace(/\s/g, '').length != 0){ | ||
if (this.historyIndex !== -1){ | ||
this.historyBuffer[this.historyIndex] = this.history[this.historyIndex]; | ||
if (value.replace(/\s/g, "").length != 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally it would be nice to save the history when refreshing. Maybe add a "TODO"? (Not to imply that anyone will ever do it.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's definitely easy to change things so that the history persists if you do multiple iterations of "Start REPL" followed by "Stop". I actually kind of went out of my way to clear the history between REPL sessions. Saving history across reloads also probably wouldn't be too terribly hard if we wanted that; we could shove the history into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think saving the history is nice... particularly combined with reverse search! But it's up to you if you want to bother. |
||
if (this.historyIndex !== -1) { | ||
this.historyBuffer[this.historyIndex] = | ||
this.history[this.historyIndex]; | ||
} | ||
this.history.push(value.slice(0, -1)); | ||
this.historyBuffer.push(value.slice(0, -1)); | ||
|
@@ -594,11 +608,11 @@ | |
finishedCallback, | ||
); | ||
}; | ||
var editor; | ||
document.addEventListener('DOMContentLoaded', () => { | ||
editor = ace.edit("editor"); | ||
editor.session.setMode("ace/mode/python"); | ||
}); | ||
var editor; | ||
document.addEventListener("DOMContentLoaded", () => { | ||
editor = ace.edit("editor"); | ||
editor.session.setMode("ace/mode/python"); | ||
}); | ||
</script> | ||
</head> | ||
<body> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Native console also writes out
KeyboardInterrupt
when you pressCTRL+C
, why not do that here too?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can definitely add that. I had thought about it initially but felt like it was awkward for me just to print that when Python wasn't actually ever seeing the
CTRL+C
. But I think you're right that it would be good to mimic what people see at the normal REPL. I can make that change.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
CTRL+C
handling is actually not really working correctly in my current implementation, unfortunately. Its behavior matches that of the regular REPL if we're dealing with single-line inputs only, but in multiline method, it doesn't match (my implementation results in the code being run instead of ignored). I'd like to actually send aSIGINT
in the case of receiving aCTRL+C
, but I haven't yet figured out how to do that.If I'm not able to find a way to make that actually work the same way the regular REPL does, the question is whether we just accept this limitation and leave it as-is, or remove the
CTRL+C
case entirely.