Skip to content

Commit 3aeea2f

Browse files
committed
Fix results different with REPL outputs;
Remove useless operations.
1 parent d5778d9 commit 3aeea2f

File tree

4 files changed

+71
-130
lines changed

4 files changed

+71
-130
lines changed

src/code.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ export function rewriteModulePathInRequire(code: string, basePath: string, fileP
3838

3939

4040
const lineBreak = /\r?\n/;
41-
const consoleLogCall = /console\s*\.(log|debug|error)\(/g;
41+
const consoleLogCall = /console\s*\.(debug|error|info|log|warn)\(/g;
4242

4343
export function rewriteConsoleToAppendLineNumber(code: string): string {
4444
let num = 0,
4545
out = [];
4646

4747
for (let line of code.split(lineBreak)) {
48-
out.push(line.replace(consoleLogCall, `global['\`console\`'].$1(${num++}, `));
48+
out.push(line.replace(consoleLogCall, (str, method) => `global['\`console\`'].${method}(${num}, `));
49+
num++;
4950
}
5051

5152
return out.join('\n');

src/decorator.ts

Lines changed: 42 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import {
99
window,
1010
} from "vscode";
1111

12-
import * as Util from 'util';
13-
1412

1513
// create a decorator type that we use to decorate small numbers
1614
const resultDecorationType = window.createTextEditorDecorationType({
@@ -23,10 +21,7 @@ const colorOfType = {
2321
'Console': '#457abb',
2422
'Error': 'red',
2523
}
26-
// TODO: if Node's Version of VSCode >=9.9, use default option
27-
const inspectOptions: NodeJS.InspectOptions = { depth: 20 };
28-
29-
type Data = { line: number, type: 'Expression' | 'Terminal', value: any };
24+
type Data = { line: number, value: string };
3025
type Result = { line: number, type: 'Value of Expression' | 'Console' | 'Error', text: string, value: string };
3126

3227
export default class Decorator {
@@ -45,19 +40,48 @@ export default class Decorator {
4540
}
4641

4742
async update(data: Data) {
43+
if (!data) return;
44+
45+
let result = this.format(data);
46+
47+
this.outputChannel.appendLine(` ${result.value}`);
48+
49+
if (result.type === 'Console') {
50+
result = this.mergeConsoleOutput(result);
51+
}
52+
this.updateWith(result);
53+
this.decorateAll();
54+
}
55+
private format({ line, value }: Data): Result {
56+
let match: RegExpExecArray;
4857

49-
let result = (data.type === 'Expression')
50-
? await this.formatExpressionValue(data)
51-
: this.formatTerminalOutput(data);
58+
if ((match = /((\w*Error(?:\s\[[^\]]+\])?:\s.*)(?:\n\s*at\s[\s\S]+)?)$/.exec(value)) != null) {
59+
return { line, type: 'Error', text: match[1], value: match[2] };
60+
}
61+
else if ((match = /^`\{(\d+)\}`([\s\S]*)$/.exec(value)) != null) {
62+
let value = match[2] || '';
63+
return { line: +match[1], type: 'Console', text: value.replace(/\r?\n/g, ' '), value };
64+
}
65+
else {
66+
return { line, type: 'Value of Expression', text: value.replace(/\r?\n/g, ' '), value };
67+
}
68+
}
69+
private mergeConsoleOutput({ line, text, value }: Result) {
70+
let output = this.lineToOutput.get(line);
71+
if (output == null) {
72+
this.lineToOutput.set(line, output = { line, type: 'Console', text: '', value: '' });
73+
}
5274

53-
if (!result) return;
75+
output.text += (output.text && ', ') + text;
76+
output.value += (output.value && '\n') + value;
5477

78+
return output;
79+
}
80+
private updateWith({ line, type, text, value }: Result) {
5581
let decorator: DecorationOptions;
5682

57-
if ((decorator = this.lineToDecorator.get(result.line)) == null) {
58-
let line = result.line,
59-
length = this.editor.document.getText(new Range(new Position(line, 0), new Position(line, 37768))).length + 1,
60-
pos = new Position(line, length);
83+
if ((decorator = this.lineToDecorator.get(line)) == null) {
84+
let pos = new Position(line, Number.MAX_SAFE_INTEGER);
6185

6286
decorator = {
6387
renderOptions: { before: { margin: '0 0 0 1em' } },
@@ -67,79 +91,11 @@ export default class Decorator {
6791
this.decorators.push(decorator);
6892
}
6993

70-
decorator.renderOptions.before.color = colorOfType[result.type];
71-
decorator.renderOptions.before.contentText = ` ${result.text}`;
94+
decorator.renderOptions.before.color = colorOfType[type];
95+
decorator.renderOptions.before.contentText = ` ${text}`;
7296

73-
decorator.hoverMessage = new MarkdownString(result.type);
74-
decorator.hoverMessage.appendCodeblock(result.value, result.type === 'Error' ? 'text' : 'javascript');
75-
76-
this.decorateAll();
77-
}
78-
private async formatExpressionValue(data: Data): Promise<Result> {
79-
let result = data.value;
80-
switch (typeof result) {
81-
case 'undefined':
82-
return null;
83-
84-
case 'object':
85-
if (result.constructor && result.constructor.name === 'Promise' && result.then) {
86-
try {
87-
data.value = await (<Promise<any>>result);
88-
return data.value ? this.formatExpressionValue(data) : null;
89-
} catch (error) {
90-
return {
91-
line: data.line,
92-
type: 'Error',
93-
text: `${error.name}: ${error.message}`,
94-
value: error.stack,
95-
}
96-
}
97-
}
98-
99-
let string = Util.inspect(result, inspectOptions);
100-
return {
101-
line: data.line,
102-
type: 'Value of Expression',
103-
text: string.replace(/\n/g, ' '),
104-
value: string,
105-
}
106-
107-
default:
108-
return {
109-
line: data.line,
110-
type: 'Value of Expression',
111-
text: result.toString().replace(/\r?\n/g, ' '),
112-
value: result,
113-
}
114-
}
115-
}
116-
private formatTerminalOutput(data: Data): Result {
117-
let out = data.value as string;
118-
let match: RegExpExecArray;
119-
120-
if ((match = /^(\w*Error(?: \[[^\]]+\])?:\s.*)(?:\n\s*at\s)?/.exec(out)) != null) {
121-
this.outputChannel.appendLine(` ${out}`);
122-
123-
return { line: data.line, type: 'Error', text: match[1], value: out };
124-
}
125-
else if ((match = /^`\{(\d+)\}`([\s\S]*)$/.exec(out)) != null) {
126-
let line = +match[1];
127-
let msg = match[2] || '';
128-
129-
let output = this.lineToOutput.get(line);
130-
if (output == null) {
131-
this.lineToOutput.set(line, output = { line, type: 'Console', text: '', value: '' });
132-
}
133-
134-
output.text += (output.text && ', ') + msg.replace(/\r?\n/g, ' ');
135-
output.value += (output.value && '\n') + msg;
136-
137-
this.outputChannel.appendLine(` ${msg}`);
138-
return output;
139-
}
140-
else {
141-
this.outputChannel.appendLine(` ${out}`);
142-
}
97+
decorator.hoverMessage = new MarkdownString(type)
98+
.appendCodeblock(value, type === 'Error' ? 'text' : 'javascript');
14399
}
144100

145101
decorateAll() {

src/repl-client.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,11 @@ export default class ReplClient {
138138
}
139139

140140
dispose() {
141+
if (!this.isClosed) this.close();
142+
141143
this.changeActiveDisposable.dispose();
142144
this.closeTextDocumentDisposable.dispose();
143145
this.changeEventDisposable.dispose();
144146
this.editor = null;
145-
146-
this.repl.send({ operation: 'exit' });
147-
this.repl = null;
148147
}
149148
}

src/repl-server.ts

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import * as Util from 'util';
33
import { Writable, Readable } from 'stream';
44

55

6-
type ReplServer = Repl.REPLServer & { inputStream: Readable, eval: ReplEval };
7-
type ReplEval = (cmd: string, context: any, filename: string, cb: (err?: Error, result?: any) => void) => void;
6+
type ReplServer = Repl.REPLServer & { inputStream: Readable };
87

98
let lineCount = 0;
109

@@ -13,63 +12,49 @@ const server = Repl.start({
1312
input: new Readable({ read: () => { } }),
1413
output: new Writable({
1514
write: (chunk, encoding, callback) => {
16-
let out = chunk.toString().trim();
17-
switch (out) {
18-
case '...': break;
19-
case '': break;
20-
default:
21-
process.send({ line: lineCount, type: 'Terminal', value: out });
22-
break;
23-
}
15+
let value = chunk.toString().trim();
16+
17+
if (value !== '' && /^\.{3,}$/.test(value) === false)
18+
process.send({ line: lineCount, value });
19+
2420
callback();
2521
}
2622
}),
2723
ignoreUndefined: true,
2824

2925
}) as ReplServer;
3026

31-
32-
const originEval = server.eval; // keep a backup of original eval
33-
const lineNumber = /\/\*`(\d+)`\*\//g;
34-
35-
// nice place to read the result in sequence and inject it in the code
36-
server.eval = (cmd, context, filename, callback) => {
37-
originEval(cmd, context, filename, (err, result) => {
38-
let match: RegExpExecArray;
39-
40-
while ((match = lineNumber.exec(cmd)) != null)
41-
lineCount += +match[1];
42-
43-
if (result)
44-
process.send({ line: lineCount, type: 'Expression', value: result });
45-
46-
callback(err, result);
47-
});
48-
49-
lineCount++;
50-
}
51-
5227
const originLog = server.context.console.log;
5328
const appendLineLog = (lineNumber: number, text: any, ...args: any[]) => {
5429
originLog(`\`{${lineNumber}}\`${typeof text === 'string' ? text : Util.inspect(text)}`, ...args);
5530
}
5631
Object.defineProperty(server.context, '`console`', {
5732
value: {
58-
log: appendLineLog,
5933
debug: appendLineLog,
6034
error: appendLineLog,
35+
info: appendLineLog,
36+
log: appendLineLog,
37+
warn: appendLineLog,
6138
}
6239
});
6340

41+
const lineNumber = /\/\*`(\d+)`\*\//g;
42+
6443
process.on('message', data => {
65-
if (data.code) {
66-
try {
67-
for (let line of data.code.split('\n'))
68-
server.inputStream.push(line + '\n');
69-
} catch (error) {
70-
process.emit('error', error);
44+
45+
if (typeof data.code === 'string') {
46+
for (let codeLine of data.code.split('\n')) {
47+
let match: RegExpExecArray;
48+
49+
while ((match = lineNumber.exec(codeLine)) != null)
50+
lineCount += +match[1];
51+
52+
server.inputStream.push(codeLine + '\n');
53+
54+
lineCount++;
7155
}
72-
} else if (data.operation === 'exit') {
56+
}
57+
else if (data.operation === 'exit') {
7358
process.exit();
7459
}
7560
});

0 commit comments

Comments
 (0)