Merge #1586
1586: Add type decorators r=matklad a=SomeoneToIgnore A follow-up of https://github.com/rust-analyzer/rust-analyzer/pull/1549 Now the frontend shows inlay hints as VS Code Decorators: <img width="666" alt="image" src="https://user-images.githubusercontent.com/2690773/61802687-918fcc80-ae39-11e9-97b0-3195ab467393.png"> <img width="893" alt="image" src="https://user-images.githubusercontent.com/2690773/61802688-93599000-ae39-11e9-8bcb-4512e22aa3ed.png"> A few notes on the implementation: * I could not find a normal way to run and display the hints for the file that's already open in the VS Code when it starts. The updating code runs ok, but does not actually show anything. Seems like I miss some event that I could add a handler to. I've also experimented with `setTimeout` and it worked, but this is too ugly. The hints appear now when a new file is open or when some change is done in the existing file. * If there's a `dbg!` used in the lsp_server, the frontend starts receiving change events that contain the string from the `dbg!` output. It should not be the case in a real life, but I've decided to cover this case, just in case. * For bigger files, ~500 lines, the decorators start to blink, when updated, this does not seem to be very much of a problem for me at this particular stage of the feature development and can be optimized later. In the worst case, those decorators can be turned off in settings. * Cursor movement is rather non-intuitive on the right edge of the decorator. Seems like a thing to fix in the VS Code, not in the plugin. Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
commit
4647e89def
5 changed files with 150 additions and 1 deletions
|
|
@ -238,6 +238,11 @@
|
|||
"type": "number",
|
||||
"default": null,
|
||||
"description": "Number of syntax trees rust-analyzer keeps in memory"
|
||||
},
|
||||
"rust-analyzer.displayInlayHints": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Display additional type information in the editor"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -444,6 +449,15 @@
|
|||
"light": "#000000",
|
||||
"highContrast": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ralsp.inlayHint",
|
||||
"description": "Color for inlay hints",
|
||||
"defaults": {
|
||||
"dark": "#A0A0A0F0",
|
||||
"light": "#747474",
|
||||
"highContrast": "#BEBEBE"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import * as analyzerStatus from './analyzer_status';
|
||||
import * as applySourceChange from './apply_source_change';
|
||||
import * as inlayHints from './inlay_hints';
|
||||
import * as joinLines from './join_lines';
|
||||
import * as matchingBrace from './matching_brace';
|
||||
import * as onEnter from './on_enter';
|
||||
|
|
@ -15,5 +16,6 @@ export {
|
|||
parentModule,
|
||||
runnables,
|
||||
syntaxTree,
|
||||
onEnter
|
||||
onEnter,
|
||||
inlayHints
|
||||
};
|
||||
|
|
|
|||
104
editors/code/src/commands/inlay_hints.ts
Normal file
104
editors/code/src/commands/inlay_hints.ts
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
import * as vscode from 'vscode';
|
||||
import { Range, TextDocumentChangeEvent, TextEditor } from 'vscode';
|
||||
import { TextDocumentIdentifier } from 'vscode-languageclient';
|
||||
import { Server } from '../server';
|
||||
|
||||
interface InlayHintsParams {
|
||||
textDocument: TextDocumentIdentifier;
|
||||
}
|
||||
|
||||
interface InlayHint {
|
||||
range: Range;
|
||||
kind: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
|
||||
after: {
|
||||
color: new vscode.ThemeColor('ralsp.inlayHint')
|
||||
}
|
||||
});
|
||||
|
||||
export class HintsUpdater {
|
||||
private displayHints = true;
|
||||
|
||||
public async loadHints(
|
||||
editor: vscode.TextEditor | undefined
|
||||
): Promise<void> {
|
||||
if (
|
||||
this.displayHints &&
|
||||
editor !== undefined &&
|
||||
this.isRustDocument(editor.document)
|
||||
) {
|
||||
await this.updateDecorationsFromServer(
|
||||
editor.document.uri.toString(),
|
||||
editor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
|
||||
if (this.displayHints !== displayHints) {
|
||||
this.displayHints = displayHints;
|
||||
|
||||
if (displayHints) {
|
||||
return this.updateHints();
|
||||
} else {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor != null) {
|
||||
return editor.setDecorations(typeHintDecorationType, []);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async updateHints(cause?: TextDocumentChangeEvent): Promise<void> {
|
||||
if (!this.displayHints) {
|
||||
return;
|
||||
}
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor == null) {
|
||||
return;
|
||||
}
|
||||
const document = cause == null ? editor.document : cause.document;
|
||||
if (!this.isRustDocument(document)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return await this.updateDecorationsFromServer(
|
||||
document.uri.toString(),
|
||||
editor
|
||||
);
|
||||
}
|
||||
|
||||
private isRustDocument(document: vscode.TextDocument): boolean {
|
||||
return document && document.languageId === 'rust';
|
||||
}
|
||||
|
||||
private async updateDecorationsFromServer(
|
||||
documentUri: string,
|
||||
editor: TextEditor
|
||||
): Promise<void> {
|
||||
const newHints = (await this.queryHints(documentUri)) || [];
|
||||
const newDecorations = newHints.map(hint => ({
|
||||
range: hint.range,
|
||||
renderOptions: { after: { contentText: `: ${hint.label}` } }
|
||||
}));
|
||||
return editor.setDecorations(typeHintDecorationType, newDecorations);
|
||||
}
|
||||
|
||||
private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
|
||||
const request: InlayHintsParams = {
|
||||
textDocument: { uri: documentUri }
|
||||
};
|
||||
const client = Server.client;
|
||||
return client
|
||||
.onReady()
|
||||
.then(() =>
|
||||
client.sendRequest<InlayHint[] | null>(
|
||||
'rust-analyzer/inlayHints',
|
||||
request
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ export class Config {
|
|||
public raLspServerPath = RA_LSP_DEBUG || 'ra_lsp_server';
|
||||
public showWorkspaceLoadedNotification = true;
|
||||
public lruCapacity: null | number = null;
|
||||
public displayInlayHints = true;
|
||||
public cargoWatchOptions: CargoWatchOptions = {
|
||||
enableOnStartup: 'ask',
|
||||
trace: 'off',
|
||||
|
|
@ -123,5 +124,9 @@ export class Config {
|
|||
if (config.has('lruCapacity')) {
|
||||
this.lruCapacity = config.get('lruCapacity') as number;
|
||||
}
|
||||
|
||||
if (config.has('displayInlayHints')) {
|
||||
this.displayInlayHints = config.get('displayInlayHints') as boolean;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import * as lc from 'vscode-languageclient';
|
|||
|
||||
import * as commands from './commands';
|
||||
import { CargoWatchProvider } from './commands/cargo_watch';
|
||||
import { HintsUpdater } from './commands/inlay_hints';
|
||||
import {
|
||||
interactivelyStartCargoWatch,
|
||||
startCargoWatch
|
||||
|
|
@ -147,6 +148,29 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
|
||||
// Start the language server, finally!
|
||||
startServer();
|
||||
|
||||
if (Server.config.displayInlayHints) {
|
||||
const hintsUpdater = new HintsUpdater();
|
||||
hintsUpdater.loadHints(vscode.window.activeTextEditor).then(() => {
|
||||
disposeOnDeactivation(
|
||||
vscode.window.onDidChangeActiveTextEditor(editor =>
|
||||
hintsUpdater.loadHints(editor)
|
||||
)
|
||||
);
|
||||
disposeOnDeactivation(
|
||||
vscode.workspace.onDidChangeTextDocument(e =>
|
||||
hintsUpdater.updateHints(e)
|
||||
)
|
||||
);
|
||||
disposeOnDeactivation(
|
||||
vscode.workspace.onDidChangeConfiguration(_ =>
|
||||
hintsUpdater.toggleHintsDisplay(
|
||||
Server.config.displayInlayHints
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function deactivate(): Thenable<void> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue