Skip to content

Commit

Permalink
feat(vscode): multi workspace support & only load au2 extension if pa…
Browse files Browse the repository at this point in the history
…ckage.json contains packages from the scope @aurelia. #106
  • Loading branch information
erik-lieben committed Aug 16, 2019
1 parent 99b90ed commit 2665faf
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 75 deletions.
99 changes: 99 additions & 0 deletions client/src/WorkspaceLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { workspace as Workspace, OutputChannel } from 'vscode';
import { LanguageClient, TransportKind, LanguageClientOptions, ServerOptions, WorkspaceFolder } from 'vscode-languageclient';
import * as path from 'path';
import { asyncForEach } from './util/asyncForEach';
import { clients } from './clients';

/**
* Responsible for creating clients for each separate workspace
*
* @export
* @class WorkspaceLoader
*/
export class WorkspaceLoader {

constructor(private channel: OutputChannel, private serverModule: string) {
}

/**
* Load the initial workspace state and subscribe to changes of the workspace(s).
*
* @memberof WorkspaceLoader
*/
public async load() {

this.channel.appendLine('⚙️ checking workspaces for Aurelia workspaces');
await this.initializeWorkspaces();
this.watchForWorkspaceChanges();
}

private async initializeWorkspaces() {
try {
await asyncForEach(Workspace.workspaceFolders, this.addWorkspaceFolder.bind(this));
} catch(err) {
this.channel.appendLine(err);
}

}

private watchForWorkspaceChanges() {
Workspace.onDidChangeWorkspaceFolders(async (event) => {

if (event.added.length > 0) {
this.channel.appendLine('⚙️ checking newly added workspace(s)');
await asyncForEach(event.added, this.addWorkspaceFolder.bind(this));
}

if (event.removed.length > 0) {
this.channel.appendLine('⚙️ checking removed workspace(s)');
for (let folder of event.removed) {
let client = clients.get(folder.uri.toString());
if (client) {
clients.delete(folder.uri.toString());
client.stop();
this.channel.appendLine('⚰️ client stopped and deleted');
}
}
}

});
}

private async addWorkspaceFolder(folder) {

this.channel.appendLine(" ⚙️ processing workspace: " + folder.uri.toString());

const workspacePath = folder.uri.fsPath;
const packageJsonPath = path.join(workspacePath, 'package.json');
const document = await Workspace.openTextDocument(packageJsonPath);

let packageJson = JSON.parse(document.getText());
let isAureliaProject = false;
for (let npmPackage in packageJson.dependencies) {
if (packageJson.dependencies[npmPackage] && npmPackage.startsWith('@aurelia/')) {
isAureliaProject = true;
break;
}
}
if (!isAureliaProject) {
return;
}
this.channel.appendLine(" 🌱 activating Aurelia2 plugin for workspace: " + folder.uri.toString());
const debugOptions = { execArgv: ["--nolazy", `--inspect=${6011 + clients.size}`] };
const serverOptions: ServerOptions = {
run: { module: this.serverModule, transport: TransportKind.ipc },
debug: { module: this.serverModule, transport: TransportKind.ipc, options: debugOptions }
};
const clientOptions: LanguageClientOptions = {
documentSelector: [
{ scheme: 'file', language: 'plaintext', pattern: `${folder.uri.toString()}/**/*` }
],
diagnosticCollectionName: 'aurelia|' + folder.uri.toString(),
workspaceFolder: folder,
outputChannel: this.channel
};
const client = new LanguageClient('aurelia', serverOptions, clientOptions);
client.start();
clients.set(folder.uri.toString(), client);
}
}
3 changes: 3 additions & 0 deletions client/src/clients.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { LanguageClient } from 'vscode-languageclient';

export const clients: Map<string, LanguageClient> = new Map();
77 changes: 3 additions & 74 deletions client/src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,87 +1,16 @@
import {
workspace as Workspace,
ExtensionContext,
window as Window
} from 'vscode';
import * as path from 'path';
import { WorkspaceLoader } from './WorkspaceLoader';

import {
LanguageClient, TransportKind, LanguageClientOptions, ServerOptions
} from 'vscode-languageclient';

let clients: Map<string, LanguageClient> = new Map();

export function activate(context: ExtensionContext) {
export async function activate(context: ExtensionContext) {

const channel = Window.createOutputChannel('aurelia');
channel.appendLine('checking workspaces for Aurelia workspaces');

workspacePluginLoader(channel, context);

await new WorkspaceLoader(channel, context.asAbsolutePath(path.join('server', 'dist', 'server.js'))).load();
}

export function deactivate(): Thenable<void> {
return Promise.resolve();
}

/**
* Load the plugin for each seperate workspace (Proof of Concept)
*/
function workspacePluginLoader(channel, context) {
const serverModule = context.asAbsolutePath(path.join('server', 'dist', 'server.js'));

// Initial check of workspaces
Workspace.workspaceFolders.forEach(async (folder) => {

channel.appendLine("processing workspace: " + folder.uri.toString());

const workspacePath = folder.uri.fsPath;
const packageJsonPath = path.join(workspacePath, 'package.json');
const document = await Workspace.openTextDocument(packageJsonPath);
let packageJson = JSON.parse(document.getText());

// TODO: figure out if this is the right way to detect it's an Aurelia 2 workspace
if (!packageJson.dependencies.hasOwnProperty('@aurelia/runtime')) {
return;
}

channel.appendLine("activating Aurelia plugin for workspace: " + folder.uri.toString());

const debugOptions = { execArgv: ["--nolazy", `--inspect=${6011 + clients.size}`] };
const serverOptions: ServerOptions = {
run: { module: serverModule, transport: TransportKind.ipc },
debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions}
};
const clientOptions: LanguageClientOptions = {
documentSelector: [
{ scheme: 'file', language: 'plaintext', pattern: `${folder.uri.fsPath}/**/*` }
],
diagnosticCollectionName: 'aurelia|' + workspacePath,
workspaceFolder: folder,
outputChannel: channel
}

const client = new LanguageClient('aurelia', serverOptions, clientOptions);
client.start();
clients.set(workspacePath, client);

});

Workspace.onDidChangeWorkspaceFolders((event) => {

// add client if workspace is added
for (let folder of event.removed) {
channel.appendLine("workspace added :" + folder.uri.fsPath);
}

// remove client when workspace is removed
for (let folder of event.removed) {
let client = clients.get(folder.uri.fsPath);
channel.appendLine("workspace deleted :" + folder.uri.fsPath);
if (client) {
clients.delete(folder.uri.toString());
client.stop();
}
}
});
}
5 changes: 5 additions & 0 deletions client/src/util/asyncForEach.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
2 changes: 1 addition & 1 deletion server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ documents.listen(connection);

connection.onInitialize((params) => {
workspaceFolder = params.rootUri;
connection.console.log(`[Server(${process.pid}) ${workspaceFolder}] Started and initialize received`);
connection.console.log(`🍭 server(${process.pid}) for workspace ${workspaceFolder} started and initialize received`);
return {
capabilities: {
textDocumentSync: {
Expand Down

0 comments on commit 2665faf

Please sign in to comment.