X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=editors%2Fcode%2Fsrc%2Fmain.ts;h=a92c676fa2dd7ddda1b9f5047c9ad9e58707349b;hb=6a0083a519680e8d16bde5d7c1940c8dd6d4e9d4;hp=7b7c19dfcf0b17626707302eb73ece043906b223;hpb=6ef64622afd818d7b091e36b8228bc8ebd52d2e1;p=rust.git diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 7b7c19dfcf0..a92c676fa2d 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -1,21 +1,24 @@ import * as vscode from 'vscode'; import * as path from "path"; import * as os from "os"; -import { promises as fs } from "fs"; +import { promises as fs, PathLike } from "fs"; import * as commands from './commands'; import { activateInlayHints } from './inlay_hints'; import { activateStatusDisplay } from './status_display'; import { Ctx } from './ctx'; -import { activateHighlighting } from './highlighting'; import { Config, NIGHTLY_TAG } from './config'; -import { log, assert } from './util'; +import { log, assert, isValidExecutable } from './util'; import { PersistentState } from './persistent_state'; import { fetchRelease, download } from './net'; -import { spawnSync } from 'child_process'; +import { activateTaskProvider } from './tasks'; +import { setContextValue } from './util'; +import { exec } from 'child_process'; let ctx: Ctx | undefined; +const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; + export async function activate(context: vscode.ExtensionContext) { // Register a "dumb" onEnter command for the case where server fails to // start. @@ -41,28 +44,35 @@ export async function activate(context: vscode.ExtensionContext) { 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); + ctx = await Ctx.create(config, context, serverPath, workspaceFolder.uri.fsPath); + + setContextValue(RUST_PROJECT_CONTEXT_NAME, true); // Commands which invokes manually via command palette, shortcut, etc. - ctx.registerCommand('reload', (ctx) => { - return async () => { - vscode.window.showInformationMessage('Reloading rust-analyzer...'); - // @DanTup maneuver - // https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895 - await deactivate(); - for (const sub of ctx.subscriptions) { - try { - sub.dispose(); - } catch (e) { - log.error(e); - } + + // Reloading is inspired by @DanTup maneuver: https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895 + ctx.registerCommand('reload', _ => async () => { + void vscode.window.showInformationMessage('Reloading rust-analyzer...'); + await deactivate(); + while (context.subscriptions.length > 0) { + try { + context.subscriptions.pop()!.dispose(); + } catch (err) { + log.error("Dispose error:", err); } - await activate(context); - }; + } + await activate(context).catch(log.error); }); ctx.registerCommand('analyzerStatus', commands.analyzerStatus); @@ -73,30 +83,40 @@ export async function activate(context: vscode.ExtensionContext) { ctx.registerCommand('syntaxTree', commands.syntaxTree); ctx.registerCommand('expandMacro', commands.expandMacro); ctx.registerCommand('run', commands.run); + ctx.registerCommand('debug', commands.debug); + ctx.registerCommand('newDebugConfig', commands.newDebugConfig); defaultOnEnter.dispose(); ctx.registerCommand('onEnter', commands.onEnter); ctx.registerCommand('ssr', commands.ssr); ctx.registerCommand('serverVersion', commands.serverVersion); + ctx.registerCommand('toggleInlayHints', commands.toggleInlayHints); // 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.registerCommand('applySnippetWorkspaceEdit', commands.applySnippetWorkspaceEditCommand); + ctx.registerCommand('resolveCodeAction', commands.resolveCodeAction); + ctx.registerCommand('applyActionGroup', commands.applyActionGroup); + + ctx.pushCleanup(activateTaskProvider(workspaceFolder)); activateStatusDisplay(ctx); - if (!ctx.config.highlightingSemanticTokens) { - activateHighlighting(ctx); - } activateInlayHints(ctx); + + vscode.workspace.onDidChangeConfiguration( + _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), + null, + ctx.subscriptions, + ); } export async function deactivate() { - await ctx?.client?.stop(); + setContextValue(RUST_PROJECT_CONTEXT_NAME, undefined); + await ctx?.client.stop(); ctx = undefined; } @@ -110,11 +130,13 @@ async function bootstrap(config: Config, state: PersistentState): Promise { - if (config.package.releaseTag === undefined) return; + if (config.package.releaseTag === null) return; if (config.channel === "stable") { if (config.package.releaseTag === NIGHTLY_TAG) { - vscode.window.showWarningMessage(`You are running a nightly version of rust-analyzer extension. -To switch to stable, uninstall the extension and re-install it from the marketplace`); + void vscode.window.showWarningMessage( + `You are running a nightly version of rust-analyzer extension. ` + + `To switch to stable, uninstall the extension and re-install it from the marketplace` + ); } return; }; @@ -165,18 +187,55 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise< ); } - const res = spawnSync(path, ["--version"], { encoding: 'utf8' }); - log.debug("Checked binary availability via --version", res); - log.debug(res, "--version output:", res.output); - if (res.status !== 0) { - throw new Error( - `Failed to execute ${path} --version` - ); + log.debug("Using server binary at", path); + + if (!isValidExecutable(path)) { + throw new Error(`Failed to execute ${path} --version`); } return path; } +async function patchelf(dest: PathLike): Promise { + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Patching rust-analyzer for NixOS" + }, + async (progress, _) => { + const expression = ` + {src, pkgs ? import {}}: + pkgs.stdenv.mkDerivation { + name = "rust-analyzer"; + inherit src; + phases = [ "installPhase" "fixupPhase" ]; + installPhase = "cp $src $out"; + fixupPhase = '' + chmod 755 $out + patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out + ''; + } + `; + const origFile = dest + "-orig"; + await fs.rename(dest, origFile); + progress.report({ message: "Patching executable", increment: 20 }); + await new Promise((resolve, reject) => { + const handle = exec(`nix-build -E - --arg src '${origFile}' -o ${dest}`, + (err, stdout, stderr) => { + if (err != null) { + reject(Error(stderr)); + } else { + resolve(stdout); + } + }); + handle.stdin?.write(expression); + handle.stdin?.end(); + }); + await fs.unlink(origFile); + } + ); +} + async function getServer(config: Config, state: PersistentState): Promise { const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; if (explicitPath) { @@ -185,10 +244,10 @@ async function getServer(config: Config, state: PersistentState): Promise true).catch(_ => false)) { + await patchelf(dest); + } + await state.updateServerVersion(config.package.version); return dest; }