2693: Encapsulate inlay hints activation r=matklad a=matklad



Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2019-12-30 19:25:01 +00:00 committed by GitHub
commit 17dda0972a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 139 additions and 155 deletions

View File

@ -1,3 +1,6 @@
import * as vscode from 'vscode';
import * as lc from 'vscode-languageclient';
import { Ctx, Cmd } from '../ctx';
import { analyzerStatus } from './analyzer_status';
@ -7,8 +10,7 @@ import { onEnter } from './on_enter';
import { parentModule } from './parent_module';
import { syntaxTree } from './syntax_tree';
import { expandMacro } from './expand_macro';
import * as inlayHints from './inlay_hints';
import * as runnables from './runnables';
import { run, runSingle } from './runnables';
function collectGarbage(ctx: Ctx): Cmd {
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 {
analyzerStatus,
expandMacro,
joinLines,
matchingBrace,
parentModule,
runnables,
syntaxTree,
onEnter,
inlayHints,
collectGarbage,
run,
runSingle,
showReferences,
};

View File

@ -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');
}
}
}

View File

@ -1,7 +1,67 @@
import * as vscode from 'vscode';
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 {
textDocument: lc.TextDocumentIdentifier;
@ -67,63 +127,3 @@ function createTask(spec: Runnable): vscode.Task {
t.presentationOptions.clear = true;
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);
}

View File

@ -1,14 +1,49 @@
import * as vscode from 'vscode';
import { Range, TextDocumentChangeEvent, TextEditor } from 'vscode';
import { TextDocumentIdentifier } from 'vscode-languageclient';
import { Server } from '../server';
import * as lc from 'vscode-languageclient';
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 {
textDocument: TextDocumentIdentifier;
textDocument: lc.TextDocumentIdentifier;
}
interface InlayHint {
range: Range;
range: vscode.Range;
kind: string;
label: string;
}
@ -19,7 +54,7 @@ const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
},
});
export class HintsUpdater {
class HintsUpdater {
private displayHints = true;
public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
@ -32,11 +67,10 @@ export class HintsUpdater {
}
public async refreshHintsForVisibleEditors(
cause?: TextDocumentChangeEvent,
cause?: vscode.TextDocumentChangeEvent,
): Promise<void> {
if (!this.displayHints) {
return;
}
if (!this.displayHints) return;
if (
cause !== undefined &&
(cause.contentChanges.length === 0 ||
@ -79,7 +113,7 @@ export class HintsUpdater {
}
private async updateDecorationsFromServer(
editor: TextEditor,
editor: vscode.TextEditor,
): Promise<void> {
const newHints = await this.queryHints(editor.document.uri.toString());
if (newHints !== null) {

View File

@ -2,8 +2,8 @@ import * as vscode from 'vscode';
import * as lc from 'vscode-languageclient';
import * as commands from './commands';
import { HintsUpdater } from './commands/inlay_hints';
import { StatusDisplay } from './commands/watch_status';
import { activateInlayHints } from './inlay_hints';
import { StatusDisplay } from './status_display';
import * as events from './events';
import * as notifications from './notifications';
import { Server } from './server';
@ -13,6 +13,8 @@ let ctx!: Ctx;
export async function activate(context: vscode.ExtensionContext) {
ctx = new Ctx(context);
// Commands which invokes manually via command pallet, shortcut, etc.
ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
ctx.registerCommand('collectGarbage', commands.collectGarbage);
ctx.registerCommand('matchingBrace', commands.matchingBrace);
@ -20,30 +22,11 @@ export async function activate(context: vscode.ExtensionContext) {
ctx.registerCommand('parentModule', commands.parentModule);
ctx.registerCommand('syntaxTree', commands.syntaxTree);
ctx.registerCommand('expandMacro', commands.expandMacro);
ctx.registerCommand('run', commands.run);
function disposeOnDeactivation(disposable: vscode.Disposable) {
context.subscriptions.push(disposable);
}
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),
);
},
);
// Internal commands which are invoked by the server.
ctx.registerCommand('runSingle', commands.runSingle);
ctx.registerCommand('showReferences', commands.showReferences);
if (Server.config.enableEnhancedTyping) {
ctx.overrideCommand('type', commands.onEnter);
@ -52,7 +35,7 @@ export async function activate(context: vscode.ExtensionContext) {
const watchStatus = new StatusDisplay(
Server.config.cargoWatchOptions.command,
);
disposeOnDeactivation(watchStatus);
ctx.pushCleanup(watchStatus);
// Notifications are events triggered by the language server
const allNotifications: [string, lc.GenericNotificationHandler][] = [
@ -84,38 +67,7 @@ export async function activate(context: vscode.ExtensionContext) {
}
if (Server.config.displayInlayHints) {
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();
},
);
disposeOnDeactivation(
vscode.window.onDidChangeVisibleTextEditors(_ =>
hintsUpdater.refreshHintsForVisibleEditors(),
),
);
disposeOnDeactivation(
vscode.workspace.onDidChangeTextDocument(e =>
hintsUpdater.refreshHintsForVisibleEditors(e),
),
);
disposeOnDeactivation(
vscode.workspace.onDidChangeConfiguration(_ =>
hintsUpdater.toggleHintsDisplay(
Server.config.displayInlayHints,
),
),
);
});
activateInlayHints(ctx);
}
}

View File

@ -3,7 +3,7 @@ import * as vscode from 'vscode';
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
export class StatusDisplay implements vscode.Disposable {
public packageName?: string;
packageName?: string;
private i = 0;
private statusBarItem: vscode.StatusBarItem;
@ -19,7 +19,7 @@ export class StatusDisplay implements vscode.Disposable {
this.statusBarItem.hide();
}
public show() {
show() {
this.packageName = undefined;
this.timer =
@ -39,7 +39,7 @@ export class StatusDisplay implements vscode.Disposable {
this.statusBarItem.show();
}
public hide() {
hide() {
if (this.timer) {
clearInterval(this.timer);
this.timer = undefined;
@ -48,7 +48,7 @@ export class StatusDisplay implements vscode.Disposable {
this.statusBarItem.hide();
}
public dispose() {
dispose() {
if (this.timer) {
clearInterval(this.timer);
this.timer = undefined;
@ -57,7 +57,7 @@ export class StatusDisplay implements vscode.Disposable {
this.statusBarItem.dispose();
}
public handleProgressNotification(params: ProgressParams) {
handleProgressNotification(params: ProgressParams) {
const { token, value } = params;
if (token !== 'rustAnalyzer/cargoWatcher') {
return;