-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdrepl-node.js
91 lines (81 loc) · 2.45 KB
/
drepl-node.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
const repl = require('node:repl');
const vm = require('vm')
let nextREPLResourceNumber = 1;
// This prevents v8 code cache from getting confused and using a different
// cache from a resource of the same name
function getREPLResourceName() {
return `dREPL${nextREPLResourceNumber++}`;
}
class dREPL extends repl.REPLServer {
constructor(options) {
console.log(`Welcome to Node.js ${process.version}.`)
options = { terminal: false, ...options }
super(options)
this.removeAllListeners("line")
this.on("line", this.onLine.bind(this, []))
this.sendMsg({ op: "status", status: "ready" })
}
sendMsg(data) {
const s = JSON.stringify(data)
this.output.write(`\x1b]5161;${s}\x1b\\`)
}
sendLog(obj) {
const text = this.writer(obj)
this.sendMsg({ op: "log", text })
}
ops = Object.assign(Object.create(null), {
complete: (msg) => {
const { id, code, pos } = msg
const cb = (err, data) => {
if (err) { this.sendLog(this.writer(err)) }
const [items, prefix] = data
const candidates = items.filter(Boolean)
this.sendMsg({ id, prefix, candidates })
}
// FIXME: UTF-16 nonsense
this.complete(code.slice(0, pos), cb)
},
eval: (msg) => {
const { id, code } = msg
let cb = (err, result) => {
if (err) { this.sendLog(err) }
this.output.write(this.writer(result))
this.output.write("\n" + this.getPrompt())
}
this.eval(code, this.context, getREPLResourceName(), cb)
this.sendMsg({ id })
},
checkinput: (msg) => {
const { id, code } = msg
try {
new vm.Script(code)
this.sendMsg({ id, status: "complete" })
} catch (e) {
let status = e.message.startsWith("Unexpected end of input")
? "incomplete" : "invalid"
this.sendMsg({ id, status, prompt: "... " })
}
},
default: (msg) => {
const { id } = msg
if (id) { this.sendMsg({ id }) }
}
})
onLine(buffer, line) {
if (line.startsWith("\x1b+")) {
buffer.push(line.slice(2))
return
}
if (line.startsWith("\x1b=")) {
buffer.push(line.slice(2))
const msg = JSON.parse(buffer.join(""))
buffer.length = 0
const f = this.ops[msg.op] || this.ops.default
f(msg)
this.sendMsg({ op: "status", status: "ready" })
return
}
this.sendLog("Invalid message: " + JSON.stringify(line))
}
}
repl.repl = new dREPL({ useColors: true })