From aff3fe58889563177f193caab28cb697086d55df Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Fri, 20 Jan 2017 13:56:50 +0100 Subject: [PATCH] refactored the code to connect to a standalone language server process into the commons module --- .../commons-vscode/src/launch-util.ts | 247 ++++++++++-------- .../vscode-boot-java/lib/Main.ts | 46 +--- 2 files changed, 148 insertions(+), 145 deletions(-) diff --git a/vscode-extensions/commons-vscode/src/launch-util.ts b/vscode-extensions/commons-vscode/src/launch-util.ts index 4f83a07db..2632b1306 100644 --- a/vscode-extensions/commons-vscode/src/launch-util.ts +++ b/vscode-extensions/commons-vscode/src/launch-util.ts @@ -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 { - 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 { + 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 { 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(); - handle(params : ProgressParams) { + handle(params: ProgressParams) { let oldMessage = this.status.get(params.id); if (oldMessage) { oldMessage.dispose(); diff --git a/vscode-extensions/vscode-boot-java/lib/Main.ts b/vscode-extensions/vscode-boot-java/lib/Main.ts index 986ef242e..62c553daf 100644 --- a/vscode-extensions/vscode-boot-java/lib/Main.ts +++ b/vscode-extensions/vscode-boot-java/lib/Main.ts @@ -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); }