diff --git a/mlir/utils/vscode/src/configWatcher.ts b/mlir/utils/vscode/src/configWatcher.ts --- a/mlir/utils/vscode/src/configWatcher.ts +++ b/mlir/utils/vscode/src/configWatcher.ts @@ -1,5 +1,4 @@ import * as chokidar from 'chokidar'; -import * as path from 'path'; import * as vscode from 'vscode'; import * as config from './config'; @@ -42,7 +41,8 @@ * Activate the watchers that track configuration changes which decide when to * restart the server. */ -export function activate(mlirContext: MLIRContext) { +export async function activate(mlirContext: MLIRContext, + serverPathsToWatch: string[]) { // When a configuration change happens, check to see if we should restart the // server. mlirContext.subscriptions.push(vscode.workspace.onDidChangeConfiguration(event => { @@ -61,10 +61,7 @@ // Track the server file in case it changes. We use `fs` here because the // server may not be in a workspace directory. - const settings: string[] = [ 'server_path', 'pdll_server_path' ]; - for (const setting of settings) { - const serverPath = config.get(setting); - + for (const serverPath of serverPathsToWatch) { // Check that the path actually exists. if (serverPath === '') { continue; diff --git a/mlir/utils/vscode/src/mlirContext.ts b/mlir/utils/vscode/src/mlirContext.ts --- a/mlir/utils/vscode/src/mlirContext.ts +++ b/mlir/utils/vscode/src/mlirContext.ts @@ -1,4 +1,5 @@ import * as fs from 'fs'; +import * as path from 'path'; import * as vscode from 'vscode'; import * as vscodelc from 'vscode-languageclient'; @@ -20,31 +21,36 @@ async activate(outputChannel: vscode.OutputChannel, warnOnEmptyServerPath: boolean) { // Create the language clients for mlir and pdll. - this.pdllClient = this.startLanguageClient( + let mlirServerPath: string, pdllServerPath: string; + [this.client, mlirServerPath] = await this.startLanguageClient( + outputChannel, warnOnEmptyServerPath, 'server_path', 'mlir'); + [this.pdllClient, pdllServerPath] = await this.startLanguageClient( outputChannel, warnOnEmptyServerPath, 'pdll_server_path', 'pdll'); - this.client = this.startLanguageClient(outputChannel, warnOnEmptyServerPath, - 'server_path', 'mlir'); // Watch for configuration changes. - configWatcher.activate(this); + const serverPathsToWatch = [ mlirServerPath, pdllServerPath ]; + await configWatcher.activate(this, serverPathsToWatch); } /** - * Start a new language client for the given language. + * Start a new language client for the given language. Returns an array + * containing the opened server, or null if the server could not be started, + * and the resolved server path. */ - startLanguageClient(outputChannel: vscode.OutputChannel, - warnOnEmptyServerPath: boolean, serverSettingName: string, - languageName: string): vscodelc.LanguageClient { + async startLanguageClient(outputChannel: vscode.OutputChannel, + warnOnEmptyServerPath: boolean, + serverSettingName: string, languageName: string): + Promise<[ vscodelc.LanguageClient, string ]> { const clientTitle = languageName.toUpperCase() + ' Language Client'; // Get the path of the lsp-server that is used to provide language // functionality. - const serverPath = config.get(serverSettingName); + var serverPath = await this.resolveServerPath(serverSettingName); // If we aren't emitting warnings on an empty server path, and the server // path is empty, bail. if (!warnOnEmptyServerPath && serverPath === '') { - return null; + return [ null, serverPath ]; } // Check that the file actually exists. @@ -61,7 +67,7 @@ {openToSide : false, query : `mlir.${serverSettingName}`}); } }); - return null; + return [ null, serverPath ]; } // Configure the server options. @@ -94,7 +100,53 @@ let languageClient = new vscodelc.LanguageClient( languageName + '-lsp', clientTitle, serverOptions, clientOptions); this.subscriptions.push(languageClient.start()); - return languageClient; + return [ languageClient, serverPath ]; + } + + /** + * Given a server setting, return the default server path. + */ + static getDefaultServerFilename(serverSettingName: string): string { + if (serverSettingName === 'pdll_server_path') { + return 'mlir-pdll-lsp-server'; + } + if (serverSettingName === 'server_path') { + return 'mlir-lsp-server'; + } + return ''; + } + + /** + * Try to resolve the path for the given server setting. + */ + async resolveServerPath(serverSettingName: string): Promise { + let configServerPath = config.get(serverSettingName); + let serverPath = configServerPath; + + // If the path is already fully resolved, there is nothing to do. + if (path.isAbsolute(serverPath)) { + return serverPath; + } + + // If a path hasn't been set, try to use the default path. + if (serverPath === '') { + serverPath = MLIRContext.getDefaultServerFilename(serverSettingName); + if (serverPath === '') { + return serverPath; + } + // Fallthrough to try resolving the default path. + } + + // Try to resolve the path relative to the workspace. + const foundUris: vscode.Uri[] = + await vscode.workspace.findFiles('**/' + serverPath, null, 1); + if (foundUris.length === 0) { + // If we couldn't resolve it, just return the current configuration path + // anyways. The file might not exist yet. + return configServerPath; + } + // Otherwise, return the resolved path. + return foundUris[0].fsPath; } dispose() {