1 import * as vscode from 'vscode';
2 import * as lc from 'vscode-languageclient';
4 import * as commands from './commands';
5 import { ExpandMacroContentProvider } from './commands/expand_macro';
6 import { HintsUpdater } from './commands/inlay_hints';
7 import { SyntaxTreeContentProvider } from './commands/syntaxTree';
8 import { StatusDisplay } from './commands/watch_status';
9 import * as events from './events';
10 import * as notifications from './notifications';
11 import { Server } from './server';
13 export async function activate(context: vscode.ExtensionContext) {
14 function disposeOnDeactivation(disposable: vscode.Disposable) {
15 context.subscriptions.push(disposable);
18 function registerCommand(name: string, f: any) {
19 disposeOnDeactivation(vscode.commands.registerCommand(name, f));
21 function overrideCommand(
23 f: (...args: any[]) => Promise<boolean>,
25 const defaultCmd = `default:${name}`;
26 const original = (...args: any[]) =>
27 vscode.commands.executeCommand(defaultCmd, ...args);
30 registerCommand(name, async (...args: any[]) => {
31 const editor = vscode.window.activeTextEditor;
35 editor.document.languageId !== 'rust'
37 return await original(...args);
39 if (!(await f(...args))) {
40 return await original(...args);
44 vscode.window.showWarningMessage(
45 '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',
50 // Commands are requests from vscode to the language server
52 'rust-analyzer.analyzerStatus',
53 commands.analyzerStatus.makeCommand(context),
55 registerCommand('rust-analyzer.collectGarbage', () =>
56 Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null),
59 'rust-analyzer.matchingBrace',
60 commands.matchingBrace.handle,
62 registerCommand('rust-analyzer.joinLines', commands.joinLines.handle);
63 registerCommand('rust-analyzer.parentModule', commands.parentModule.handle);
64 registerCommand('rust-analyzer.run', commands.runnables.handle);
65 // Unlike the above this does not send requests to the language server
66 registerCommand('rust-analyzer.runSingle', commands.runnables.handleSingle);
68 'rust-analyzer.applySourceChange',
69 commands.applySourceChange.handle,
72 'rust-analyzer.showReferences',
73 (uri: string, position: lc.Position, locations: lc.Location[]) => {
74 vscode.commands.executeCommand(
75 'editor.action.showReferences',
76 vscode.Uri.parse(uri),
77 Server.client.protocol2CodeConverter.asPosition(position),
78 locations.map(Server.client.protocol2CodeConverter.asLocation),
83 if (Server.config.enableEnhancedTyping) {
84 overrideCommand('type', commands.onEnter.handle);
87 const watchStatus = new StatusDisplay(
88 Server.config.cargoWatchOptions.command,
90 disposeOnDeactivation(watchStatus);
92 // Notifications are events triggered by the language server
93 const allNotifications: Iterable<[
95 lc.GenericNotificationHandler,
98 'rust-analyzer/publishDecorations',
99 notifications.publishDecorations.handle,
103 params => watchStatus.handleProgressNotification(params),
106 const syntaxTreeContentProvider = new SyntaxTreeContentProvider();
107 const expandMacroContentProvider = new ExpandMacroContentProvider();
109 // The events below are plain old javascript events, triggered and handled by vscode
110 vscode.window.onDidChangeActiveTextEditor(
111 events.changeActiveTextEditor.makeHandler(syntaxTreeContentProvider),
114 disposeOnDeactivation(
115 vscode.workspace.registerTextDocumentContentProvider(
117 syntaxTreeContentProvider,
120 disposeOnDeactivation(
121 vscode.workspace.registerTextDocumentContentProvider(
123 expandMacroContentProvider,
128 'rust-analyzer.syntaxTree',
129 commands.syntaxTree.createHandle(syntaxTreeContentProvider),
132 'rust-analyzer.expandMacro',
133 commands.expandMacro.createHandle(expandMacroContentProvider),
136 vscode.workspace.onDidChangeTextDocument(
137 events.changeTextDocument.createHandler(syntaxTreeContentProvider),
139 context.subscriptions,
142 const startServer = () => Server.start(allNotifications);
143 const reloadCommand = () => reloadServer(startServer);
145 vscode.commands.registerCommand('rust-analyzer.reload', reloadCommand);
147 // Start the language server, finally!
151 vscode.window.showErrorMessage(e.message);
154 if (Server.config.displayInlayHints) {
155 const hintsUpdater = new HintsUpdater();
156 hintsUpdater.refreshHintsForVisibleEditors().then(() => {
157 // vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
158 // so update the hints once when the focus changes to guarantee their presence
159 let editorChangeDisposable: vscode.Disposable | null = null;
160 editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor(
162 if (editorChangeDisposable !== null) {
163 editorChangeDisposable.dispose();
165 return hintsUpdater.refreshHintsForVisibleEditors();
169 disposeOnDeactivation(
170 vscode.window.onDidChangeVisibleTextEditors(_ =>
171 hintsUpdater.refreshHintsForVisibleEditors(),
174 disposeOnDeactivation(
175 vscode.workspace.onDidChangeTextDocument(e =>
176 hintsUpdater.refreshHintsForVisibleEditors(e),
179 disposeOnDeactivation(
180 vscode.workspace.onDidChangeConfiguration(_ =>
181 hintsUpdater.toggleHintsDisplay(
182 Server.config.displayInlayHints,
190 export function deactivate(): Thenable<void> {
191 if (!Server.client) {
192 return Promise.resolve();
194 return Server.client.stop();
197 async function reloadServer(startServer: () => Promise<void>) {
198 if (Server.client != null) {
199 vscode.window.showInformationMessage('Reloading rust-analyzer...');
200 await Server.client.stop();