refactored the code to connect to a standalone language server process into the commons module
This commit is contained in:
@@ -10,8 +10,9 @@ import * as FS from 'fs';
|
||||
import PortFinder = require('portfinder');
|
||||
import * as Net from 'net';
|
||||
import * as ChildProcess from 'child_process';
|
||||
import {LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, StreamInfo} from 'vscode-languageclient';
|
||||
import {TextDocument, OutputChannel, Disposable, window} from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, StreamInfo } from 'vscode-languageclient';
|
||||
import { TextDocument, OutputChannel, Disposable, window } from 'vscode';
|
||||
import { Trace } from 'vscode-jsonrpc';
|
||||
|
||||
PortFinder.basePort = 45556;
|
||||
|
||||
@@ -19,148 +20,178 @@ const DEBUG_ARG = '-agentlib:jdwp=transport=dt_socket,server=y,address=8000,susp
|
||||
|
||||
export interface ActivatorOptions {
|
||||
DEBUG: boolean;
|
||||
extensionId : string;
|
||||
clientOptions : LanguageClientOptions;
|
||||
CONNECT_TO_LS: boolean;
|
||||
extensionId: string;
|
||||
clientOptions: LanguageClientOptions;
|
||||
fatJarFile: string;
|
||||
}
|
||||
|
||||
|
||||
export function activate(options : ActivatorOptions, context: VSCode.ExtensionContext) {
|
||||
//unpack options object
|
||||
let DEBUG = options.DEBUG;
|
||||
let clientOptions = options.clientOptions;
|
||||
let fatJarFile = Path.resolve(context.extensionPath, options.fatJarFile);
|
||||
export function activate(options: ActivatorOptions, context: VSCode.ExtensionContext) {
|
||||
|
||||
var log_output = VSCode.window.createOutputChannel(options.extensionId+"-debug-log");
|
||||
log("Activating '"+options.extensionId+"' extension");
|
||||
let CONNECT_TO_LS = options.CONNECT_TO_LS;
|
||||
if (CONNECT_TO_LS) {
|
||||
connectToLS(options.extensionId, context, options.clientOptions);
|
||||
}
|
||||
else {
|
||||
let DEBUG = options.DEBUG;
|
||||
let clientOptions = options.clientOptions;
|
||||
let fatJarFile = Path.resolve(context.extensionPath, options.fatJarFile);
|
||||
|
||||
function log(msg : string) {
|
||||
if (log_output) {
|
||||
log_output.append(msg +"\n");
|
||||
var log_output = VSCode.window.createOutputChannel(options.extensionId + "-debug-log");
|
||||
log("Activating '" + options.extensionId + "' extension");
|
||||
|
||||
function log(msg: string) {
|
||||
if (log_output) {
|
||||
log_output.append(msg + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function error(msg : string) {
|
||||
if (log_output) {
|
||||
log_output.append("ERR: "+msg+"\n");
|
||||
function error(msg: string) {
|
||||
if (log_output) {
|
||||
log_output.append("ERR: " + msg + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let javaExecutablePath = findJavaExecutable('java');
|
||||
|
||||
if (javaExecutablePath == null) {
|
||||
VSCode.window.showErrorMessage("Couldn't locate java in $JAVA_HOME or $PATH");
|
||||
return;
|
||||
}
|
||||
log("Found java exe: "+javaExecutablePath);
|
||||
let javaExecutablePath = findJavaExecutable('java');
|
||||
|
||||
|
||||
isJava8(javaExecutablePath).then(eight => {
|
||||
if (!eight) {
|
||||
VSCode.window.showErrorMessage('Java-based Language Server requires Java 8 (using ' + javaExecutablePath + ')');
|
||||
if (javaExecutablePath == null) {
|
||||
VSCode.window.showErrorMessage("Couldn't locate java in $JAVA_HOME or $PATH");
|
||||
return;
|
||||
}
|
||||
log("isJavaEight => true");
|
||||
|
||||
function createServer(): Promise<StreamInfo> {
|
||||
return new Promise((resolve, reject) => {
|
||||
PortFinder.getPort((err, port) => {
|
||||
Net.createServer(socket => {
|
||||
log('Child process connected on port ' + port);
|
||||
log("Found java exe: " + javaExecutablePath);
|
||||
|
||||
resolve({
|
||||
reader: socket,
|
||||
writer: socket
|
||||
|
||||
isJava8(javaExecutablePath).then(eight => {
|
||||
if (!eight) {
|
||||
VSCode.window.showErrorMessage('Java-based Language Server requires Java 8 (using ' + javaExecutablePath + ')');
|
||||
return;
|
||||
}
|
||||
log("isJavaEight => true");
|
||||
|
||||
function createServer(): Promise<StreamInfo> {
|
||||
return new Promise((resolve, reject) => {
|
||||
PortFinder.getPort((err, port) => {
|
||||
Net.createServer(socket => {
|
||||
log('Child process connected on port ' + port);
|
||||
|
||||
resolve({
|
||||
reader: socket,
|
||||
writer: socket
|
||||
});
|
||||
}).listen(port, () => {
|
||||
let options = {
|
||||
cwd: VSCode.workspace.rootPath
|
||||
};
|
||||
let child: ChildProcess.ChildProcess;
|
||||
let args = [
|
||||
'-Dserver.port=' + port,
|
||||
'-jar',
|
||||
fatJarFile,
|
||||
];
|
||||
if (DEBUG) {
|
||||
args.unshift(DEBUG_ARG);
|
||||
}
|
||||
log("CMD = " + javaExecutablePath + ' ' + args.join(' '));
|
||||
|
||||
// Start the child java process
|
||||
child = ChildProcess.execFile(javaExecutablePath, args, options);
|
||||
child.stdout.on('data', (data) => {
|
||||
log("" + data);
|
||||
});
|
||||
child.stderr.on('data', (data) => {
|
||||
error("" + data);
|
||||
})
|
||||
});
|
||||
}).listen(port, () => {
|
||||
let options = {
|
||||
cwd: VSCode.workspace.rootPath
|
||||
};
|
||||
let child: ChildProcess.ChildProcess;
|
||||
let args = [
|
||||
'-Dserver.port=' + port,
|
||||
'-jar',
|
||||
fatJarFile,
|
||||
];
|
||||
if (DEBUG) {
|
||||
args.unshift(DEBUG_ARG);
|
||||
}
|
||||
log("CMD = "+javaExecutablePath + ' ' + args.join(' '));
|
||||
|
||||
// Start the child java process
|
||||
child = ChildProcess.execFile(javaExecutablePath, args, options);
|
||||
child.stdout.on('data', (data) => {
|
||||
log(""+data);
|
||||
});
|
||||
child.stderr.on('data', (data) => {
|
||||
error(""+data);
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Create the language client and start the client.
|
||||
let client = new LanguageClient(options.extensionId, options.extensionId,
|
||||
createServer, clientOptions
|
||||
);
|
||||
let progressService = new ProgressService();
|
||||
client.onNotification({method: "sts/progress"}, (params : ProgressParams) => {
|
||||
progressService.handle(params);
|
||||
setupLanguageClient(options.extensionId, context, createServer, clientOptions);
|
||||
});
|
||||
let disposable = client.start();
|
||||
}
|
||||
}
|
||||
|
||||
// Push the disposable to the context's subscriptions so that the
|
||||
// client can be deactivated on extension deactivation
|
||||
context.subscriptions.push(disposable);
|
||||
context.subscriptions.push(progressService);
|
||||
function connectToLS(extensionId: string, context: VSCode.ExtensionContext, clientOptions: LanguageClientOptions) {
|
||||
let connectionInfo = {
|
||||
port: 5007
|
||||
};
|
||||
|
||||
let serverOptions = () => {
|
||||
let socket = Net.connect(connectionInfo);
|
||||
let result: StreamInfo = {
|
||||
writer: socket,
|
||||
reader: socket
|
||||
};
|
||||
return Promise.resolve(result);
|
||||
};
|
||||
|
||||
setupLanguageClient(extensionId, context, serverOptions, clientOptions);
|
||||
}
|
||||
|
||||
function setupLanguageClient(extensionId: string, context: VSCode.ExtensionContext, createServer: ServerOptions, clientOptions: LanguageClientOptions) {
|
||||
// Create the language client and start the client.
|
||||
let client = new LanguageClient(extensionId, extensionId,
|
||||
createServer, clientOptions
|
||||
);
|
||||
client.trace = Trace.Verbose;
|
||||
|
||||
let progressService = new ProgressService();
|
||||
client.onNotification({ method: "sts/progress" }, (params: ProgressParams) => {
|
||||
progressService.handle(params);
|
||||
});
|
||||
let disposable = client.start();
|
||||
|
||||
// Push the disposable to the context's subscriptions so that the
|
||||
// client can be deactivated on extension deactivation
|
||||
context.subscriptions.push(disposable);
|
||||
context.subscriptions.push(progressService);
|
||||
}
|
||||
|
||||
|
||||
function isJava8(javaExecutablePath: string): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let result = ChildProcess.execFile(javaExecutablePath, ['-version'], { }, (error, stdout, stderr) => {
|
||||
let result = ChildProcess.execFile(javaExecutablePath, ['-version'], {}, (error, stdout, stderr) => {
|
||||
let eight = stderr.indexOf('1.8') >= 0;
|
||||
resolve(eight);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function findJavaExecutable(binname: string) {
|
||||
binname = correctBinname(binname);
|
||||
binname = correctBinname(binname);
|
||||
|
||||
// First search each JAVA_HOME bin folder
|
||||
if (process.env['JAVA_HOME']) {
|
||||
let workspaces = process.env['JAVA_HOME'].split(Path.delimiter);
|
||||
for (let i = 0; i < workspaces.length; i++) {
|
||||
let binpath = Path.join(workspaces[i], 'bin', binname);
|
||||
if (FS.existsSync(binpath)) {
|
||||
return binpath;
|
||||
}
|
||||
}
|
||||
}
|
||||
// First search each JAVA_HOME bin folder
|
||||
if (process.env['JAVA_HOME']) {
|
||||
let workspaces = process.env['JAVA_HOME'].split(Path.delimiter);
|
||||
for (let i = 0; i < workspaces.length; i++) {
|
||||
let binpath = Path.join(workspaces[i], 'bin', binname);
|
||||
if (FS.existsSync(binpath)) {
|
||||
return binpath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then search PATH parts
|
||||
if (process.env['PATH']) {
|
||||
let pathparts = process.env['PATH'].split(Path.delimiter);
|
||||
for (let i = 0; i < pathparts.length; i++) {
|
||||
let binpath = Path.join(pathparts[i], binname);
|
||||
if (FS.existsSync(binpath)) {
|
||||
return binpath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Else return the binary name directly (this will likely always fail downstream)
|
||||
return null;
|
||||
// Then search PATH parts
|
||||
if (process.env['PATH']) {
|
||||
let pathparts = process.env['PATH'].split(Path.delimiter);
|
||||
for (let i = 0; i < pathparts.length; i++) {
|
||||
let binpath = Path.join(pathparts[i], binname);
|
||||
if (FS.existsSync(binpath)) {
|
||||
return binpath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Else return the binary name directly (this will likely always fail downstream)
|
||||
return null;
|
||||
}
|
||||
|
||||
function correctBinname(binname: string) {
|
||||
if (process.platform === 'win32')
|
||||
return binname + '.exe';
|
||||
else
|
||||
return binname;
|
||||
if (process.platform === 'win32')
|
||||
return binname + '.exe';
|
||||
else
|
||||
return binname;
|
||||
}
|
||||
|
||||
interface ProgressParams {
|
||||
@@ -172,7 +203,7 @@ class ProgressService {
|
||||
|
||||
private status = new Map<String, Disposable>();
|
||||
|
||||
handle(params : ProgressParams) {
|
||||
handle(params: ProgressParams) {
|
||||
let oldMessage = this.status.get(params.id);
|
||||
if (oldMessage) {
|
||||
oldMessage.dispose();
|
||||
|
||||
@@ -17,45 +17,17 @@ import * as commons from 'commons-vscode';
|
||||
|
||||
export function activate(context: VSCode.ExtensionContext) {
|
||||
|
||||
let CONNECT_TO_LS = false;
|
||||
|
||||
if (CONNECT_TO_LS) {
|
||||
let connectionInfo = {
|
||||
port: 5007
|
||||
};
|
||||
let serverOptions = () => {
|
||||
let socket = net.connect(connectionInfo);
|
||||
let result: StreamInfo = {
|
||||
writer: socket,
|
||||
reader: socket
|
||||
};
|
||||
return Promise.resolve(result);
|
||||
};
|
||||
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
let options: commons.ActivatorOptions = {
|
||||
DEBUG: false,
|
||||
CONNECT_TO_LS: true,
|
||||
extensionId: 'vscode-boot-java',
|
||||
fatJarFile: 'target/vscode-boot-java-0.0.1-SNAPSHOT.jar',
|
||||
clientOptions: {
|
||||
documentSelector: ['java'],
|
||||
synchronize: {
|
||||
configurationSection: 'vscode-boot-java'
|
||||
}
|
||||
};
|
||||
|
||||
let lc = new LanguageClient('vscode-boot-java', serverOptions, clientOptions);
|
||||
lc.trace = Trace.Verbose;
|
||||
let disposable = lc.start();
|
||||
context.subscriptions.push(disposable);
|
||||
}
|
||||
else {
|
||||
let options: commons.ActivatorOptions = {
|
||||
DEBUG: false,
|
||||
extensionId: 'vscode-boot-java',
|
||||
fatJarFile: 'target/vscode-boot-java-0.0.1-SNAPSHOT.jar',
|
||||
clientOptions: {
|
||||
documentSelector: ['java'],
|
||||
synchronize: {
|
||||
configurationSection: 'vscode-boot-java'
|
||||
}
|
||||
}
|
||||
};
|
||||
commons.activate(options, context);
|
||||
}
|
||||
}
|
||||
};
|
||||
commons.activate(options, context);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user