1 import * as vscode from 'vscode';
2 import * as lc from 'vscode-languageclient';
4 import * as commands from './commands';
5 import { CargoWatchProvider } from './commands/cargo_watch';
6 import { ExpandMacroHoverProvider } from './commands/expand_macro';
7 import { HintsUpdater } from './commands/inlay_hints';
9 interactivelyStartCargoWatch,
11 } from './commands/runnables';
12 import { SyntaxTreeContentProvider } from './commands/syntaxTree';
13 import * as events from './events';
14 import * as notifications from './notifications';
15 import { Server } from './server';
17 export function activate(context: vscode.ExtensionContext) {
18 function disposeOnDeactivation(disposable: vscode.Disposable) {
19 context.subscriptions.push(disposable);
22 function registerCommand(name: string, f: any) {
23 disposeOnDeactivation(vscode.commands.registerCommand(name, f));
25 function overrideCommand(
27 f: (...args: any[]) => Promise<boolean>
29 const defaultCmd = `default:${name}`;
30 const original = (...args: any[]) =>
31 vscode.commands.executeCommand(defaultCmd, ...args);
34 registerCommand(name, async (...args: any[]) => {
35 const editor = vscode.window.activeTextEditor;
39 editor.document.languageId !== 'rust'
41 return await original(...args);
43 if (!(await f(...args))) {
44 return await original(...args);
48 vscode.window.showWarningMessage(
49 'Enhanced typing feature is disabled because of incompatibility with VIM extension, consider turning off rust-analyzer.enableEnhancedTyping: https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/README.md#settings'
54 // Commands are requests from vscode to the language server
56 'rust-analyzer.analyzerStatus',
57 commands.analyzerStatus.makeCommand(context)
59 registerCommand('rust-analyzer.collectGarbage', () =>
60 Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null)
63 'rust-analyzer.matchingBrace',
64 commands.matchingBrace.handle
66 registerCommand('rust-analyzer.joinLines', commands.joinLines.handle);
67 registerCommand('rust-analyzer.parentModule', commands.parentModule.handle);
68 registerCommand('rust-analyzer.run', commands.runnables.handle);
69 // Unlike the above this does not send requests to the language server
70 registerCommand('rust-analyzer.runSingle', commands.runnables.handleSingle);
72 'rust-analyzer.applySourceChange',
73 commands.applySourceChange.handle
76 'rust-analyzer.showReferences',
77 (uri: string, position: lc.Position, locations: lc.Location[]) => {
78 vscode.commands.executeCommand(
79 'editor.action.showReferences',
80 vscode.Uri.parse(uri),
81 Server.client.protocol2CodeConverter.asPosition(position),
82 locations.map(Server.client.protocol2CodeConverter.asLocation)
87 if (Server.config.enableEnhancedTyping) {
88 overrideCommand('type', commands.onEnter.handle);
91 // Notifications are events triggered by the language server
92 const allNotifications: Iterable<
93 [string, lc.GenericNotificationHandler]
96 'rust-analyzer/publishDecorations',
97 notifications.publishDecorations.handle
100 const syntaxTreeContentProvider = new SyntaxTreeContentProvider();
102 // The events below are plain old javascript events, triggered and handled by vscode
103 vscode.window.onDidChangeActiveTextEditor(
104 events.changeActiveTextEditor.makeHandler(syntaxTreeContentProvider)
107 disposeOnDeactivation(
108 vscode.workspace.registerTextDocumentContentProvider(
110 syntaxTreeContentProvider
115 'rust-analyzer.syntaxTree',
116 commands.syntaxTree.createHandle(syntaxTreeContentProvider)
119 vscode.workspace.onDidChangeTextDocument(
120 events.changeTextDocument.createHandler(syntaxTreeContentProvider),
122 context.subscriptions
125 const expandMacroContentProvider = new ExpandMacroHoverProvider();
127 disposeOnDeactivation(
128 vscode.languages.registerHoverProvider(
130 expandMacroContentProvider
134 const startServer = () => Server.start(allNotifications);
135 const reloadCommand = () => reloadServer(startServer);
137 vscode.commands.registerCommand('rust-analyzer.reload', reloadCommand);
139 // Executing `cargo watch` provides us with inline diagnostics on save
140 let provider: CargoWatchProvider | undefined;
141 interactivelyStartCargoWatch(context).then(p => {
144 registerCommand('rust-analyzer.startCargoWatch', () => {
148 startCargoWatch(context).then(p => {
153 registerCommand('rust-analyzer.stopCargoWatch', () => {
159 // Start the language server, finally!
162 if (Server.config.displayInlayHints) {
163 const hintsUpdater = new HintsUpdater();
164 hintsUpdater.refreshHintsForVisibleEditors().then(() => {
165 // vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
166 // so update the hints once when the focus changes to guarantee their presence
167 let editorChangeDisposable: vscode.Disposable | null = null;
168 editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor(
170 if (editorChangeDisposable !== null) {
171 editorChangeDisposable.dispose();
173 return hintsUpdater.refreshHintsForVisibleEditors();
177 disposeOnDeactivation(
178 vscode.window.onDidChangeVisibleTextEditors(_ =>
179 hintsUpdater.refreshHintsForVisibleEditors()
182 disposeOnDeactivation(
183 vscode.workspace.onDidChangeTextDocument(e =>
184 hintsUpdater.refreshHintsForVisibleEditors(e)
187 disposeOnDeactivation(
188 vscode.workspace.onDidChangeConfiguration(_ =>
189 hintsUpdater.toggleHintsDisplay(
190 Server.config.displayInlayHints
198 export function deactivate(): Thenable<void> {
199 if (!Server.client) {
200 return Promise.resolve();
202 return Server.client.stop();
205 async function reloadServer(startServer: () => void) {
206 if (Server.client != null) {
207 vscode.window.showInformationMessage('Reloading rust-analyzer...');
208 await Server.client.stop();