2019-12-30 13:42:59 +00:00
import * as vscode from "vscode" ;
2024-07-23 17:34:03 +00:00
import type * as lc from "vscode-languageclient/node" ;
2020-07-02 10:37:04 +00:00
import * as ra from "./lsp_ext" ;
2020-02-02 21:23:01 +00:00
2023-04-03 01:37:07 +00:00
import { Config , prepareVSCodeConfig } from "./config" ;
import { createClient } from "./client" ;
2023-03-09 20:27:24 +00:00
import {
2023-04-05 17:57:01 +00:00
isDocumentInWorkspace ,
2023-03-09 20:27:24 +00:00
isRustDocument ,
isRustEditor ,
LazyOutputChannel ,
log ,
2023-07-10 21:10:00 +00:00
type RustEditor ,
2022-07-17 15:38:56 +00:00
} from "./util" ;
2023-07-10 21:10:00 +00:00
import type { ServerStatusParams } from "./lsp_ext" ;
2022-07-17 15:38:56 +00:00
import {
2023-07-10 21:10:00 +00:00
type Dependency ,
type DependencyFile ,
2022-07-17 15:38:56 +00:00
RustDependenciesProvider ,
2023-07-10 21:10:00 +00:00
type DependencyId ,
2022-07-17 15:38:56 +00:00
} from "./dependencies_provider" ;
import { execRevealDependency } from "./commands" ;
2023-04-03 01:37:07 +00:00
import { PersistentState } from "./persistent_state" ;
import { bootstrap } from "./bootstrap" ;
2024-03-01 10:10:29 +00:00
import { prepareTestExplorer } from "./test_explorer" ;
2024-06-07 12:20:05 +00:00
import { spawn } from "node:child_process" ;
import { text } from "node:stream/consumers" ;
2024-07-23 17:34:03 +00:00
import type { RustAnalyzerExtensionApi } from "./main" ;
2019-12-30 13:42:59 +00:00
2022-10-28 23:28:32 +00:00
// We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
// only those are in use. We use "Empty" to represent these scenarios
// (r-a still somewhat works with Live Share, because commands are tunneled to the host)
2021-05-23 13:22:13 +00:00
export type Workspace =
2022-10-28 22:44:37 +00:00
| { kind : "Empty" }
2021-05-23 13:22:13 +00:00
| {
2023-09-05 19:45:52 +00:00
kind : "Workspace Folder" ;
}
2022-05-17 17:15:06 +00:00
| {
2023-09-05 19:45:52 +00:00
kind : "Detached Files" ;
files : vscode.TextDocument [ ] ;
} ;
2021-05-23 13:22:13 +00:00
2022-10-28 23:28:32 +00:00
export function fetchWorkspace ( ) : Workspace {
const folders = ( vscode . workspace . workspaceFolders || [ ] ) . filter (
2023-07-11 13:35:10 +00:00
( folder ) = > folder . uri . scheme === "file" ,
2022-10-28 23:28:32 +00:00
) ;
const rustDocuments = vscode . workspace . textDocuments . filter ( ( document ) = >
2023-07-11 13:35:10 +00:00
isRustDocument ( document ) ,
2022-10-28 23:28:32 +00:00
) ;
return folders . length === 0
? rustDocuments . length === 0
2023-04-03 01:37:07 +00:00
? { kind : "Empty" }
2022-10-28 23:28:32 +00:00
: {
2023-09-05 19:45:52 +00:00
kind : "Detached Files" ,
files : rustDocuments ,
}
2023-04-03 01:37:07 +00:00
: { kind : "Workspace Folder" } ;
2022-10-28 23:28:32 +00:00
}
2022-10-21 14:00:43 +00:00
export type CommandFactory = {
2022-10-28 22:44:37 +00:00
enabled : ( ctx : CtxInit ) = > Cmd ;
2022-10-21 14:00:43 +00:00
disabled ? : ( ctx : Ctx ) = > Cmd ;
} ;
2022-10-28 22:44:37 +00:00
export type CtxInit = Ctx & {
readonly client : lc.LanguageClient ;
} ;
2023-10-17 15:29:11 +00:00
export class Ctx implements RustAnalyzerExtensionApi {
2022-10-17 12:20:14 +00:00
readonly statusBar : vscode.StatusBarItem ;
2024-07-23 17:34:03 +00:00
readonly config : Config ;
2022-10-28 22:44:37 +00:00
readonly workspace : Workspace ;
2024-06-07 12:20:05 +00:00
readonly version : string ;
2022-10-17 12:53:46 +00:00
2022-10-28 22:44:37 +00:00
private _client : lc.LanguageClient | undefined ;
2022-10-17 13:05:20 +00:00
private _serverPath : string | undefined ;
private traceOutputChannel : vscode.OutputChannel | undefined ;
2024-03-06 18:10:50 +00:00
private testController : vscode.TestController | undefined ;
2022-10-17 13:05:20 +00:00
private outputChannel : vscode.OutputChannel | undefined ;
2022-10-21 14:00:43 +00:00
private clientSubscriptions : Disposable [ ] ;
2022-10-17 13:05:20 +00:00
private state : PersistentState ;
2022-10-21 14:00:43 +00:00
private commandFactories : Record < string , CommandFactory > ;
private commandDisposables : Disposable [ ] ;
2023-03-16 15:26:19 +00:00
private unlinkedFiles : vscode.Uri [ ] ;
2023-04-03 00:58:20 +00:00
private _dependencies : RustDependenciesProvider | undefined ;
private _treeView : vscode.TreeView < Dependency | DependencyFile | DependencyId > | undefined ;
2023-08-12 06:25:51 +00:00
private lastStatus : ServerStatusParams | { health : "stopped" } = { health : "stopped" } ;
2024-06-07 12:20:05 +00:00
private _serverVersion : string ;
get serverPath ( ) : string | undefined {
return this . _serverPath ;
}
get serverVersion ( ) : string | undefined {
return this . _serverVersion ;
}
2022-10-17 12:20:14 +00:00
2022-10-28 22:44:37 +00:00
get client() {
return this . _client ;
}
2022-10-17 12:20:14 +00:00
2023-04-03 00:58:20 +00:00
get treeView() {
return this . _treeView ;
}
get dependencies() {
return this . _dependencies ;
}
2022-10-21 14:00:43 +00:00
constructor (
readonly extCtx : vscode.ExtensionContext ,
2022-10-28 22:44:37 +00:00
commandFactories : Record < string , CommandFactory > ,
2023-07-11 13:35:10 +00:00
workspace : Workspace ,
2022-10-21 14:00:43 +00:00
) {
2022-10-20 19:12:58 +00:00
extCtx . subscriptions . push ( this ) ;
2024-06-07 12:20:05 +00:00
this . version = extCtx . extension . packageJSON . version ? ? "<unknown>" ;
this . _serverVersion = "<not running>" ;
2024-07-06 18:20:21 +00:00
this . config = new Config ( extCtx . subscriptions ) ;
2022-10-21 14:00:43 +00:00
this . statusBar = vscode . window . createStatusBarItem ( vscode . StatusBarAlignment . Left ) ;
2024-03-06 18:10:50 +00:00
if ( this . config . testExplorer ) {
this . testController = vscode . tests . createTestController (
"rustAnalyzerTestController" ,
"Rust Analyzer test controller" ,
) ;
}
2022-10-17 12:20:14 +00:00
this . workspace = workspace ;
2022-10-21 14:00:43 +00:00
this . clientSubscriptions = [ ] ;
this . commandDisposables = [ ] ;
this . commandFactories = commandFactories ;
2023-03-16 15:26:19 +00:00
this . unlinkedFiles = [ ] ;
2022-10-17 12:53:46 +00:00
this . state = new PersistentState ( extCtx . globalState ) ;
2022-10-21 14:00:43 +00:00
2023-04-03 01:37:07 +00:00
this . updateCommands ( "disable" ) ;
2022-10-28 22:44:37 +00:00
this . setServerStatus ( {
health : "stopped" ,
} ) ;
2022-10-17 12:20:14 +00:00
}
2022-10-20 19:12:58 +00:00
dispose() {
this . config . dispose ( ) ;
2022-10-21 14:00:43 +00:00
this . statusBar . dispose ( ) ;
2024-03-06 18:10:50 +00:00
this . testController ? . dispose ( ) ;
2022-10-21 14:00:43 +00:00
void this . disposeClient ( ) ;
this . commandDisposables . forEach ( ( disposable ) = > disposable . dispose ( ) ) ;
2022-10-20 19:12:58 +00:00
}
2022-10-28 23:28:32 +00:00
async onWorkspaceFolderChanges() {
const workspace = fetchWorkspace ( ) ;
if ( workspace . kind === "Detached Files" && this . workspace . kind === "Detached Files" ) {
if ( workspace . files !== this . workspace . files ) {
if ( this . client ? . isRunning ( ) ) {
// Ideally we wouldn't need to tear down the server here, but currently detached files
// are only specified at server start
await this . stopAndDispose ( ) ;
await this . start ( ) ;
}
return ;
}
}
if ( workspace . kind === "Workspace Folder" && this . workspace . kind === "Workspace Folder" ) {
return ;
}
if ( workspace . kind === "Empty" ) {
await this . stopAndDispose ( ) ;
return ;
}
if ( this . client ? . isRunning ( ) ) {
await this . restart ( ) ;
}
}
2022-10-28 22:44:37 +00:00
private async getOrCreateClient() {
if ( this . workspace . kind === "Empty" ) {
return ;
}
2022-10-17 12:20:14 +00:00
if ( ! this . traceOutputChannel ) {
2023-01-31 14:43:47 +00:00
this . traceOutputChannel = new LazyOutputChannel ( "Rust Analyzer Language Server Trace" ) ;
2022-10-17 14:01:39 +00:00
this . pushExtCleanup ( this . traceOutputChannel ) ;
2022-10-17 12:20:14 +00:00
}
if ( ! this . outputChannel ) {
this . outputChannel = vscode . window . createOutputChannel ( "Rust Analyzer Language Server" ) ;
2022-10-17 14:01:39 +00:00
this . pushExtCleanup ( this . outputChannel ) ;
2022-10-17 12:20:14 +00:00
}
2022-10-17 12:53:46 +00:00
2022-10-28 22:44:37 +00:00
if ( ! this . _client ) {
2024-07-22 08:49:32 +00:00
this . _serverPath = await this . bootstrap ( ) ;
2024-06-07 12:20:05 +00:00
text ( spawn ( this . _serverPath , [ "--version" ] ) . stdout . setEncoding ( "utf-8" ) ) . then (
( data ) = > {
const prefix = ` rust-analyzer ` ;
this . _serverVersion = data
. slice ( data . startsWith ( prefix ) ? prefix.length : 0 )
. trim ( ) ;
this . refreshServerStatus ( ) ;
} ,
( _ ) = > {
this . _serverVersion = "<unknown>" ;
this . refreshServerStatus ( ) ;
} ,
) ;
2023-01-24 12:43:56 +00:00
const newEnv = Object . assign ( { } , process . env , this . config . serverExtraEnv ) ;
2022-10-17 12:20:14 +00:00
const run : lc.Executable = {
2022-10-17 13:05:20 +00:00
command : this._serverPath ,
2023-04-03 01:37:07 +00:00
options : { env : newEnv } ,
2022-10-17 12:20:14 +00:00
} ;
2022-10-17 12:53:46 +00:00
const serverOptions = {
2022-10-17 12:20:14 +00:00
run ,
debug : run ,
} ;
2022-10-17 12:53:46 +00:00
2022-10-17 12:20:14 +00:00
let rawInitializationOptions = vscode . workspace . getConfiguration ( "rust-analyzer" ) ;
if ( this . workspace . kind === "Detached Files" ) {
rawInitializationOptions = {
detachedFiles : this.workspace.files.map ( ( file ) = > file . uri . fsPath ) ,
. . . rawInitializationOptions ,
} ;
}
2024-07-23 17:34:03 +00:00
const initializationOptions = prepareVSCodeConfig ( rawInitializationOptions ) ;
2022-10-17 12:20:14 +00:00
2022-10-28 22:44:37 +00:00
this . _client = await createClient (
2022-10-17 12:20:14 +00:00
this . traceOutputChannel ,
this . outputChannel ,
initializationOptions ,
2022-11-18 18:47:45 +00:00
serverOptions ,
2023-03-16 15:26:19 +00:00
this . config ,
2023-07-11 13:35:10 +00:00
this . unlinkedFiles ,
2022-10-17 12:20:14 +00:00
) ;
2022-10-21 14:00:43 +00:00
this . pushClientCleanup (
2022-10-28 22:44:37 +00:00
this . _client . onNotification ( ra . serverStatus , ( params ) = >
2023-07-11 13:35:10 +00:00
this . setServerStatus ( params ) ,
) ,
2022-10-21 14:00:43 +00:00
) ;
2023-01-23 12:10:25 +00:00
this . pushClientCleanup (
this . _client . onNotification ( ra . openServerLogs , ( ) = > {
this . outputChannel ! . show ( ) ;
2023-07-11 13:35:10 +00:00
} ) ,
2023-01-23 12:10:25 +00:00
) ;
2022-10-17 12:20:14 +00:00
}
2022-10-28 22:44:37 +00:00
return this . _client ;
2022-10-17 12:20:14 +00:00
}
2024-07-22 08:49:32 +00:00
private async bootstrap ( ) : Promise < string > {
return bootstrap ( this . extCtx , this . config , this . state ) . catch ( ( err ) = > {
let message = "bootstrap error. " ;
message +=
'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ' ;
2024-07-28 04:43:35 +00:00
message +=
'To enable verbose logs, click the gear icon in the "OUTPUT" tab and select "Debug".' ;
2024-07-22 08:49:32 +00:00
log . error ( "Bootstrap error" , err ) ;
throw new Error ( message ) ;
} ) ;
}
2022-10-28 23:28:32 +00:00
async start() {
log . info ( "Starting language client" ) ;
2022-10-28 22:44:37 +00:00
const client = await this . getOrCreateClient ( ) ;
if ( ! client ) {
return ;
}
2022-10-17 12:20:14 +00:00
await client . start ( ) ;
2022-10-21 14:00:43 +00:00
this . updateCommands ( ) ;
2023-05-26 15:50:07 +00:00
2024-03-06 18:10:50 +00:00
if ( this . testController ) {
prepareTestExplorer ( this , this . testController , client ) ;
}
2023-05-26 15:50:07 +00:00
if ( this . config . showDependenciesExplorer ) {
this . prepareTreeDependenciesView ( client ) ;
}
2023-04-03 00:58:20 +00:00
}
private prepareTreeDependenciesView ( client : lc.LanguageClient ) {
const ctxInit : CtxInit = {
. . . this ,
2023-04-03 01:37:07 +00:00
client : client ,
2023-04-03 00:58:20 +00:00
} ;
2023-04-05 17:57:01 +00:00
this . _dependencies = new RustDependenciesProvider ( ctxInit ) ;
2023-04-03 00:58:20 +00:00
this . _treeView = vscode . window . createTreeView ( "rustDependencies" , {
treeDataProvider : this._dependencies ,
showCollapseAll : true ,
} ) ;
2023-04-05 17:57:01 +00:00
this . pushExtCleanup ( this . _treeView ) ;
2023-04-08 17:18:29 +00:00
vscode . window . onDidChangeActiveTextEditor ( async ( e ) = > {
2023-04-05 17:57:01 +00:00
// we should skip documents that belong to the current workspace
2023-04-08 17:18:29 +00:00
if ( this . shouldRevealDependency ( e ) ) {
try {
await execRevealDependency ( e ) ;
} catch ( reason ) {
await vscode . window . showErrorMessage ( ` Dependency error: ${ reason } ` ) ;
}
}
} ) ;
this . treeView ? . onDidChangeVisibility ( async ( e ) = > {
if ( e . visible ) {
const activeEditor = vscode . window . activeTextEditor ;
if ( this . shouldRevealDependency ( activeEditor ) ) {
try {
await execRevealDependency ( activeEditor ) ;
} catch ( reason ) {
await vscode . window . showErrorMessage ( ` Dependency error: ${ reason } ` ) ;
}
}
2023-04-03 00:58:20 +00:00
}
} ) ;
2022-10-17 12:20:14 +00:00
}
2023-04-08 17:18:29 +00:00
private shouldRevealDependency ( e : vscode.TextEditor | undefined ) : e is RustEditor {
return (
e !== undefined &&
isRustEditor ( e ) &&
! isDocumentInWorkspace ( e . document ) &&
( this . treeView ? . visible || false )
) ;
}
2022-10-28 23:28:32 +00:00
async restart() {
// FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
await this . stopAndDispose ( ) ;
await this . start ( ) ;
}
async stop() {
2022-10-28 22:44:37 +00:00
if ( ! this . _client ) {
return ;
}
2022-10-28 23:28:32 +00:00
log . info ( "Stopping language client" ) ;
2022-10-28 22:44:37 +00:00
this . updateCommands ( "disable" ) ;
await this . _client . stop ( ) ;
2022-10-17 12:20:14 +00:00
}
2022-10-28 23:28:32 +00:00
async stopAndDispose() {
2022-10-28 22:44:37 +00:00
if ( ! this . _client ) {
return ;
}
2022-10-28 23:28:32 +00:00
log . info ( "Disposing language client" ) ;
2022-10-28 22:44:37 +00:00
this . updateCommands ( "disable" ) ;
2022-10-21 14:00:43 +00:00
await this . disposeClient ( ) ;
}
private async disposeClient() {
this . clientSubscriptions ? . forEach ( ( disposable ) = > disposable . dispose ( ) ) ;
this . clientSubscriptions = [ ] ;
2022-10-28 22:44:37 +00:00
await this . _client ? . dispose ( ) ;
2022-10-17 13:05:20 +00:00
this . _serverPath = undefined ;
2022-10-28 22:44:37 +00:00
this . _client = undefined ;
2020-02-17 13:11:01 +00:00
}
2019-12-31 17:14:00 +00:00
2020-03-07 12:07:44 +00:00
get activeRustEditor ( ) : RustEditor | undefined {
2019-12-30 14:20:13 +00:00
const editor = vscode . window . activeTextEditor ;
2020-03-07 12:07:44 +00:00
return editor && isRustEditor ( editor ) ? editor : undefined ;
2019-12-30 14:20:13 +00:00
}
2021-08-10 13:35:37 +00:00
get extensionPath ( ) : string {
return this . extCtx . extensionPath ;
}
2020-02-02 21:23:01 +00:00
get subscriptions ( ) : Disposable [ ] {
2019-12-30 18:05:41 +00:00
return this . extCtx . subscriptions ;
}
2022-10-28 22:44:37 +00:00
private updateCommands ( forceDisable ? : "disable" ) {
2022-10-21 14:00:43 +00:00
this . commandDisposables . forEach ( ( disposable ) = > disposable . dispose ( ) ) ;
this . commandDisposables = [ ] ;
2022-10-28 22:44:37 +00:00
const clientRunning = ( ! forceDisable && this . _client ? . isRunning ( ) ) ? ? false ;
const isClientRunning = function ( _ctx : Ctx ) : _ctx is CtxInit {
return clientRunning ;
2022-10-21 14:00:43 +00:00
} ;
2022-10-28 22:44:37 +00:00
2022-10-21 14:00:43 +00:00
for ( const [ name , factory ] of Object . entries ( this . commandFactories ) ) {
const fullName = ` rust-analyzer. ${ name } ` ;
2022-10-28 22:44:37 +00:00
let callback ;
if ( isClientRunning ( this ) ) {
// we asserted that `client` is defined
callback = factory . enabled ( this ) ;
} else if ( factory . disabled ) {
callback = factory . disabled ( this ) ;
} else {
callback = ( ) = >
vscode . window . showErrorMessage (
2023-07-11 13:35:10 +00:00
` command ${ fullName } failed: rust-analyzer server is not running ` ,
2022-10-28 22:44:37 +00:00
) ;
}
2022-10-21 14:00:43 +00:00
this . commandDisposables . push ( vscode . commands . registerCommand ( fullName , callback ) ) ;
}
}
2022-10-28 21:10:10 +00:00
setServerStatus ( status : ServerStatusParams | { health : "stopped" } ) {
2023-08-12 06:25:51 +00:00
this . lastStatus = status ;
this . updateStatusBarItem ( ) ;
}
refreshServerStatus() {
this . updateStatusBarItem ( ) ;
}
private updateStatusBarItem() {
2021-04-06 11:16:35 +00:00
let icon = "" ;
2023-08-12 06:25:51 +00:00
const status = this . lastStatus ;
2022-07-13 11:16:35 +00:00
const statusBar = this . statusBar ;
2023-03-20 20:24:53 +00:00
statusBar . show ( ) ;
2023-03-10 09:13:30 +00:00
statusBar . tooltip = new vscode . MarkdownString ( "" , true ) ;
statusBar . tooltip . isTrusted = true ;
2021-04-06 11:16:35 +00:00
switch ( status . health ) {
case "ok" :
2022-07-13 11:16:35 +00:00
statusBar . color = undefined ;
statusBar . backgroundColor = undefined ;
2023-10-04 04:44:03 +00:00
if ( this . config . statusBarClickAction === "stopServer" ) {
statusBar . command = "rust-analyzer.stopServer" ;
} else {
statusBar . command = "rust-analyzer.openLogs" ;
}
2023-04-03 00:58:20 +00:00
this . dependencies ? . refresh ( ) ;
2020-07-02 10:37:04 +00:00
break ;
2021-04-06 11:16:35 +00:00
case "warning" :
2022-07-13 11:16:35 +00:00
statusBar . color = new vscode . ThemeColor ( "statusBarItem.warningForeground" ) ;
statusBar . backgroundColor = new vscode . ThemeColor (
2023-07-11 13:35:10 +00:00
"statusBarItem.warningBackground" ,
2022-05-26 10:31:07 +00:00
) ;
2023-03-13 11:32:53 +00:00
statusBar . command = "rust-analyzer.openLogs" ;
2021-04-06 11:16:35 +00:00
icon = "$(warning) " ;
break ;
case "error" :
2022-07-13 11:16:35 +00:00
statusBar . color = new vscode . ThemeColor ( "statusBarItem.errorForeground" ) ;
statusBar . backgroundColor = new vscode . ThemeColor ( "statusBarItem.errorBackground" ) ;
2023-03-13 11:32:53 +00:00
statusBar . command = "rust-analyzer.openLogs" ;
2021-04-06 11:16:35 +00:00
icon = "$(error) " ;
2020-07-02 10:37:04 +00:00
break ;
2022-10-28 21:10:10 +00:00
case "stopped" :
2023-03-10 09:13:30 +00:00
statusBar . tooltip . appendText ( "Server is stopped" ) ;
statusBar . tooltip . appendMarkdown (
2023-07-11 13:35:10 +00:00
"\n\n[Start server](command:rust-analyzer.startServer)" ,
2023-03-10 09:13:30 +00:00
) ;
2023-08-04 18:07:22 +00:00
statusBar . color = new vscode . ThemeColor ( "statusBarItem.warningForeground" ) ;
statusBar . backgroundColor = new vscode . ThemeColor (
"statusBarItem.warningBackground" ,
) ;
2023-03-13 11:32:53 +00:00
statusBar . command = "rust-analyzer.startServer" ;
2023-08-12 06:25:51 +00:00
statusBar . text = "$(stop-circle) rust-analyzer" ;
2022-10-28 21:10:10 +00:00
return ;
2020-07-02 10:37:04 +00:00
}
2024-04-26 09:06:52 +00:00
if ( status . message ) {
statusBar . tooltip . appendText ( status . message ) ;
}
2023-03-10 09:13:30 +00:00
if ( statusBar . tooltip . value ) {
2023-07-30 12:35:20 +00:00
statusBar . tooltip . appendMarkdown ( "\n\n---\n\n" ) ;
2023-03-10 09:13:30 +00:00
}
2024-06-07 12:20:05 +00:00
const toggleCheckOnSave = this . config . checkOnSave ? "Disable" : "Enable" ;
2023-04-28 19:34:31 +00:00
statusBar . tooltip . appendMarkdown (
2024-07-22 08:49:32 +00:00
` [Extension Info](command:rust-analyzer.serverVersion "Show version and server binary info"): Version ${ this . version } , Server Version ${ this . _serverVersion } ` +
2024-06-07 12:20:05 +00:00
"\n\n---\n\n" +
'[$(terminal) Open Logs](command:rust-analyzer.openLogs "Open the server logs")' +
"\n\n" +
` [ $ (settings) ${ toggleCheckOnSave } Check on Save](command:rust-analyzer.toggleCheckOnSave "Temporarily ${ toggleCheckOnSave . toLowerCase ( ) } check on save functionality") ` +
"\n\n" +
'[$(refresh) Reload Workspace](command:rust-analyzer.reloadWorkspace "Reload and rediscover workspaces")' +
"\n\n" +
'[$(symbol-property) Rebuild Build Dependencies](command:rust-analyzer.rebuildProcMacros "Rebuild build scripts and proc-macros")' +
"\n\n" +
'[$(stop-circle) Stop server](command:rust-analyzer.stopServer "Stop the server")' +
"\n\n" +
'[$(debug-restart) Restart server](command:rust-analyzer.restartServer "Restart the server")' ,
2023-04-28 19:34:31 +00:00
) ;
2024-06-07 12:20:05 +00:00
if ( ! status . quiescent ) icon = "$(loading~spin) " ;
2022-07-13 11:16:35 +00:00
statusBar . text = ` ${ icon } rust-analyzer ` ;
2020-07-02 10:37:04 +00:00
}
2022-10-17 12:20:14 +00:00
pushExtCleanup ( d : Disposable ) {
2019-12-30 14:11:30 +00:00
this . extCtx . subscriptions . push ( d ) ;
2019-12-30 13:42:59 +00:00
}
2022-10-21 14:00:43 +00:00
2024-03-01 10:10:29 +00:00
pushClientCleanup ( d : Disposable ) {
2022-10-21 14:00:43 +00:00
this . clientSubscriptions . push ( d ) ;
}
2019-12-30 13:42:59 +00:00
}
2019-12-30 13:53:43 +00:00
2020-02-02 21:23:01 +00:00
export interface Disposable {
dispose ( ) : void ;
}
2022-02-26 00:37:55 +00:00
2023-04-27 01:02:38 +00:00
export type Cmd = ( . . . args : any [ ] ) = > unknown ;