I am trying to build an extension for the Brackets editor which is a Node.js REPL, similar to the SublimeREPL extension for Sublime Text.
I understand from the docs that I need to implement the REPL as a NodeDomain to make it accessible to Brackets and I used the example extension as a base for mine.
Unfortunately, when I send some Javascript code to the REPL it is not evaluated and only the prompt text I set is returned.
My idea for the setup of the extension is as follows:
However, the result only contains the prompt text and not the evaluated code.
Here's the code for the NodeDomain:
ReplDomain.js
(function () {
"use strict";
var net = require('net');
var Readable = require('stream').Readable;
var Writable = require('stream').Writable;
var repl = require("repl");
// inputstream for REPL, input code will be pushed into this stream from Brackets
var ReplInput = new Readable();
ReplInput._read = function noop() {};
// outputstream for REPL, any output will be pushed into the CallbackInput stream so when the 'data' event is emitted
// the 'done()' callback in cmdExecRepl will be called with the REPL output and retured to Brackets
var ReplOutput = new Writable();
ReplOutput._write = function noop(data, enc, next) {
CallbackInput.push(data);
CallbackInput.push(null);
next();
};
var CallbackInput = new Readable();
CallbackInput._read = function noop() {};
//setup REPL
var r = repl.start({
prompt: 'node repl> ',
input: ReplInput,
output: ReplOutput,
terminal: false,
useGlobal: false
});
/**
* Handler function for the repl.execRepl command.
*
*/
function cmdExecRepl(code, done) {
// code from Brackets is pushed into the ReplInput readable stream and so put into the REPL
ReplInput.push(code);
ReplInput.push(null);
// the output from the REPL is pushed into the CallbackInput readable stream so we can detect the
// 'data' event and return the evaluated code to Brackets
CallbackInput.on('data', function(data) {
console.log('evaluated code:', data.toString('binary'));
// data contains just the prompt, but NOT the evaluated code
done(null, data.toString('binary'));
});
}
/**
* Initializes the domain
*/
function init(domainManager) {
if (!domainManager.hasDomain("customRepl")) {
domainManager.registerDomain("customRepl");
}
domainManager.registerCommand(
"customRepl", // domain name
"doRepl", // command name
cmdExecRepl, // command handler function
true // this command is synchronous in Node
);
}
exports.init = init;
}());
I wrote a test script that simply logs the REPL output to the console to verify this setup and it seems to work. This is my test script:
repl-test.js
"use strict";
var Readable = require('stream').Readable;
var Writable = require('stream').Writable;
var repl = require("repl");
var fs = require('fs');
// inputstream for REPL, input code will be pushed into this stream
var ReplInput = new Readable();
ReplInput._read = function noop() {};
// outputstream for REPL, any output will be pushed into the CallbackInput stream so we can detect the 'data'
// event and get the data
var ReplOutput = new Writable();
ReplOutput._write = function (data, enc, next) {
CallbackInput.push(data);
// when I add the line below I only get the prompt text back
// CallbackInput.push(null);
next();
};
var CallbackInput = new Readable();
CallbackInput._read = function noop() {};
// THIS WORKS: I get the actual REPL output here
CallbackInput.on('data', function(data) {
console.log('output from REPL:', data.toString());
});
// start the REPL
var r = repl.start({
prompt: 'node repl> ',
input: ReplInput,
output: ReplOutput,
terminal: false
});
// feed the REPL some code to evaluate
var code = '[1,2,3].join(" ")';
ReplInput.push(code);
ReplInput.push(null);
Output of this script:
output from REPL: node repl>
output from REPL: '1 2 3'
output from REPL: node repl>
Note that the script outputs the prompt text as the last line. I suspect that this is the only line that is returned to Brackets so that would explain why I only get the prompt back, I just don't know why this is the case.
At first I had the line:
CallbackInput.push(null);
in ReplOutput._write and that also caused the output of the REPL to only return the prompt text, but when I remove that same line from ReplDomain.js it does not help.
Another thing I tried is to set the "terminal" option of the REPL to true which causes the 'data' event on CallbackInput to be emitted for every single character, but that also doesn't change what is sent back to Brackets.
Perhaps I'm not using streams the right way but so far I cannot find what is going wrong here.
Any help is greatly appreciated!