180 lines
4.8 KiB
JavaScript
180 lines
4.8 KiB
JavaScript
const argv = require('yargs').argv;
|
|
const fs = require('fs');
|
|
const path = require("path");
|
|
const {servers} = require("./languageServers");
|
|
const {spawn} = require('child_process');
|
|
const url = require('url');
|
|
const WebSocket = require('ws');
|
|
const verbose = argv.verbose || false;
|
|
|
|
const {
|
|
IPCMessageReader,
|
|
IPCMessageWriter,
|
|
StreamMessageReader,
|
|
StreamMessageWriter
|
|
} = require('vscode-jsonrpc');
|
|
const {
|
|
formatPath,
|
|
makeClientPath,
|
|
makeServerPath
|
|
} = require("./paths-utility");
|
|
|
|
|
|
|
|
const _port = 9999;
|
|
const wss = new WebSocket.Server({port: _port});
|
|
console.log("Started websocket server on port: ", _port);
|
|
|
|
|
|
|
|
wss.on('connection', (ws, req) => {
|
|
const pathname = url.parse(req.url).pathname;
|
|
handleLanguageConnection(ws, pathname.substring(1));
|
|
});
|
|
|
|
|
|
|
|
function handleLanguageConnection(ws, pathname) {
|
|
const server = servers.find(server => server.endpointName === pathname);
|
|
setupLanguageServer(ws, server);
|
|
}
|
|
|
|
function setupLanguageServer(ws, server) {
|
|
if (!server) return;
|
|
|
|
const {
|
|
reader,
|
|
writer
|
|
} = startLanguageServer(server);
|
|
|
|
server.writer = writer;
|
|
|
|
reader.listen(message => {
|
|
if (message.error) {
|
|
console.error(server.nameEndsWith + ":");
|
|
console.error(message.error);
|
|
return;
|
|
}
|
|
|
|
if (verbose) {
|
|
console.log(`From server(${server.endpointName}): `);
|
|
console.log(message);
|
|
}
|
|
|
|
processMessage(message, ws, server);
|
|
});
|
|
|
|
ws.on('message', message => {
|
|
let parsed = JSON.parse(message);
|
|
|
|
if (verbose) {
|
|
console.log("From client: ");
|
|
console.log(parsed);
|
|
}
|
|
|
|
handleMessage(parsed, server);
|
|
});
|
|
}
|
|
|
|
function startLanguageServer(languageServer) {
|
|
let env = process.env;
|
|
const serverProcess = spawn(...languageServer.args, {env, shell: true});
|
|
|
|
serverProcess.stderr.on('data', data => {
|
|
console.error(`${serverProcess.spawnfile} error: ${data}`);
|
|
});
|
|
|
|
serverProcess.on('exit', code => {
|
|
fs.readdirSync("temp").forEach(file => {
|
|
fs.unlinkSync("temp" + path.sep + file);
|
|
});
|
|
|
|
console.log(`${serverProcess.spawnfile} exited with code ${code}`);
|
|
});
|
|
|
|
serverProcess.on('error', err => {
|
|
console.error(`Failed to start ${serverProcess.spawnfile}:`, err);
|
|
});
|
|
|
|
let reader;
|
|
let writer;
|
|
|
|
switch (languageServer.connectionType) {
|
|
case "ipc":
|
|
reader = new IPCMessageReader(serverProcess);
|
|
writer = new IPCMessageWriter(serverProcess);
|
|
|
|
break;
|
|
case "stdio":
|
|
if (serverProcess.stdin !== null && serverProcess.stdout !== null) {
|
|
reader = new StreamMessageReader(serverProcess.stdout);
|
|
writer = new StreamMessageWriter(serverProcess.stdin);
|
|
} else {
|
|
throw 'The language server process does not have a valid stdin or stdout';
|
|
}
|
|
|
|
break;
|
|
default:
|
|
throw 'Unknown connection type...';
|
|
}
|
|
|
|
return {
|
|
reader,
|
|
writer
|
|
};
|
|
}
|
|
|
|
function processMessage(message, ws, server) {
|
|
if (message.params) {
|
|
if (message.params.textDocument && message.params.textDocument.uri) {
|
|
message.params.textDocument.uri = makeClientPath(
|
|
message.params.textDocument.uri,
|
|
server.clientFileNameReplacePattern
|
|
);
|
|
} else if (message.params.uri) {
|
|
message.params.uri = makeClientPath(
|
|
message.params.uri,
|
|
server.clientFileNameReplacePattern
|
|
);
|
|
}
|
|
}
|
|
|
|
ws.send(JSON.stringify(message));
|
|
}
|
|
|
|
function handleMessage(parsed, server) {
|
|
if (parsed.method) {
|
|
switch (parsed.method) {
|
|
case "initialize":
|
|
let rootUri = formatPath(__dirname + path.sep + "temp");
|
|
|
|
if (!parsed.params || (!parsed.params.rootUri && !parsed.params.rootPath && !parsed.params.workspaceFolders)) {
|
|
if (!fs.existsSync("temp")) {
|
|
fs.mkdirSync("temp");
|
|
}
|
|
parsed.params.rootUri = rootUri;
|
|
parsed.params.rootPath = __dirname + path.sep + "temp";
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (parsed.params && parsed.params.textDocument && parsed.params.textDocument.uri) {
|
|
parsed.params.textDocument.uri = makeServerPath(
|
|
parsed.params.textDocument.uri,
|
|
server.serverFileNameReplacePattern
|
|
);
|
|
|
|
if (server && server.relativePath) {
|
|
parsed.params.textDocument.uri = parsed.params.textDocument.uri.replace(__dirname + path.sep, "");
|
|
}
|
|
}
|
|
|
|
const writer = server?.writer;
|
|
if (writer) {
|
|
writer.write(parsed);
|
|
}
|
|
}
|