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
@ -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,
|
||||
};
|
||||
|
@ -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 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);
|
||||
}
|
||||
|
@ -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) {
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
Loading…
x
Reference in New Issue
Block a user