mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 14:21:44 +00:00
Merge #2693
2693: Encapsulate inlay hints activation r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
17dda0972a
6 changed files with 139 additions and 155 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import * as lc from 'vscode-languageclient';
|
||||||
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
import { Ctx, Cmd } from '../ctx';
|
||||||
|
|
||||||
import { analyzerStatus } from './analyzer_status';
|
import { analyzerStatus } from './analyzer_status';
|
||||||
|
@ -7,8 +10,7 @@ import { onEnter } from './on_enter';
|
||||||
import { parentModule } from './parent_module';
|
import { parentModule } from './parent_module';
|
||||||
import { syntaxTree } from './syntax_tree';
|
import { syntaxTree } from './syntax_tree';
|
||||||
import { expandMacro } from './expand_macro';
|
import { expandMacro } from './expand_macro';
|
||||||
import * as inlayHints from './inlay_hints';
|
import { run, runSingle } from './runnables';
|
||||||
import * as runnables from './runnables';
|
|
||||||
|
|
||||||
function collectGarbage(ctx: Ctx): Cmd {
|
function collectGarbage(ctx: Ctx): Cmd {
|
||||||
return async () => {
|
return async () => {
|
||||||
|
@ -16,15 +18,27 @@ function collectGarbage(ctx: Ctx): Cmd {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showReferences(ctx: Ctx): Cmd {
|
||||||
|
return (uri: string, position: lc.Position, locations: lc.Location[]) => {
|
||||||
|
vscode.commands.executeCommand(
|
||||||
|
'editor.action.showReferences',
|
||||||
|
vscode.Uri.parse(uri),
|
||||||
|
ctx.client.protocol2CodeConverter.asPosition(position),
|
||||||
|
locations.map(ctx.client.protocol2CodeConverter.asLocation),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
analyzerStatus,
|
analyzerStatus,
|
||||||
expandMacro,
|
expandMacro,
|
||||||
joinLines,
|
joinLines,
|
||||||
matchingBrace,
|
matchingBrace,
|
||||||
parentModule,
|
parentModule,
|
||||||
runnables,
|
|
||||||
syntaxTree,
|
syntaxTree,
|
||||||
onEnter,
|
onEnter,
|
||||||
inlayHints,
|
|
||||||
collectGarbage,
|
collectGarbage,
|
||||||
|
run,
|
||||||
|
runSingle,
|
||||||
|
showReferences,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
export class LineBuffer {
|
|
||||||
private outBuffer: string = '';
|
|
||||||
|
|
||||||
public processOutput(chunk: string, cb: (line: string) => void) {
|
|
||||||
this.outBuffer += chunk;
|
|
||||||
let eolIndex = this.outBuffer.indexOf('\n');
|
|
||||||
while (eolIndex >= 0) {
|
|
||||||
// line includes the EOL
|
|
||||||
const line = this.outBuffer.slice(0, eolIndex + 1);
|
|
||||||
cb(line);
|
|
||||||
this.outBuffer = this.outBuffer.slice(eolIndex + 1);
|
|
||||||
|
|
||||||
eolIndex = this.outBuffer.indexOf('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,67 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as lc from 'vscode-languageclient';
|
import * as lc from 'vscode-languageclient';
|
||||||
|
|
||||||
import { Server } from '../server';
|
import { Ctx, Cmd } from '../ctx';
|
||||||
|
|
||||||
|
export function run(ctx: Ctx): Cmd {
|
||||||
|
let prevRunnable: RunnableQuickPick | undefined;
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
const editor = ctx.activeRustEditor;
|
||||||
|
if (!editor) return;
|
||||||
|
|
||||||
|
const textDocument: lc.TextDocumentIdentifier = {
|
||||||
|
uri: editor.document.uri.toString(),
|
||||||
|
};
|
||||||
|
const params: RunnablesParams = {
|
||||||
|
textDocument,
|
||||||
|
position: ctx.client.code2ProtocolConverter.asPosition(
|
||||||
|
editor.selection.active,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
const runnables = await ctx.client.sendRequest<Runnable[]>(
|
||||||
|
'rust-analyzer/runnables',
|
||||||
|
params,
|
||||||
|
);
|
||||||
|
const items: RunnableQuickPick[] = [];
|
||||||
|
if (prevRunnable) {
|
||||||
|
items.push(prevRunnable);
|
||||||
|
}
|
||||||
|
for (const r of runnables) {
|
||||||
|
if (
|
||||||
|
prevRunnable &&
|
||||||
|
JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
items.push(new RunnableQuickPick(r));
|
||||||
|
}
|
||||||
|
const item = await vscode.window.showQuickPick(items);
|
||||||
|
if (!item) return;
|
||||||
|
|
||||||
|
item.detail = 'rerun';
|
||||||
|
prevRunnable = item;
|
||||||
|
const task = createTask(item.runnable);
|
||||||
|
return await vscode.tasks.executeTask(task);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runSingle(ctx: Ctx): Cmd {
|
||||||
|
return async (runnable: Runnable) => {
|
||||||
|
const editor = ctx.activeRustEditor;
|
||||||
|
if (!editor) return;
|
||||||
|
|
||||||
|
const task = createTask(runnable);
|
||||||
|
task.group = vscode.TaskGroup.Build;
|
||||||
|
task.presentationOptions = {
|
||||||
|
reveal: vscode.TaskRevealKind.Always,
|
||||||
|
panel: vscode.TaskPanelKind.Dedicated,
|
||||||
|
clear: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
return vscode.tasks.executeTask(task);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface RunnablesParams {
|
interface RunnablesParams {
|
||||||
textDocument: lc.TextDocumentIdentifier;
|
textDocument: lc.TextDocumentIdentifier;
|
||||||
|
@ -67,63 +127,3 @@ function createTask(spec: Runnable): vscode.Task {
|
||||||
t.presentationOptions.clear = true;
|
t.presentationOptions.clear = true;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
let prevRunnable: RunnableQuickPick | undefined;
|
|
||||||
export async function handle(): Promise<vscode.TaskExecution | undefined> {
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
if (editor == null || editor.document.languageId !== 'rust') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const textDocument: lc.TextDocumentIdentifier = {
|
|
||||||
uri: editor.document.uri.toString(),
|
|
||||||
};
|
|
||||||
const params: RunnablesParams = {
|
|
||||||
textDocument,
|
|
||||||
position: Server.client.code2ProtocolConverter.asPosition(
|
|
||||||
editor.selection.active,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
const runnables = await Server.client.sendRequest<Runnable[]>(
|
|
||||||
'rust-analyzer/runnables',
|
|
||||||
params,
|
|
||||||
);
|
|
||||||
const items: RunnableQuickPick[] = [];
|
|
||||||
if (prevRunnable) {
|
|
||||||
items.push(prevRunnable);
|
|
||||||
}
|
|
||||||
for (const r of runnables) {
|
|
||||||
if (
|
|
||||||
prevRunnable &&
|
|
||||||
JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
items.push(new RunnableQuickPick(r));
|
|
||||||
}
|
|
||||||
const item = await vscode.window.showQuickPick(items);
|
|
||||||
if (!item) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.detail = 'rerun';
|
|
||||||
prevRunnable = item;
|
|
||||||
const task = createTask(item.runnable);
|
|
||||||
return await vscode.tasks.executeTask(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleSingle(runnable: Runnable) {
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
if (editor == null || editor.document.languageId !== 'rust') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const task = createTask(runnable);
|
|
||||||
task.group = vscode.TaskGroup.Build;
|
|
||||||
task.presentationOptions = {
|
|
||||||
reveal: vscode.TaskRevealKind.Always,
|
|
||||||
panel: vscode.TaskPanelKind.Dedicated,
|
|
||||||
clear: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return vscode.tasks.executeTask(task);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,49 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { Range, TextDocumentChangeEvent, TextEditor } from 'vscode';
|
import * as lc from 'vscode-languageclient';
|
||||||
import { TextDocumentIdentifier } from 'vscode-languageclient';
|
import { Server } from './server';
|
||||||
import { Server } from '../server';
|
import { Ctx } from './ctx';
|
||||||
|
|
||||||
|
export function activateInlayHints(ctx: Ctx) {
|
||||||
|
const hintsUpdater = new HintsUpdater();
|
||||||
|
hintsUpdater.refreshHintsForVisibleEditors().then(() => {
|
||||||
|
// vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
|
||||||
|
// so update the hints once when the focus changes to guarantee their presence
|
||||||
|
let editorChangeDisposable: vscode.Disposable | null = null;
|
||||||
|
editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor(
|
||||||
|
_ => {
|
||||||
|
if (editorChangeDisposable !== null) {
|
||||||
|
editorChangeDisposable.dispose();
|
||||||
|
}
|
||||||
|
return hintsUpdater.refreshHintsForVisibleEditors();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.pushCleanup(
|
||||||
|
vscode.window.onDidChangeVisibleTextEditors(_ =>
|
||||||
|
hintsUpdater.refreshHintsForVisibleEditors(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
ctx.pushCleanup(
|
||||||
|
vscode.workspace.onDidChangeTextDocument(e =>
|
||||||
|
hintsUpdater.refreshHintsForVisibleEditors(e),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
ctx.pushCleanup(
|
||||||
|
vscode.workspace.onDidChangeConfiguration(_ =>
|
||||||
|
hintsUpdater.toggleHintsDisplay(
|
||||||
|
Server.config.displayInlayHints,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
interface InlayHintsParams {
|
interface InlayHintsParams {
|
||||||
textDocument: TextDocumentIdentifier;
|
textDocument: lc.TextDocumentIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InlayHint {
|
interface InlayHint {
|
||||||
range: Range;
|
range: vscode.Range;
|
||||||
kind: string;
|
kind: string;
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +54,7 @@ const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export class HintsUpdater {
|
class HintsUpdater {
|
||||||
private displayHints = true;
|
private displayHints = true;
|
||||||
|
|
||||||
public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
|
public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
|
||||||
|
@ -32,11 +67,10 @@ export class HintsUpdater {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async refreshHintsForVisibleEditors(
|
public async refreshHintsForVisibleEditors(
|
||||||
cause?: TextDocumentChangeEvent,
|
cause?: vscode.TextDocumentChangeEvent,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!this.displayHints) {
|
if (!this.displayHints) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
cause !== undefined &&
|
cause !== undefined &&
|
||||||
(cause.contentChanges.length === 0 ||
|
(cause.contentChanges.length === 0 ||
|
||||||
|
@ -79,7 +113,7 @@ export class HintsUpdater {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateDecorationsFromServer(
|
private async updateDecorationsFromServer(
|
||||||
editor: TextEditor,
|
editor: vscode.TextEditor,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const newHints = await this.queryHints(editor.document.uri.toString());
|
const newHints = await this.queryHints(editor.document.uri.toString());
|
||||||
if (newHints !== null) {
|
if (newHints !== null) {
|
|
@ -2,8 +2,8 @@ import * as vscode from 'vscode';
|
||||||
import * as lc from 'vscode-languageclient';
|
import * as lc from 'vscode-languageclient';
|
||||||
|
|
||||||
import * as commands from './commands';
|
import * as commands from './commands';
|
||||||
import { HintsUpdater } from './commands/inlay_hints';
|
import { activateInlayHints } from './inlay_hints';
|
||||||
import { StatusDisplay } from './commands/watch_status';
|
import { StatusDisplay } from './status_display';
|
||||||
import * as events from './events';
|
import * as events from './events';
|
||||||
import * as notifications from './notifications';
|
import * as notifications from './notifications';
|
||||||
import { Server } from './server';
|
import { Server } from './server';
|
||||||
|
@ -13,6 +13,8 @@ let ctx!: Ctx;
|
||||||
|
|
||||||
export async function activate(context: vscode.ExtensionContext) {
|
export async function activate(context: vscode.ExtensionContext) {
|
||||||
ctx = new Ctx(context);
|
ctx = new Ctx(context);
|
||||||
|
|
||||||
|
// Commands which invokes manually via command pallet, shortcut, etc.
|
||||||
ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
|
ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
|
||||||
ctx.registerCommand('collectGarbage', commands.collectGarbage);
|
ctx.registerCommand('collectGarbage', commands.collectGarbage);
|
||||||
ctx.registerCommand('matchingBrace', commands.matchingBrace);
|
ctx.registerCommand('matchingBrace', commands.matchingBrace);
|
||||||
|
@ -20,30 +22,11 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
ctx.registerCommand('parentModule', commands.parentModule);
|
ctx.registerCommand('parentModule', commands.parentModule);
|
||||||
ctx.registerCommand('syntaxTree', commands.syntaxTree);
|
ctx.registerCommand('syntaxTree', commands.syntaxTree);
|
||||||
ctx.registerCommand('expandMacro', commands.expandMacro);
|
ctx.registerCommand('expandMacro', commands.expandMacro);
|
||||||
|
ctx.registerCommand('run', commands.run);
|
||||||
|
|
||||||
function disposeOnDeactivation(disposable: vscode.Disposable) {
|
// Internal commands which are invoked by the server.
|
||||||
context.subscriptions.push(disposable);
|
ctx.registerCommand('runSingle', commands.runSingle);
|
||||||
}
|
ctx.registerCommand('showReferences', commands.showReferences);
|
||||||
|
|
||||||
function registerCommand(name: string, f: any) {
|
|
||||||
disposeOnDeactivation(vscode.commands.registerCommand(name, f));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commands are requests from vscode to the language server
|
|
||||||
registerCommand('rust-analyzer.run', commands.runnables.handle);
|
|
||||||
// Unlike the above this does not send requests to the language server
|
|
||||||
registerCommand('rust-analyzer.runSingle', commands.runnables.handleSingle);
|
|
||||||
registerCommand(
|
|
||||||
'rust-analyzer.showReferences',
|
|
||||||
(uri: string, position: lc.Position, locations: lc.Location[]) => {
|
|
||||||
vscode.commands.executeCommand(
|
|
||||||
'editor.action.showReferences',
|
|
||||||
vscode.Uri.parse(uri),
|
|
||||||
Server.client.protocol2CodeConverter.asPosition(position),
|
|
||||||
locations.map(Server.client.protocol2CodeConverter.asLocation),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (Server.config.enableEnhancedTyping) {
|
if (Server.config.enableEnhancedTyping) {
|
||||||
ctx.overrideCommand('type', commands.onEnter);
|
ctx.overrideCommand('type', commands.onEnter);
|
||||||
|
@ -52,7 +35,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
const watchStatus = new StatusDisplay(
|
const watchStatus = new StatusDisplay(
|
||||||
Server.config.cargoWatchOptions.command,
|
Server.config.cargoWatchOptions.command,
|
||||||
);
|
);
|
||||||
disposeOnDeactivation(watchStatus);
|
ctx.pushCleanup(watchStatus);
|
||||||
|
|
||||||
// Notifications are events triggered by the language server
|
// Notifications are events triggered by the language server
|
||||||
const allNotifications: [string, lc.GenericNotificationHandler][] = [
|
const allNotifications: [string, lc.GenericNotificationHandler][] = [
|
||||||
|
@ -84,38 +67,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Server.config.displayInlayHints) {
|
if (Server.config.displayInlayHints) {
|
||||||
const hintsUpdater = new HintsUpdater();
|
activateInlayHints(ctx);
|
||||||
hintsUpdater.refreshHintsForVisibleEditors().then(() => {
|
|
||||||
// vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
|
|
||||||
// so update the hints once when the focus changes to guarantee their presence
|
|
||||||
let editorChangeDisposable: vscode.Disposable | null = null;
|
|
||||||
editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor(
|
|
||||||
_ => {
|
|
||||||
if (editorChangeDisposable !== null) {
|
|
||||||
editorChangeDisposable.dispose();
|
|
||||||
}
|
|
||||||
return hintsUpdater.refreshHintsForVisibleEditors();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
disposeOnDeactivation(
|
|
||||||
vscode.window.onDidChangeVisibleTextEditors(_ =>
|
|
||||||
hintsUpdater.refreshHintsForVisibleEditors(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
disposeOnDeactivation(
|
|
||||||
vscode.workspace.onDidChangeTextDocument(e =>
|
|
||||||
hintsUpdater.refreshHintsForVisibleEditors(e),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
disposeOnDeactivation(
|
|
||||||
vscode.workspace.onDidChangeConfiguration(_ =>
|
|
||||||
hintsUpdater.toggleHintsDisplay(
|
|
||||||
Server.config.displayInlayHints,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as vscode from 'vscode';
|
||||||
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
||||||
|
|
||||||
export class StatusDisplay implements vscode.Disposable {
|
export class StatusDisplay implements vscode.Disposable {
|
||||||
public packageName?: string;
|
packageName?: string;
|
||||||
|
|
||||||
private i = 0;
|
private i = 0;
|
||||||
private statusBarItem: vscode.StatusBarItem;
|
private statusBarItem: vscode.StatusBarItem;
|
||||||
|
@ -19,7 +19,7 @@ export class StatusDisplay implements vscode.Disposable {
|
||||||
this.statusBarItem.hide();
|
this.statusBarItem.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
public show() {
|
show() {
|
||||||
this.packageName = undefined;
|
this.packageName = undefined;
|
||||||
|
|
||||||
this.timer =
|
this.timer =
|
||||||
|
@ -39,7 +39,7 @@ export class StatusDisplay implements vscode.Disposable {
|
||||||
this.statusBarItem.show();
|
this.statusBarItem.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public hide() {
|
hide() {
|
||||||
if (this.timer) {
|
if (this.timer) {
|
||||||
clearInterval(this.timer);
|
clearInterval(this.timer);
|
||||||
this.timer = undefined;
|
this.timer = undefined;
|
||||||
|
@ -48,7 +48,7 @@ export class StatusDisplay implements vscode.Disposable {
|
||||||
this.statusBarItem.hide();
|
this.statusBarItem.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
dispose() {
|
||||||
if (this.timer) {
|
if (this.timer) {
|
||||||
clearInterval(this.timer);
|
clearInterval(this.timer);
|
||||||
this.timer = undefined;
|
this.timer = undefined;
|
||||||
|
@ -57,7 +57,7 @@ export class StatusDisplay implements vscode.Disposable {
|
||||||
this.statusBarItem.dispose();
|
this.statusBarItem.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleProgressNotification(params: ProgressParams) {
|
handleProgressNotification(params: ProgressParams) {
|
||||||
const { token, value } = params;
|
const { token, value } = params;
|
||||||
if (token !== 'rustAnalyzer/cargoWatcher') {
|
if (token !== 'rustAnalyzer/cargoWatcher') {
|
||||||
return;
|
return;
|
Loading…
Add table
Add a link
Reference in a new issue