From 5c0d7017a53e9b0ad703ccd8d9b2fda3a63a6698 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 04:55:56 +0200 Subject: [PATCH 01/11] add cli flag to override root dir from language protocol and force it to be cwd of the RA server --- crates/rust-analyzer/src/bin/args.rs | 13 ++++++++--- crates/rust-analyzer/src/bin/main.rs | 35 +++++++++++++++++++--------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs index 3cf394bb41ff..2ab59311af26 100644 --- a/crates/rust-analyzer/src/bin/args.rs +++ b/crates/rust-analyzer/src/bin/args.rs @@ -11,6 +11,7 @@ use std::{fmt::Write, path::PathBuf}; pub(crate) struct Args { pub(crate) verbosity: Verbosity, + pub(crate) use_cwd: bool, pub(crate) command: Command, } @@ -43,9 +44,15 @@ impl Args { pub(crate) fn parse() -> Result> { let mut matches = Arguments::from_env(); + let use_cwd = matches.contains("--use-cwd"); + if matches.contains("--version") { matches.finish().or_else(handle_extra_flags)?; - return Ok(Ok(Args { verbosity: Verbosity::Normal, command: Command::Version })); + return Ok(Ok(Args { + verbosity: Verbosity::Normal, + use_cwd, + command: Command::Version, + })); } let verbosity = match ( @@ -65,7 +72,7 @@ impl Args { Some(it) => it, None => { matches.finish().or_else(handle_extra_flags)?; - return Ok(Ok(Args { verbosity, command: Command::RunServer })); + return Ok(Ok(Args { verbosity, use_cwd, command: Command::RunServer })); } }; let command = match subcommand.as_str() { @@ -230,7 +237,7 @@ SUBCOMMANDS: return Ok(Err(HelpPrinted)); } }; - Ok(Ok(Args { verbosity, command })) + Ok(Ok(Args { verbosity, use_cwd, command })) } } diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 608f4f67b2c8..6a6a8970048e 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -39,7 +39,7 @@ fn main() -> Result<()> { cli::analysis_bench(args.verbosity, path.as_ref(), what, load_output_dirs)? } - args::Command::RunServer => run_server()?, + args::Command::RunServer => run_server(args.use_cwd)?, args::Command::Version => println!("rust-analyzer {}", env!("REV")), } Ok(()) @@ -52,7 +52,7 @@ fn setup_logging() -> Result<()> { Ok(()) } -fn run_server() -> Result<()> { +fn run_server(use_cwd: bool) -> Result<()> { log::info!("lifecycle: server started"); let (connection, io_threads) = Connection::stdio(); @@ -67,15 +67,28 @@ fn run_server() -> Result<()> { } let cwd = std::env::current_dir()?; - let root = initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); - - let workspace_roots = initialize_params - .workspace_folders - .map(|workspaces| { - workspaces.into_iter().filter_map(|it| it.uri.to_file_path().ok()).collect::>() - }) - .filter(|workspaces| !workspaces.is_empty()) - .unwrap_or_else(|| vec![root]); + let root = if use_cwd { + cwd + } else { + initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd) + }; + + log::info!("lifecycle: server started"); + + let workspace_roots = if use_cwd { + vec![root] + } else { + initialize_params + .workspace_folders + .map(|workspaces| { + workspaces + .into_iter() + .filter_map(|it| it.uri.to_file_path().ok()) + .collect::>() + }) + .filter(|workspaces| !workspaces.is_empty()) + .unwrap_or_else(|| vec![root]) + }; let config = { let mut config = Config::default(); From 6091d1804d7ed267c2b00a0bf648d572baaf9cb4 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 04:57:20 +0200 Subject: [PATCH 02/11] create helper to find the location of Cargo.toml root folder --- editors/code/src/util.ts | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 6f91f81d63ed..d353ad482e88 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -1,5 +1,8 @@ import * as lc from "vscode-languageclient"; import * as vscode from "vscode"; +import * as path from 'path'; +import * as fs from 'fs'; +import * as util from 'util'; import { strict as nativeAssert } from "assert"; export function assert(condition: boolean, explanation: string): asserts condition { @@ -11,6 +14,7 @@ export function assert(condition: boolean, explanation: string): asserts conditi } } + export const log = new class { private enabled = true; @@ -82,3 +86,51 @@ export function isRustDocument(document: vscode.TextDocument): document is RustD export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor { return isRustDocument(editor.document); } + +export function createWorkspaceWithNewLocation(workspace: vscode.WorkspaceFolder, newLoc: vscode.Uri) { + return { + ...workspace, + name: path.basename(newLoc.fsPath), + uri: newLoc, + }; +} + +// searches up the folder structure until it finds a Cargo.toml +export async function nearestParentWithCargoToml( + workspaceRootUri: vscode.Uri, + fileLoc: vscode.Uri, + ): Promise { + const file_exists: (path: fs.PathLike) => Promise = util.promisify(fs.exists); + // check that the workspace folder already contains the "Cargo.toml" + const workspaceRoot = workspaceRootUri.fsPath; + const rootManifest = path.join(workspaceRoot, 'Cargo.toml'); + if (await file_exists(rootManifest)) { + return workspaceRootUri; + } + + // algorithm that will strip one folder at a time and check if that folder contains "Cargo.toml" + let current = fileLoc.fsPath; + 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 reached the workspace root + if (workspaceRoot === current) { + break; + } + + // check if "Cargo.toml" is present in the parent folder + const cargoPath = path.join(current, 'Cargo.toml'); + if (await file_exists(cargoPath)) { + // ghetto change the uri on Workspace folder to make vscode think it's located elsewhere + return vscode.Uri.file(current); + } + } + + return null; + } From f2e24a1c19dcabb88338dd7e0ecd594995c0ccdc Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 04:58:51 +0200 Subject: [PATCH 03/11] create functionality to lazily create ctx based on opening rust files and finding the cargo toml that belongs to that file --- editors/code/src/main.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index efd56a84b52f..7a9eb27e2ee4 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -15,9 +15,40 @@ import { spawnSync } from 'child_process'; import { activateTaskProvider } from './tasks'; let ctx: Ctx | undefined; +const ctxes: Map = new Map(); export async function activate(context: vscode.ExtensionContext) { // Register a "dumb" onEnter command for the case where server fails to + +async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode.ExtensionContext) { + if (!isRustDocument(doc)) { + return; + } + + let workspaceRoot = vscode.workspace.getWorkspaceFolder(doc.uri); + if (!workspaceRoot) { + return; + } + + let cargoRoot = await nearestParentWithCargoToml(workspaceRoot.uri, doc.uri); + if (cargoRoot == null) { + vscode.window.showWarningMessage("Cargo.toml could not be located"); + return; + } + + + if (ctxes.has(cargoRoot.path)) { + ctx = ctxes.get(cargoRoot.path); + return; + } else { + const workspaceOnCargoRoot = createWorkspaceWithNewLocation(workspaceRoot, cargoRoot); + const newCtx = await activate_new(workspaceOnCargoRoot, context); + ctxes.set(cargoRoot.path, newCtx); + ctx = newCtx; + } + +} + // start. // // FIXME: refactor command registration code such that commands are From 8c7c21239edd9ea6bb665fcd3d0dd56342d6b759 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 05:01:43 +0200 Subject: [PATCH 04/11] create functionality to register Commands that only gets triggered for the active Ctx --- editors/code/src/ctx.ts | 17 +++++++---------- editors/code/src/main.ts | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index f7ed62d0356b..e1c0f3404376 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -11,6 +11,7 @@ export class Ctx { private readonly extCtx: vscode.ExtensionContext, readonly client: lc.LanguageClient, readonly serverPath: string, + readonly subscriptions: Disposable[], ) { } @@ -22,7 +23,7 @@ export class Ctx { cwd: string, ): Promise { const client = await createClient(serverPath, cwd); - const res = new Ctx(config, extCtx, client, serverPath); + const res = new Ctx(config, extCtx, client, serverPath, []); res.pushCleanup(client.start()); await client.onReady(); return res; @@ -39,23 +40,19 @@ export class Ctx { return vscode.window.visibleTextEditors.filter(isRustEditor); } - registerCommand(name: string, factory: (ctx: Ctx) => Cmd) { - const fullName = `rust-analyzer.${name}`; - const cmd = factory(this); - const d = vscode.commands.registerCommand(fullName, cmd); - this.pushCleanup(d); - } get globalState(): vscode.Memento { return this.extCtx.globalState; } - get subscriptions(): Disposable[] { - return this.extCtx.subscriptions; + dispose() { + for (let d of this.subscriptions) { + d.dispose(); + } } pushCleanup(d: Disposable) { - this.extCtx.subscriptions.push(d); + this.subscriptions.push(d); } } diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 7a9eb27e2ee4..6442af666061 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -17,6 +17,23 @@ import { activateTaskProvider } from './tasks'; let ctx: Ctx | undefined; const ctxes: Map = new Map(); + +function registerCtxCommand(name: string, factory: (ctx: Ctx) => Cmd, fallback: Cmd | undefined, context: vscode.ExtensionContext) { + const fullName = `rust-analyzer.${name}`; + + async function wrapped_cmd(...args: any[]): Promise { + if (ctx) { + let cmd = factory(ctx); + return await cmd(args); + } else if (fallback) { + return await fallback(args); + } + return; + } + + const d = vscode.commands.registerCommand(fullName, wrapped_cmd); + context.subscriptions.push(d); +} export async function activate(context: vscode.ExtensionContext) { // Register a "dumb" onEnter command for the case where server fails to From 6eb447197339e054616a2bcfbd08d18e9e1b1cf3 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 05:05:08 +0200 Subject: [PATCH 05/11] redesign active such that ctxes are lazily loaded but has the ability to have many simultaniously running. --- editors/code/src/main.ts | 89 ++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 49 deletions(-) diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 6442af666061..c1935e1158d7 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -34,8 +34,6 @@ function registerCtxCommand(name: string, factory: (ctx: Ctx) => Cmd, fallback: const d = vscode.commands.registerCommand(fullName, wrapped_cmd); context.subscriptions.push(d); } -export async function activate(context: vscode.ExtensionContext) { - // Register a "dumb" onEnter command for the case where server fails to async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode.ExtensionContext) { if (!isRustDocument(doc)) { @@ -79,33 +77,43 @@ async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode // "rust-analyzer is not available" // ), // ) - const defaultOnEnter = vscode.commands.registerCommand( - 'rust-analyzer.onEnter', - () => vscode.commands.executeCommand('default:type', { text: '\n' }), - ); - context.subscriptions.push(defaultOnEnter); const config = new Config(context); const state = new PersistentState(context.globalState); const serverPath = await bootstrap(config, state); - const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; - if (workspaceFolder === undefined) { - const err = "Cannot activate rust-analyzer when no folder is opened"; - void vscode.window.showErrorMessage(err); - throw new Error(err); - } - // Note: we try to start the server before we activate type hints so that it - // registers its `onDidChangeDocument` handler before us. - // - // This a horribly, horribly wrong way to deal with this problem. - ctx = await Ctx.create(config, context, serverPath, workspaceFolder.uri.fsPath); - // Commands which invokes manually via command palette, shortcut, etc. - // Reloading is inspired by @DanTup maneuver: https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895 - ctx.registerCommand('reload', _ => async () => { +export async function activate(context: vscode.ExtensionContext) { + + // context.subscriptions.push(defaultOnEnter); + + // Commands which invokes manually via command palette, shortcut, etc., they will attempt to find the use the RA for the specific document's project + const register = (name: string, command: (ctx: Ctx) => Cmd) => registerCtxCommand(name, command, undefined, context); + const registerWithFallBack = (name: string, command: (ctx: Ctx) => Cmd, fallback: Cmd) => registerCtxCommand(name, command, fallback, context); + register('analyzerStatus', commands.analyzerStatus); + register('collectGarbage', commands.collectGarbage); + register('matchingBrace', commands.matchingBrace); + register('joinLines', commands.joinLines); + register('parentModule', commands.parentModule); + register('syntaxTree', commands.syntaxTree); + register('expandMacro', commands.expandMacro); + register('run', commands.run); + + registerWithFallBack('onEnter', commands.onEnter, () => vscode.commands.executeCommand('default:type', { text: '\n' })); + + register('ssr', commands.ssr); + register('serverVersion', commands.serverVersion); + + // Internal commands which are invoked by the server. + register('runSingle', commands.runSingle); + register('debugSingle', commands.debugSingle); + register('showReferences', commands.showReferences); + register('applySourceChange', commands.applySourceChange); + register('selectAndApplySourceChange', commands.selectAndApplySourceChange); + + register('reload', _ => async () => { void vscode.window.showInformationMessage('Reloading rust-analyzer...'); await deactivate(); while (context.subscriptions.length > 0) { @@ -117,40 +125,23 @@ async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode } await activate(context).catch(log.error); }); + // Reloading is inspired by @DanTup maneuver: https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895 - ctx.registerCommand('analyzerStatus', commands.analyzerStatus); - ctx.registerCommand('collectGarbage', commands.collectGarbage); - ctx.registerCommand('matchingBrace', commands.matchingBrace); - ctx.registerCommand('joinLines', commands.joinLines); - ctx.registerCommand('parentModule', commands.parentModule); - ctx.registerCommand('syntaxTree', commands.syntaxTree); - ctx.registerCommand('expandMacro', commands.expandMacro); - ctx.registerCommand('run', commands.run); - - defaultOnEnter.dispose(); - ctx.registerCommand('onEnter', commands.onEnter); - - ctx.registerCommand('ssr', commands.ssr); - ctx.registerCommand('serverVersion', commands.serverVersion); - - // Internal commands which are invoked by the server. - ctx.registerCommand('runSingle', commands.runSingle); - ctx.registerCommand('debugSingle', commands.debugSingle); - ctx.registerCommand('showReferences', commands.showReferences); - ctx.registerCommand('applySourceChange', commands.applySourceChange); - ctx.registerCommand('selectAndApplySourceChange', commands.selectAndApplySourceChange); - - ctx.pushCleanup(activateTaskProvider(workspaceFolder)); - - activateStatusDisplay(ctx); + vscode.workspace.onDidOpenTextDocument(doc => whenOpeningTextDocument(doc, context), null, context.subscriptions); + vscode.workspace.textDocuments.forEach(doc => whenOpeningTextDocument(doc, context)); - activateInlayHints(ctx); + function changeConfig() { + for (let ctx of ctxes.values()) { + ctx.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }); + } + } vscode.workspace.onDidChangeConfiguration( - _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), + _ => changeConfig, null, - ctx.subscriptions, + context.subscriptions, ); + } export async function deactivate() { From 0c3b3001faf402ee9e33d76f399c5b394eb0d987 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 05:06:11 +0200 Subject: [PATCH 06/11] create the version of activate that is executed for each new project with a Cargo.toml --- editors/code/src/main.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index c1935e1158d7..6b24f7bc27f3 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -64,6 +64,8 @@ async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode } +async function activate_new(workspaceFolder: vscode.WorkspaceFolder, context: vscode.ExtensionContext): Promise { +// Register a "dumb" onEnter command for the case where server fails to // start. // // FIXME: refactor command registration code such that commands are @@ -83,7 +85,15 @@ async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode const serverPath = await bootstrap(config, state); + let ctx = await Ctx.create(config, context, serverPath, workspaceFolder); + context.subscriptions.push(activateTaskProvider(workspaceFolder)); + + + activateInlayHints(ctx); + + return ctx; +} export async function activate(context: vscode.ExtensionContext) { From 48e0769931c6b917c8dda6e3f444028ff1608cb2 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 05:16:28 +0200 Subject: [PATCH 07/11] update deactive such that it cleans every ctx --- editors/code/src/main.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 6b24f7bc27f3..0d27809852b1 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -155,7 +155,10 @@ export async function activate(context: vscode.ExtensionContext) { } export async function deactivate() { - await ctx?.client.stop(); + for (let ctx of ctxes.values()) { + await ctx.dispose(); + } + ctxes.clear(); ctx = undefined; } From e676e9a41e438062261787a5aa356c9306e6388e Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 05:09:50 +0200 Subject: [PATCH 08/11] change language server such that: * it only looks at files from it's ctx * uses cwd for the language server --- editors/code/src/client.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 0ad4b63aeb18..945e30b5a1f6 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -4,14 +4,15 @@ import * as vscode from 'vscode'; import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; -export async function createClient(serverPath: string, cwd: string): Promise { +export async function createClient(serverPath: string, cwd: vscode.WorkspaceFolder): Promise { // '.' Is the fallback if no folder is open // TODO?: Workspace folders support Uri's (eg: file://test.txt). // It might be a good idea to test if the uri points to a file. const run: lc.Executable = { command: serverPath, - options: { cwd }, + args: ["--use-cwd"], + options: { cwd: cwd.uri.fsPath }, }; const serverOptions: lc.ServerOptions = { run, @@ -22,7 +23,7 @@ export async function createClient(serverPath: string, cwd: string): Promise Date: Tue, 14 Apr 2020 05:10:23 +0200 Subject: [PATCH 09/11] fix tasks such that they work depending on which project you are focusing --- editors/code/src/tasks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts index fa1c4a951ddb..9eec3dd2b000 100644 --- a/editors/code/src/tasks.ts +++ b/editors/code/src/tasks.ts @@ -42,7 +42,7 @@ function getStandardCargoTasks(target: vscode.WorkspaceFolder): vscode.Task[] { `cargo ${command}`, 'rust', // What to do when this command is executed. - new vscode.ShellExecution('cargo', [command]), + new vscode.ShellExecution('cargo', [command], { cwd: target.uri.fsPath } ), // Problem matchers. ['$rustc'], ); From 9b936a4716b9c1f38377cf863ddf89f45ca735c3 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 05:17:07 +0200 Subject: [PATCH 10/11] update StatusDisplay * one status diplay per project * Will hide / show depending on the active project --- editors/code/src/ctx.ts | 27 +++++++++++++++++++++++++-- editors/code/src/main.ts | 7 ++++--- editors/code/src/status_display.ts | 23 +++++------------------ 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index e1c0f3404376..30f60ff850e9 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -4,6 +4,8 @@ import * as lc from 'vscode-languageclient'; import { Config } from './config'; import { createClient } from './client'; import { isRustEditor, RustEditor } from './util'; +import { StatusDisplay } from './status_display'; +import { WorkDoneProgress } from 'vscode-languageclient'; export class Ctx { private constructor( @@ -12,6 +14,7 @@ export class Ctx { readonly client: lc.LanguageClient, readonly serverPath: string, readonly subscriptions: Disposable[], + private readonly status: StatusDisplay, ) { } @@ -20,12 +23,24 @@ export class Ctx { config: Config, extCtx: vscode.ExtensionContext, serverPath: string, - cwd: string, + cwd: vscode.WorkspaceFolder, ): Promise { const client = await createClient(serverPath, cwd); - const res = new Ctx(config, extCtx, client, serverPath, []); + + const statusDisplay = new StatusDisplay(config.checkOnSave.command); + const res = new Ctx(config, extCtx, client, serverPath, [], statusDisplay); + res.pushCleanup(client.start()); await client.onReady(); + + res.pushCleanup(res.status); + if (client != null) { + res.pushCleanup(client.onProgress( + WorkDoneProgress.type, + 'rustAnalyzer/cargoWatcher', + params => res.status.handleProgressNotification(params) + )); + } return res; } @@ -45,6 +60,14 @@ export class Ctx { return this.extCtx.globalState; } + show() { + this.status.statusBarItem.show(); + } + + hide() { + this.status.statusBarItem.hide(); + } + dispose() { for (let d of this.subscriptions) { d.dispose(); diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 0d27809852b1..ef5b026a3a3a 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -5,10 +5,9 @@ import { promises as fs } from "fs"; import * as commands from './commands'; import { activateInlayHints } from './inlay_hints'; -import { activateStatusDisplay } from './status_display'; -import { Ctx } from './ctx'; +import { Ctx,Cmd } from './ctx'; import { Config, NIGHTLY_TAG } from './config'; -import { log, assert } from './util'; +import { log, assert, isRustDocument, nearestParentWithCargoToml, createWorkspaceWithNewLocation } from './util'; import { PersistentState } from './persistent_state'; import { fetchRelease, download } from './net'; import { spawnSync } from 'child_process'; @@ -51,6 +50,7 @@ async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode return; } + ctx?.hide(); if (ctxes.has(cargoRoot.path)) { ctx = ctxes.get(cargoRoot.path); @@ -61,6 +61,7 @@ async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode ctxes.set(cargoRoot.path, newCtx); ctx = newCtx; } + ctx?.show(); } diff --git a/editors/code/src/status_display.ts b/editors/code/src/status_display.ts index f9cadc8a2258..669171bb2772 100644 --- a/editors/code/src/status_display.ts +++ b/editors/code/src/status_display.ts @@ -1,29 +1,16 @@ import * as vscode from 'vscode'; -import { WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd, Disposable } from 'vscode-languageclient'; - -import { Ctx } from './ctx'; +import { WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd, Disposable } from 'vscode-languageclient'; const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; -export function activateStatusDisplay(ctx: Ctx) { - const statusDisplay = new StatusDisplay(ctx.config.checkOnSave.command); - ctx.pushCleanup(statusDisplay); - const client = ctx.client; - if (client != null) { - ctx.pushCleanup(client.onProgress( - WorkDoneProgress.type, - 'rustAnalyzer/cargoWatcher', - params => statusDisplay.handleProgressNotification(params) - )); - } -} -class StatusDisplay implements Disposable { + +export class StatusDisplay implements Disposable { packageName?: string; private i: number = 0; - private statusBarItem: vscode.StatusBarItem; + public statusBarItem: vscode.StatusBarItem; private command: string; private timer?: NodeJS.Timeout; @@ -33,7 +20,7 @@ class StatusDisplay implements Disposable { 10, ); this.command = command; - this.statusBarItem.hide(); + this.statusBarItem.show(); } show() { From e3a46029bf653961da0d4b12aa2f5a8d83ddb6e9 Mon Sep 17 00:00:00 2001 From: Jannick Johnsen Date: Tue, 14 Apr 2020 05:52:45 +0200 Subject: [PATCH 11/11] fix linting --- editors/code/src/client.ts | 2 +- editors/code/src/ctx.ts | 2 +- editors/code/src/main.ts | 26 ++++++++++---------- editors/code/src/tasks.ts | 2 +- editors/code/src/util.ts | 50 +++++++++++++++++++------------------- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 945e30b5a1f6..703898c9500e 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -12,7 +12,7 @@ export async function createClient(serverPath: string, cwd: vscode.WorkspaceFold const run: lc.Executable = { command: serverPath, args: ["--use-cwd"], - options: { cwd: cwd.uri.fsPath }, + options: { cwd: cwd.uri.fsPath }, }; const serverOptions: lc.ServerOptions = { run, diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 30f60ff850e9..24ca90d3ae19 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -69,7 +69,7 @@ export class Ctx { } dispose() { - for (let d of this.subscriptions) { + for (const d of this.subscriptions) { d.dispose(); } } diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index ef5b026a3a3a..22a4c00e86bb 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -5,7 +5,7 @@ import { promises as fs } from "fs"; import * as commands from './commands'; import { activateInlayHints } from './inlay_hints'; -import { Ctx,Cmd } from './ctx'; +import { Ctx, Cmd } from './ctx'; import { Config, NIGHTLY_TAG } from './config'; import { log, assert, isRustDocument, nearestParentWithCargoToml, createWorkspaceWithNewLocation } from './util'; import { PersistentState } from './persistent_state'; @@ -17,12 +17,12 @@ let ctx: Ctx | undefined; const ctxes: Map = new Map(); -function registerCtxCommand(name: string, factory: (ctx: Ctx) => Cmd, fallback: Cmd | undefined, context: vscode.ExtensionContext) { +function registerCtxCommand(name: string, factory: (ctx: Ctx) => Cmd, fallback: Cmd | undefined, context: vscode.ExtensionContext) { const fullName = `rust-analyzer.${name}`; - async function wrapped_cmd(...args: any[]): Promise { + async function wrappedCmd(...args: any[]): Promise { if (ctx) { - let cmd = factory(ctx); + const cmd = factory(ctx); return await cmd(args); } else if (fallback) { return await fallback(args); @@ -30,7 +30,7 @@ function registerCtxCommand(name: string, factory: (ctx: Ctx) => Cmd, fallback: return; } - const d = vscode.commands.registerCommand(fullName, wrapped_cmd); + const d = vscode.commands.registerCommand(fullName, wrappedCmd); context.subscriptions.push(d); } @@ -39,12 +39,12 @@ async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode return; } - let workspaceRoot = vscode.workspace.getWorkspaceFolder(doc.uri); + const workspaceRoot = vscode.workspace.getWorkspaceFolder(doc.uri); if (!workspaceRoot) { return; } - let cargoRoot = await nearestParentWithCargoToml(workspaceRoot.uri, doc.uri); + const cargoRoot = await nearestParentWithCargoToml(workspaceRoot.uri, doc.uri); if (cargoRoot == null) { vscode.window.showWarningMessage("Cargo.toml could not be located"); return; @@ -57,7 +57,7 @@ async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode return; } else { const workspaceOnCargoRoot = createWorkspaceWithNewLocation(workspaceRoot, cargoRoot); - const newCtx = await activate_new(workspaceOnCargoRoot, context); + const newCtx = await activateNew(workspaceOnCargoRoot, context); ctxes.set(cargoRoot.path, newCtx); ctx = newCtx; } @@ -65,8 +65,8 @@ async function whenOpeningTextDocument(doc: vscode.TextDocument, context: vscode } -async function activate_new(workspaceFolder: vscode.WorkspaceFolder, context: vscode.ExtensionContext): Promise { -// Register a "dumb" onEnter command for the case where server fails to +async function activateNew(workspaceFolder: vscode.WorkspaceFolder, context: vscode.ExtensionContext): Promise { + // Register a "dumb" onEnter command for the case where server fails to // start. // // FIXME: refactor command registration code such that commands are @@ -86,7 +86,7 @@ async function activate_new(workspaceFolder: vscode.WorkspaceFolder, context: vs const serverPath = await bootstrap(config, state); - let ctx = await Ctx.create(config, context, serverPath, workspaceFolder); + const ctx = await Ctx.create(config, context, serverPath, workspaceFolder); context.subscriptions.push(activateTaskProvider(workspaceFolder)); @@ -142,7 +142,7 @@ export async function activate(context: vscode.ExtensionContext) { vscode.workspace.textDocuments.forEach(doc => whenOpeningTextDocument(doc, context)); function changeConfig() { - for (let ctx of ctxes.values()) { + for (const ctx of ctxes.values()) { ctx.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }); } } @@ -156,7 +156,7 @@ export async function activate(context: vscode.ExtensionContext) { } export async function deactivate() { - for (let ctx of ctxes.values()) { + for (const ctx of ctxes.values()) { await ctx.dispose(); } ctxes.clear(); diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts index 9eec3dd2b000..f440c82722e2 100644 --- a/editors/code/src/tasks.ts +++ b/editors/code/src/tasks.ts @@ -42,7 +42,7 @@ function getStandardCargoTasks(target: vscode.WorkspaceFolder): vscode.Task[] { `cargo ${command}`, 'rust', // What to do when this command is executed. - new vscode.ShellExecution('cargo', [command], { cwd: target.uri.fsPath } ), + new vscode.ShellExecution('cargo', [command], { cwd: target.uri.fsPath }), // Problem matchers. ['$rustc'], ); diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index d353ad482e88..068f4ed60dca 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -92,45 +92,45 @@ export function createWorkspaceWithNewLocation(workspace: vscode.WorkspaceFolder ...workspace, name: path.basename(newLoc.fsPath), uri: newLoc, - }; + }; } // searches up the folder structure until it finds a Cargo.toml export async function nearestParentWithCargoToml( workspaceRootUri: vscode.Uri, fileLoc: vscode.Uri, - ): Promise { - const file_exists: (path: fs.PathLike) => Promise = util.promisify(fs.exists); +): Promise { + const fileExists: (path: fs.PathLike) => Promise = util.promisify(fs.exists); // check that the workspace folder already contains the "Cargo.toml" const workspaceRoot = workspaceRootUri.fsPath; const rootManifest = path.join(workspaceRoot, 'Cargo.toml'); - if (await file_exists(rootManifest)) { - return workspaceRootUri; + if (await fileExists(rootManifest)) { + return workspaceRootUri; } // algorithm that will strip one folder at a time and check if that folder contains "Cargo.toml" let current = fileLoc.fsPath; 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 reached the workspace root - if (workspaceRoot === current) { - break; - } - - // check if "Cargo.toml" is present in the parent folder - const cargoPath = path.join(current, 'Cargo.toml'); - if (await file_exists(cargoPath)) { - // ghetto change the uri on Workspace folder to make vscode think it's located elsewhere - return vscode.Uri.file(current); - } + 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 reached the workspace root + if (workspaceRoot === current) { + break; + } + + // check if "Cargo.toml" is present in the parent folder + const cargoPath = path.join(current, 'Cargo.toml'); + if (await fileExists(cargoPath)) { + // ghetto change the uri on Workspace folder to make vscode think it's located elsewhere + return vscode.Uri.file(current); + } } return null; - } +}