Extract launch code from manifest-yml to commons-vscode
This commit is contained in:
2
vscode-extensions/commons-vscode/.gitignore
vendored
2
vscode-extensions/commons-vscode/.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
coverage/
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
lib/
|
||||
|
||||
|
||||
@@ -1,25 +1,7 @@
|
||||
# Using this module in other modules
|
||||
# commons-vscode
|
||||
|
||||
Here is a quick example of how this module can be used in other modules. The [TypeScript Module Resolution Logic](https://www.typescriptlang.org/docs/handbook/module-resolution.html) makes it quite easy. The file `src/index.ts` acts as an aggregator of all the functionality in this module. It imports from other files and re-exports to provide a unified interface for this module. The _package.json_ file contains `main` attribute that points to the generated `lib/index.js` file and `typings` attribute that points to the generated `lib/index.d.ts` file.
|
||||
A node+typescript module containing some utilites shared between STS4 vscode-extensions.
|
||||
|
||||
> If you are planning to have code in multiple files (which is quite natural for a NodeJS module) that users can import, make sure you update `src/index.ts` file appropriately.
|
||||
Mainly offers utility function(s) to help launch a language-server implemented in
|
||||
Java and then connect to it.
|
||||
|
||||
Now assuming you have published this amazing module to _npm_ with the name `my-amazing-lib`, and installed it in the module in which you need it -
|
||||
|
||||
- To use the `Greeter` class in a TypeScript file -
|
||||
|
||||
```ts
|
||||
import { Greeter } from "my-amazing-lib";
|
||||
|
||||
const greeter = new Greeter("World!");
|
||||
greeter.greet();
|
||||
```
|
||||
|
||||
- To use the `Greeter` class in a JavaScript file -
|
||||
|
||||
```js
|
||||
const Greeter = require('my-amazing-lib').Greeter;
|
||||
|
||||
const greeter = new Greeter('World!');
|
||||
greeter.greet();
|
||||
```
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"repository": "",
|
||||
"author": "Kris De Volder <kdevolder@pivotal.io>",
|
||||
"engines": {
|
||||
"node": ">=4.0.0",
|
||||
"vscode": "^1.5.0"
|
||||
"node": ">=4.0.0",
|
||||
"vscode": "^1.5.0"
|
||||
},
|
||||
"keywords": [
|
||||
""
|
||||
@@ -19,15 +19,17 @@
|
||||
"main": "lib/index.js",
|
||||
"typings": "lib/index.d.ts",
|
||||
"scripts": {
|
||||
"clean": "rm -rf lib node_modules",
|
||||
"compile": "tsc -watch -p ./",
|
||||
"prepublish": "node ./node_modules/vscode/bin/install && tsc -p ./"
|
||||
"clean": "rm -rf lib node_modules",
|
||||
"compile": "tsc -watch -p ./",
|
||||
"prepublish": "node ./node_modules/vscode/bin/install && tsc -p ./"
|
||||
},
|
||||
"dependencies": {
|
||||
"portfinder": "^0.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "2.0.x",
|
||||
"@types/node": "6.0.40",
|
||||
"vscode": "^1.0.0"
|
||||
"vscode": "^1.0.0",
|
||||
"vscode-languageclient": "^2.6.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import {testUtil} from './launch-util';
|
||||
import {activate, ActivatorOptions} from './launch-util';
|
||||
|
||||
export {testUtil};
|
||||
export {activate, ActivatorOptions};
|
||||
|
||||
@@ -1,5 +1,161 @@
|
||||
import * as code from 'vscode';
|
||||
|
||||
export function testUtil() {
|
||||
return 'this is a test';
|
||||
}
|
||||
'use strict';
|
||||
// The module 'vscode' contains the VS Code extensibility API
|
||||
// Import the module and reference it with the alias vscode in your code below
|
||||
|
||||
import * as VSCode from 'vscode';
|
||||
import * as Path from 'path';
|
||||
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} from 'vscode';
|
||||
|
||||
PortFinder.basePort = 45556;
|
||||
|
||||
const DEBUG_ARG = '-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=y';
|
||||
|
||||
export interface ActivatorOptions {
|
||||
DEBUG: 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);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
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);
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Create the language client and start the client.
|
||||
let client = new LanguageClient(options.extensionId, options.extensionId,
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function isJava8(javaExecutablePath: string): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
function correctBinname(binname: string) {
|
||||
if (process.platform === 'win32')
|
||||
return binname + '.exe';
|
||||
else
|
||||
return binname;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"noImplicitAny": true,
|
||||
"target": "es6",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"noImplicitAny": false,
|
||||
"sourceMap": true,
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
"src/**/*",
|
||||
"typings/**.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
||||
@@ -3,17 +3,14 @@
|
||||
// Import the module and reference it with the alias vscode in your code below
|
||||
|
||||
import * as VSCode from 'vscode';
|
||||
import {testUtil} from 'commons-vscode';
|
||||
import * as commons from 'commons-vscode';
|
||||
import * as Path from 'path';
|
||||
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} from 'vscode';
|
||||
|
||||
PortFinder.basePort = 45556;
|
||||
|
||||
var DEBUG = false;
|
||||
const DEBUG_ARG = '-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=y';
|
||||
//If DEBUG is falsy then
|
||||
@@ -38,28 +35,11 @@ function error(msg : string) {
|
||||
|
||||
/** Called when extension is activated */
|
||||
export function activate(context: VSCode.ExtensionContext) {
|
||||
VSCode.window.showInformationMessage(testUtil());
|
||||
VSCode.window.showInformationMessage("Activating manifest.yml extension");
|
||||
log_output = VSCode.window.createOutputChannel("manifest-yml-debug-log");
|
||||
log("Activating manifest.yml extension");
|
||||
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);
|
||||
|
||||
isJava8(javaExecutablePath).then(eight => {
|
||||
if (!eight) {
|
||||
VSCode.window.showErrorMessage('Java language support requires Java 8 (using ' + javaExecutablePath + ')');
|
||||
return;
|
||||
}
|
||||
log("isJavaEight => true");
|
||||
|
||||
// Options to control the language client
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
|
||||
let options : commons.ActivatorOptions = {
|
||||
DEBUG : false,
|
||||
extensionId: 'vscode-manifest-yaml',
|
||||
fatJarFile: 'target/vscode-manifest-yaml-0.0.1-SNAPSHOT.jar',
|
||||
clientOptions: {
|
||||
// HACK!!! documentSelector only takes string|string[] where string is language id, but DocumentFilter object is passed instead
|
||||
// Reasons:
|
||||
// 1. documentSelector is just passed over to functions like #registerHoverProvider(documentSelector, ...) that take documentSelector
|
||||
@@ -70,118 +50,14 @@ export function activate(context: VSCode.ExtensionContext) {
|
||||
// TODO: Remove <any> cast ones https://github.com/Microsoft/vscode-languageserver-node/issues/9 is resolved
|
||||
documentSelector: [ <any> {language: 'yaml', pattern: '**/manifest*.yml'}],
|
||||
synchronize: {
|
||||
// Synchronize the setting section to the server:
|
||||
configurationSection: 'languageServerExample',
|
||||
// Notify the server about file changes to 'javaconfig.json' files contain in the workspace
|
||||
fileEvents: [
|
||||
//What's this for? Don't think it does anything useful for this example:
|
||||
VSCode.workspace.createFileSystemWatcher('**/.clientrc')
|
||||
],
|
||||
|
||||
// TODO: Remove textDocumentFilter property ones https://github.com/Microsoft/vscode-languageserver-node/issues/9 is resolved
|
||||
// TODO: Remove textDocumentFilter property once https://github.com/Microsoft/vscode-languageserver-node/issues/9 is resolved
|
||||
textDocumentFilter: function(textDocument : TextDocument) : boolean {
|
||||
let result : boolean = /^(.*\/)?manifest[^\s\\/]*.yml$/i.test(textDocument.fileName);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 fatJarFile = Path.resolve(context.extensionPath, 'target/vscode-manifest-yaml-0.0.1-SNAPSHOT.jar');
|
||||
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('manifest-yaml-extension', 'manifest-yaml-extension',
|
||||
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);
|
||||
});
|
||||
};
|
||||
commons.activate(options, context);
|
||||
}
|
||||
|
||||
function isJava8(javaExecutablePath: string): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
function correctBinname(binname: string) {
|
||||
if (process.platform === 'win32')
|
||||
return binname + '.exe';
|
||||
else
|
||||
return binname;
|
||||
}
|
||||
|
||||
// this method is called when your extension is deactivated
|
||||
export function deactivate() {
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
"vsce-package": "vsce package"
|
||||
},
|
||||
"dependencies": {
|
||||
"portfinder": "^0.4.0",
|
||||
"vscode-languageclient": "2.5.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Reference in New Issue
Block a user