From 1e2e04c61f12adfa9092f5885331a51f6d6bcdd1 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Wed, 7 Aug 2019 02:13:01 +0200 Subject: [PATCH 01/10] reintroduce multi project setup * enable multiple projects with multiple rls running * change the URI key back to string for workspaces (as it's unreliable) * add selectors such that only the correct rls is used for a given project * take great care to ensure the old setup works normally * add a configuration and turn it off by default. --- package.json | 5 ++ src/configuration.ts | 4 ++ src/extension.ts | 139 +++++++++++++++++++++++++++---------------- 3 files changed, 97 insertions(+), 51 deletions(-) diff --git a/package.json b/package.json index 91603fbb..57695597 100644 --- a/package.json +++ b/package.json @@ -219,6 +219,11 @@ "default": true, "description": "If one root workspace folder is nested in another root folder, look for the Rust config in the outermost root." }, + "rust-client.enableMultiProjectSetup": { + "type": "boolean", + "default": false, + "description": "Allow multiple projects in the same folder, along with remove the constraint that the cargo.toml must be located at the root. (Experimental: might not work for certain setups)" + }, "rust.sysroot": { "type": [ "string", diff --git a/src/configuration.ts b/src/configuration.ts index 641e9a35..8f1e03b9 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -118,6 +118,10 @@ export class RLSConfiguration { return this.configuration.get('rust-client.rlsPath'); } + public get multiProjectEnabled(): boolean { + return this.configuration.get('rust-client.enableMultiProjectSetup', false); + } + // Added ignoreChannel for readChannel function. Otherwise we end in an infinite loop. public rustupConfig(ignoreChannel: boolean = false): RustupConfig { return { diff --git a/src/extension.ts b/src/extension.ts index 983ecd51..e251f4b2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -69,23 +69,37 @@ function didOpenTextDocument( if (!folder) { return; } + if ( + workspace + .getConfiguration() + .get('rust-client.enableMultiProjectSetup', false) + ) { + folder = getCargoTomlWorkspace(folder, document.uri.fsPath); + } else if ( workspace .getConfiguration() .get('rust-client.nestedMultiRootConfigInOutermost', true) ) { folder = getOuterMostWorkspaceFolder(folder); } - // folder = getCargoTomlWorkspace(folder, document.uri.fsPath); + if (!folder) { stopSpinner(`RLS: Cargo.toml missing`); return; } - if (!workspaces.has(folder.uri)) { + const folderPath = folder.uri.toString(); + + if (!workspaces.has(folderPath)) { + const workspace = new ClientWorkspace(folder); - workspaces.set(folder.uri, workspace); + activeWorkspace = workspace; + workspaces.set(folderPath, workspace); workspace.start(context); + } else { + const ws = workspaces.get(folderPath); + activeWorkspace = typeof ws === "undefined" ? null : ws; } } @@ -110,37 +124,37 @@ function sortedWorkspaceFolders(): string[] { return _sortedWorkspaceFolders || []; } -// function getCargoTomlWorkspace(cur_workspace: WorkspaceFolder, file_path: string): WorkspaceFolder { -// if (!cur_workspace) { -// return cur_workspace; -// } - -// const workspace_root = path.parse(cur_workspace.uri.fsPath).dir; -// const root_manifest = path.join(workspace_root, 'Cargo.toml'); -// if (fs.existsSync(root_manifest)) { -// return cur_workspace; -// } - -// let current = file_path; - -// while (true) { -// const old = current; -// current = path.dirname(current); -// if (old == current) { -// break; -// } -// if (workspace_root == path.parse(current).dir) { -// break; -// } - -// const cargo_path = path.join(current, 'Cargo.toml'); -// if (fs.existsSync(cargo_path)) { -// return { ...cur_workspace, uri: Uri.parse(current) }; -// } -// } - -// return cur_workspace; -// } +function getCargoTomlWorkspace(cur_workspace: WorkspaceFolder, file_path: string): WorkspaceFolder { + if (!cur_workspace) { + return cur_workspace; + } + + const workspace_root = path.parse(cur_workspace.uri.fsPath).dir; + const root_manifest = path.join(workspace_root, 'Cargo.toml'); + if (fs.existsSync(root_manifest)) { + return cur_workspace; + } + + let current = file_path; + + while (true) { + const old = current; + current = path.dirname(current); + if (old == current) { + break; + } + if (workspace_root == path.parse(current).dir) { + break; + } + + const cargo_path = path.join(current, 'Cargo.toml'); + if (fs.existsSync(cargo_path)) { + return { ...cur_workspace, uri: Uri.parse(current) }; + } + } + + return cur_workspace; +} function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder { const sorted = sortedWorkspaceFolders(); @@ -166,13 +180,13 @@ function didChangeWorkspaceFolders( // if not, and it is a Rust project (i.e., has a Cargo.toml), then create a new client. for (let folder of e.added) { folder = getOuterMostWorkspaceFolder(folder); - if (workspaces.has(folder.uri)) { + if (workspaces.has(folder.uri.toString())) { continue; } for (const f of fs.readdirSync(folder.uri.fsPath)) { if (f === 'Cargo.toml') { const workspace = new ClientWorkspace(folder); - workspaces.set(folder.uri, workspace); + workspaces.set(folder.uri.toString(), workspace); workspace.start(context); break; } @@ -181,15 +195,18 @@ function didChangeWorkspaceFolders( // If a workspace is removed which is a Rust workspace, kill the client. for (const folder of e.removed) { - const ws = workspaces.get(folder.uri); + const ws = workspaces.get(folder.uri.toString()); if (ws) { - workspaces.delete(folder.uri); + workspaces.delete(folder.uri.toString()); ws.stop(); } } } -const workspaces: Map = new Map(); +// Don't use URI as it's unreliable the same path might not become the same URI. +const workspaces: Map = new Map(); +let activeWorkspace: ClientWorkspace | null; +let commandsUnregistered: boolean = true; // We run one RLS and one corresponding language client per workspace folder // (VSCode workspace, not Cargo workspace). This class contains all the per-client @@ -209,7 +226,10 @@ class ClientWorkspace { } public async start(context: ExtensionContext) { - warnOnMissingCargoToml(); + if (!this.config.multiProjectEnabled) { + warnOnMissingCargoToml(); + } + startSpinner('RLS', 'Starting'); @@ -217,13 +237,17 @@ class ClientWorkspace { await this.autoUpdate(); return this.makeRlsProcess(); }; + + const pattern = this.config.multiProjectEnabled ? `${this.folder.uri.path}/**` : undefined; + const collectionName = this.config.multiProjectEnabled ? `rust ${this.folder.uri.toString()}` : 'rust'; const clientOptions: LanguageClientOptions = { // Register the server for Rust files + documentSelector: [ - { language: 'rust', scheme: 'file' }, - { language: 'rust', scheme: 'untitled' }, + { language: 'rust', scheme: 'file', pattern }, + { language: 'rust', scheme: 'untitled', pattern }, ], - diagnosticCollectionName: 'rust', + diagnosticCollectionName: collectionName, synchronize: { configurationSection: 'rust' }, // Controls when to focus the channel rather than when to reveal it in the drop-down list revealOutputChannelOn: this.config.revealOutputChannelOn, @@ -259,13 +283,15 @@ class ClientWorkspace { clientOptions, ); + const selector = this.config.multiProjectEnabled ? { language: 'rust', scheme: 'file', pattern } : { language: 'rust' }; + this.setupProgressCounter(); - this.registerCommands(context); + this.registerCommands(context, this.config.multiProjectEnabled); this.disposables.push(activateTaskProvider(this.folder)); this.disposables.push(this.lc.start()); this.disposables.push( languages.registerSignatureHelpProvider( - { language: 'rust' }, + selector, new SignatureHelpProvider(this.lc), '(', ',', @@ -279,30 +305,41 @@ class ClientWorkspace { } this.disposables.forEach(d => d.dispose()); + commandsUnregistered = true; } - private registerCommands(context: ExtensionContext) { + private registerCommands(context: ExtensionContext, multiProjectEnabled: boolean) { if (!this.lc) { return; } + if (multiProjectEnabled && !commandsUnregistered) { + return; + } + commandsUnregistered = false; const rustupUpdateDisposable = commands.registerCommand( 'rls.update', () => { - return rustupUpdate(this.config.rustupConfig()); + const ws = multiProjectEnabled && activeWorkspace ? activeWorkspace : this; + return rustupUpdate(ws.config.rustupConfig()); }, ); this.disposables.push(rustupUpdateDisposable); const restartServer = commands.registerCommand('rls.restart', async () => { - await this.stop(); - return this.start(context); + const ws = multiProjectEnabled && activeWorkspace ? activeWorkspace : this; + await ws.stop(); + return ws.start(context); + }); this.disposables.push(restartServer); this.disposables.push( - commands.registerCommand('rls.run', (cmd: Execution) => - runRlsCommand(this.folder, cmd), + commands.registerCommand('rls.run', (cmd: Execution) => { + const ws = multiProjectEnabled && activeWorkspace ? activeWorkspace : this; + runRlsCommand(ws.folder, cmd) + }, + ), ); } From 6684a084ddf5fae25607f903e196236b30cfefd9 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Wed, 7 Aug 2019 04:53:07 +0200 Subject: [PATCH 02/10] apply prettier --- src/configuration.ts | 5 ++- src/extension.ts | 88 ++++++++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/configuration.ts b/src/configuration.ts index 8f1e03b9..e9afc840 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -119,7 +119,10 @@ export class RLSConfiguration { } public get multiProjectEnabled(): boolean { - return this.configuration.get('rust-client.enableMultiProjectSetup', false); + return this.configuration.get( + 'rust-client.enableMultiProjectSetup', + false, + ); } // Added ignoreChannel for readChannel function. Otherwise we end in an infinite loop. diff --git a/src/extension.ts b/src/extension.ts index e251f4b2..b9757de7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -92,14 +92,13 @@ function didOpenTextDocument( const folderPath = folder.uri.toString(); if (!workspaces.has(folderPath)) { - const workspace = new ClientWorkspace(folder); activeWorkspace = workspace; workspaces.set(folderPath, workspace); workspace.start(context); } else { const ws = workspaces.get(folderPath); - activeWorkspace = typeof ws === "undefined" ? null : ws; + activeWorkspace = typeof ws === 'undefined' ? null : ws; } } @@ -124,36 +123,39 @@ function sortedWorkspaceFolders(): string[] { return _sortedWorkspaceFolders || []; } -function getCargoTomlWorkspace(cur_workspace: WorkspaceFolder, file_path: string): WorkspaceFolder { - if (!cur_workspace) { - return cur_workspace; - } +function getCargoTomlWorkspace( + curWorkspace: WorkspaceFolder, + filePath: string, +): WorkspaceFolder { + if (!curWorkspace) { + return curWorkspace; + } - const workspace_root = path.parse(cur_workspace.uri.fsPath).dir; - const root_manifest = path.join(workspace_root, 'Cargo.toml'); - if (fs.existsSync(root_manifest)) { - return cur_workspace; - } + const workspaceRoot = path.parse(curWorkspace.uri.fsPath).dir; + const rootManifest = path.join(workspaceRoot, 'Cargo.toml'); + if (fs.existsSync(rootManifest)) { + return curWorkspace; + } - let current = file_path; + let current = filePath; - while (true) { - const old = current; - current = path.dirname(current); - if (old == current) { - break; - } - if (workspace_root == path.parse(current).dir) { - break; - } + while (true) { + const old = current; + current = path.dirname(current); + if (old === current) { + break; + } + if (workspaceRoot === path.parse(current).dir) { + break; + } - const cargo_path = path.join(current, 'Cargo.toml'); - if (fs.existsSync(cargo_path)) { - return { ...cur_workspace, uri: Uri.parse(current) }; - } + const cargoPath = path.join(current, 'Cargo.toml'); + if (fs.existsSync(cargoPath)) { + return { ...curWorkspace, uri: Uri.parse(current) }; } + } - return cur_workspace; + return curWorkspace; } function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder { @@ -230,7 +232,6 @@ class ClientWorkspace { warnOnMissingCargoToml(); } - startSpinner('RLS', 'Starting'); const serverOptions: ServerOptions = async () => { @@ -238,8 +239,12 @@ class ClientWorkspace { return this.makeRlsProcess(); }; - const pattern = this.config.multiProjectEnabled ? `${this.folder.uri.path}/**` : undefined; - const collectionName = this.config.multiProjectEnabled ? `rust ${this.folder.uri.toString()}` : 'rust'; + const pattern = this.config.multiProjectEnabled + ? `${this.folder.uri.path}/**` + : undefined; + const collectionName = this.config.multiProjectEnabled + ? `rust ${this.folder.uri.toString()}` + : 'rust'; const clientOptions: LanguageClientOptions = { // Register the server for Rust files @@ -283,7 +288,9 @@ class ClientWorkspace { clientOptions, ); - const selector = this.config.multiProjectEnabled ? { language: 'rust', scheme: 'file', pattern } : { language: 'rust' }; + const selector = this.config.multiProjectEnabled + ? { language: 'rust', scheme: 'file', pattern } + : { language: 'rust' }; this.setupProgressCounter(); this.registerCommands(context, this.config.multiProjectEnabled); @@ -308,7 +315,10 @@ class ClientWorkspace { commandsUnregistered = true; } - private registerCommands(context: ExtensionContext, multiProjectEnabled: boolean) { + private registerCommands( + context: ExtensionContext, + multiProjectEnabled: boolean, + ) { if (!this.lc) { return; } @@ -320,27 +330,27 @@ class ClientWorkspace { const rustupUpdateDisposable = commands.registerCommand( 'rls.update', () => { - const ws = multiProjectEnabled && activeWorkspace ? activeWorkspace : this; + const ws = + multiProjectEnabled && activeWorkspace ? activeWorkspace : this; return rustupUpdate(ws.config.rustupConfig()); }, ); this.disposables.push(rustupUpdateDisposable); const restartServer = commands.registerCommand('rls.restart', async () => { - const ws = multiProjectEnabled && activeWorkspace ? activeWorkspace : this; + const ws = + multiProjectEnabled && activeWorkspace ? activeWorkspace : this; await ws.stop(); return ws.start(context); - }); this.disposables.push(restartServer); this.disposables.push( commands.registerCommand('rls.run', (cmd: Execution) => { - const ws = multiProjectEnabled && activeWorkspace ? activeWorkspace : this; - runRlsCommand(ws.folder, cmd) - }, - - ), + const ws = + multiProjectEnabled && activeWorkspace ? activeWorkspace : this; + runRlsCommand(ws.folder, cmd); + }), ); } From c80255218331707d14a09eab277065b0cd9c9c5b Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 13 Aug 2019 10:51:31 +0200 Subject: [PATCH 03/10] tell about the new setting in the warning when Cargo.toml is not found. --- src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index b9757de7..e0cb064b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -518,7 +518,7 @@ async function warnOnMissingCargoToml() { if (files.length < 1) { window.showWarningMessage( - 'A Cargo.toml file must be at the root of the workspace in order to support all features', + 'A Cargo.toml file must be at the root of the workspace in order to support all features. Alternatively set rust-client.enableMultiProjectSetup=true in settings.', ); } } From 60312e3134808ad0ddf68bdae3443048b9d51035 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 10 Sep 2019 22:27:53 +0200 Subject: [PATCH 04/10] move nearestParentWorkspace into workspace_util --- src/extension.ts | 35 +-------------------------------- src/workspace_util.ts | 45 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 34 deletions(-) create mode 100644 src/workspace_util.ts diff --git a/src/extension.ts b/src/extension.ts index e0cb064b..7f08f525 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -21,6 +21,7 @@ import { ServerOptions, } from 'vscode-languageclient'; +import * as workspace_util from './workspace_util'; import { RLSConfiguration } from './configuration'; import { SignatureHelpProvider } from './providers/signatureHelpProvider'; import { checkForRls, ensureToolchain, rustupUpdate } from './rustup'; @@ -123,40 +124,6 @@ function sortedWorkspaceFolders(): string[] { return _sortedWorkspaceFolders || []; } -function getCargoTomlWorkspace( - curWorkspace: WorkspaceFolder, - filePath: string, -): WorkspaceFolder { - if (!curWorkspace) { - return curWorkspace; - } - - const workspaceRoot = path.parse(curWorkspace.uri.fsPath).dir; - const rootManifest = path.join(workspaceRoot, 'Cargo.toml'); - if (fs.existsSync(rootManifest)) { - return curWorkspace; - } - - let current = filePath; - - while (true) { - const old = current; - current = path.dirname(current); - if (old === current) { - break; - } - if (workspaceRoot === path.parse(current).dir) { - break; - } - - const cargoPath = path.join(current, 'Cargo.toml'); - if (fs.existsSync(cargoPath)) { - return { ...curWorkspace, uri: Uri.parse(current) }; - } - } - - return curWorkspace; -} function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder { const sorted = sortedWorkspaceFolders(); diff --git a/src/workspace_util.ts b/src/workspace_util.ts new file mode 100644 index 00000000..89d2603f --- /dev/null +++ b/src/workspace_util.ts @@ -0,0 +1,45 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { WorkspaceFolder, Uri } from 'vscode'; + + + +// searches up the folder structure until it finds a Cargo.toml +export function nearestParentWorkspace( + curWorkspace: WorkspaceFolder, + filePath: string, + ): WorkspaceFolder { + + + if (!curWorkspace) { + return curWorkspace; + } + + const workspaceRoot = path.parse(curWorkspace.uri.fsPath).dir; + const rootManifest = path.join(workspaceRoot, 'Cargo.toml'); + if (fs.existsSync(rootManifest)) { + return curWorkspace; + } + + let current = filePath; + + while (true) { + const old = current; + current = path.dirname(current); + if (old === current) { + break; + } + if (workspaceRoot === path.parse(current).dir) { + break; + } + + const cargoPath = path.join(current, 'Cargo.toml'); + if (fs.existsSync(cargoPath)) { + return { ...curWorkspace, uri: Uri.parse(current) }; + } + } + + return curWorkspace; + } + + From 2a5ab7828ca519e9189e15b5c8f7e261311d8d95 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 10 Sep 2019 22:52:19 +0200 Subject: [PATCH 05/10] remove defensive programming (as it's already being defended against) --- src/workspace_util.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/workspace_util.ts b/src/workspace_util.ts index 89d2603f..7b6ae58b 100644 --- a/src/workspace_util.ts +++ b/src/workspace_util.ts @@ -10,11 +10,6 @@ export function nearestParentWorkspace( filePath: string, ): WorkspaceFolder { - - if (!curWorkspace) { - return curWorkspace; - } - const workspaceRoot = path.parse(curWorkspace.uri.fsPath).dir; const rootManifest = path.join(workspaceRoot, 'Cargo.toml'); if (fs.existsSync(rootManifest)) { From 0e1114b7c5ff81cc538c38a9cdffd003f4e6a324 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 10 Sep 2019 22:54:14 +0200 Subject: [PATCH 06/10] make intent more clear by using easier to understand names in exchange of cargo cult --- src/extension.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 7f08f525..5da4af33 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -45,10 +45,10 @@ interface ProgressParams { export async function activate(context: ExtensionContext) { context.subscriptions.push(configureLanguage()); - workspace.onDidOpenTextDocument(doc => didOpenTextDocument(doc, context)); - workspace.textDocuments.forEach(doc => didOpenTextDocument(doc, context)); + workspace.onDidOpenTextDocument(doc => whenOpeningTextDocument(doc, context)); + workspace.textDocuments.forEach(doc => whenOpeningTextDocument(doc, context)); workspace.onDidChangeWorkspaceFolders(e => - didChangeWorkspaceFolders(e, context), + whenChangingWorkspaceFolders(e, context), ); } @@ -57,7 +57,7 @@ export async function deactivate() { } // Taken from https://github.com/Microsoft/vscode-extension-samples/blob/master/lsp-multi-server-sample/client/src/extension.ts -function didOpenTextDocument( +function whenOpeningTextDocument( document: TextDocument, context: ExtensionContext, ) { @@ -71,17 +71,17 @@ function didOpenTextDocument( return; } - if ( - workspace + const inMultiProjectMode = workspace .getConfiguration() - .get('rust-client.enableMultiProjectSetup', false) - ) { - folder = getCargoTomlWorkspace(folder, document.uri.fsPath); - } else if ( - workspace - .getConfiguration() - .get('rust-client.nestedMultiRootConfigInOutermost', true) - ) { + .get('rust-client.enableMultiProjectSetup', false); + + const inNestedOuterProjectMode = workspace + .getConfiguration() + .get('rust-client.nestedMultiRootConfigInOutermost', true); + + if (inMultiProjectMode) { + folder = workspace_util.nearestParentWorkspace(folder, document.uri.fsPath); + } else if (inNestedOuterProjectMode) { folder = getOuterMostWorkspaceFolder(folder); } @@ -139,7 +139,7 @@ function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder { return folder; } -function didChangeWorkspaceFolders( +function whenChangingWorkspaceFolders( e: WorkspaceFoldersChangeEvent, context: ExtensionContext, ) { From 6a580eb8e014812bb8ad12811b95ac77a3e871e7 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 10 Sep 2019 22:54:46 +0200 Subject: [PATCH 07/10] Remove the double negative --- src/extension.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 5da4af33..07d71073 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -175,7 +175,7 @@ function whenChangingWorkspaceFolders( // Don't use URI as it's unreliable the same path might not become the same URI. const workspaces: Map = new Map(); let activeWorkspace: ClientWorkspace | null; -let commandsUnregistered: boolean = true; +let commandsRegistered: boolean = false; // We run one RLS and one corresponding language client per workspace folder // (VSCode workspace, not Cargo workspace). This class contains all the per-client @@ -279,7 +279,7 @@ class ClientWorkspace { } this.disposables.forEach(d => d.dispose()); - commandsUnregistered = true; + commandsRegistered = false; } private registerCommands( @@ -289,11 +289,11 @@ class ClientWorkspace { if (!this.lc) { return; } - if (multiProjectEnabled && !commandsUnregistered) { + if (multiProjectEnabled && commandsRegistered) { return; } - commandsUnregistered = false; + commandsRegistered = true; const rustupUpdateDisposable = commands.registerCommand( 'rls.update', () => { From 3c957c13e45b891affe01cb87c99db74faf150a8 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 10 Sep 2019 22:55:33 +0200 Subject: [PATCH 08/10] add todo for future work --- src/extension.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/extension.ts b/src/extension.ts index 07d71073..c4066722 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -108,6 +108,7 @@ function whenOpeningTextDocument( let _sortedWorkspaceFolders: string[] | undefined; function sortedWorkspaceFolders(): string[] { + // TODO: decouple the global state such that it can be moved to workspace_util if (!_sortedWorkspaceFolders && workspace.workspaceFolders) { _sortedWorkspaceFolders = workspace.workspaceFolders .map(folder => { @@ -126,6 +127,7 @@ function sortedWorkspaceFolders(): string[] { function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder { + // TODO: decouple the global state such that it can be moved to workspace_util const sorted = sortedWorkspaceFolders(); for (const element of sorted) { let uri = folder.uri.toString(); From da6bb20c09bd2aacdd08073274da48edc15caded Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 10 Sep 2019 23:02:53 +0200 Subject: [PATCH 09/10] add coments to the "Cargo.toml" search --- src/workspace_util.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/workspace_util.ts b/src/workspace_util.ts index 7b6ae58b..8618e2d5 100644 --- a/src/workspace_util.ts +++ b/src/workspace_util.ts @@ -10,26 +10,34 @@ export function nearestParentWorkspace( filePath: string, ): WorkspaceFolder { + // check that the workspace folder already contains the "Cargo.toml" const workspaceRoot = path.parse(curWorkspace.uri.fsPath).dir; const rootManifest = path.join(workspaceRoot, 'Cargo.toml'); if (fs.existsSync(rootManifest)) { return curWorkspace; } + // algorithm that will strip one folder at a time and check if that folder contains "Cargo.toml" let current = filePath; - while (true) { const old = current; current = path.dirname(current); + + // break in case there is a bug that could result in a busy loop if (old === current) { break; } + + // break in case the strip folder has not changed if (workspaceRoot === path.parse(current).dir) { break; } + // check if "Cargo.toml" is present in the parent folder const cargoPath = path.join(current, 'Cargo.toml'); if (fs.existsSync(cargoPath)) { + + // ghetto change the uri on Workspace folder to make vscode think it's located elsewhere return { ...curWorkspace, uri: Uri.parse(current) }; } } From 47c66be3b8801d880af1b21b5be76ec76d02d543 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 10 Sep 2019 23:08:06 +0200 Subject: [PATCH 10/10] fix linting errors --- src/extension.ts | 11 ++++---- src/workspace_util.ts | 66 ++++++++++++++++++++----------------------- 2 files changed, 35 insertions(+), 42 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index c4066722..d66a2912 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -21,7 +21,6 @@ import { ServerOptions, } from 'vscode-languageclient'; -import * as workspace_util from './workspace_util'; import { RLSConfiguration } from './configuration'; import { SignatureHelpProvider } from './providers/signatureHelpProvider'; import { checkForRls, ensureToolchain, rustupUpdate } from './rustup'; @@ -29,6 +28,7 @@ import { startSpinner, stopSpinner } from './spinner'; import { activateTaskProvider, Execution, runRlsCommand } from './tasks'; import { withWsl } from './utils/child_process'; import { uriWindowsToWsl, uriWslToWindows } from './utils/wslpath'; +import * as workspace_util from './workspace_util'; /** * Parameter type to `window/progress` request as issued by the RLS. @@ -72,12 +72,12 @@ function whenOpeningTextDocument( } const inMultiProjectMode = workspace - .getConfiguration() - .get('rust-client.enableMultiProjectSetup', false); + .getConfiguration() + .get('rust-client.enableMultiProjectSetup', false); const inNestedOuterProjectMode = workspace - .getConfiguration() - .get('rust-client.nestedMultiRootConfigInOutermost', true); + .getConfiguration() + .get('rust-client.nestedMultiRootConfigInOutermost', true); if (inMultiProjectMode) { folder = workspace_util.nearestParentWorkspace(folder, document.uri.fsPath); @@ -125,7 +125,6 @@ function sortedWorkspaceFolders(): string[] { return _sortedWorkspaceFolders || []; } - function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder { // TODO: decouple the global state such that it can be moved to workspace_util const sorted = sortedWorkspaceFolders(); diff --git a/src/workspace_util.ts b/src/workspace_util.ts index 8618e2d5..eb1961b9 100644 --- a/src/workspace_util.ts +++ b/src/workspace_util.ts @@ -1,48 +1,42 @@ import * as fs from 'fs'; import * as path from 'path'; -import { WorkspaceFolder, Uri } from 'vscode'; - - +import { Uri, WorkspaceFolder } from 'vscode'; // searches up the folder structure until it finds a Cargo.toml export function nearestParentWorkspace( - curWorkspace: WorkspaceFolder, - filePath: string, - ): WorkspaceFolder { - - // check that the workspace folder already contains the "Cargo.toml" - const workspaceRoot = path.parse(curWorkspace.uri.fsPath).dir; - const rootManifest = path.join(workspaceRoot, 'Cargo.toml'); - if (fs.existsSync(rootManifest)) { - return curWorkspace; - } - - // algorithm that will strip one folder at a time and check if that folder contains "Cargo.toml" - let current = filePath; - while (true) { - const old = current; - current = path.dirname(current); - - // break in case there is a bug that could result in a busy loop - if (old === current) { - break; - } + curWorkspace: WorkspaceFolder, + filePath: string, +): WorkspaceFolder { + // check that the workspace folder already contains the "Cargo.toml" + const workspaceRoot = path.parse(curWorkspace.uri.fsPath).dir; + const rootManifest = path.join(workspaceRoot, 'Cargo.toml'); + if (fs.existsSync(rootManifest)) { + return curWorkspace; + } - // break in case the strip folder has not changed - if (workspaceRoot === path.parse(current).dir) { - break; - } + // algorithm that will strip one folder at a time and check if that folder contains "Cargo.toml" + let current = filePath; + while (true) { + const old = current; + current = path.dirname(current); - // check if "Cargo.toml" is present in the parent folder - const cargoPath = path.join(current, 'Cargo.toml'); - if (fs.existsSync(cargoPath)) { + // break in case there is a bug that could result in a busy loop + if (old === current) { + break; + } - // ghetto change the uri on Workspace folder to make vscode think it's located elsewhere - return { ...curWorkspace, uri: Uri.parse(current) }; - } + // break in case the strip folder has not changed + if (workspaceRoot === path.parse(current).dir) { + break; } - return curWorkspace; + // check if "Cargo.toml" is present in the parent folder + const cargoPath = path.join(current, 'Cargo.toml'); + if (fs.existsSync(cargoPath)) { + // ghetto change the uri on Workspace folder to make vscode think it's located elsewhere + return { ...curWorkspace, uri: Uri.parse(current) }; + } } - + return curWorkspace; +}