mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Merge #4605
4605: Reorganize TypeScript r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
e4f91bfa57
15 changed files with 382 additions and 499 deletions
|
@ -1,93 +1,15 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as ra from '../rust-analyzer-api';
|
|
||||||
|
|
||||||
import { Ctx, Cmd, Disposable } from '../ctx';
|
|
||||||
import { isRustDocument, RustEditor, isRustEditor, sleep } from '../util';
|
|
||||||
|
|
||||||
const AST_FILE_SCHEME = "rust-analyzer";
|
|
||||||
|
|
||||||
// Opens the virtual file that will show the syntax tree
|
|
||||||
//
|
|
||||||
// The contents of the file come from the `TextDocumentContentProvider`
|
|
||||||
export function syntaxTree(ctx: Ctx): Cmd {
|
|
||||||
const tdcp = new TextDocumentContentProvider(ctx);
|
|
||||||
|
|
||||||
void new AstInspector(ctx);
|
|
||||||
|
|
||||||
ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider(AST_FILE_SCHEME, tdcp));
|
|
||||||
ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
|
|
||||||
brackets: [["[", ")"]],
|
|
||||||
}));
|
|
||||||
|
|
||||||
return async () => {
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
const rangeEnabled = !!editor && !editor.selection.isEmpty;
|
|
||||||
|
|
||||||
const uri = rangeEnabled
|
|
||||||
? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`)
|
|
||||||
: tdcp.uri;
|
|
||||||
|
|
||||||
const document = await vscode.workspace.openTextDocument(uri);
|
|
||||||
|
|
||||||
tdcp.eventEmitter.fire(uri);
|
|
||||||
|
|
||||||
void await vscode.window.showTextDocument(document, {
|
|
||||||
viewColumn: vscode.ViewColumn.Two,
|
|
||||||
preserveFocus: true
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class TextDocumentContentProvider implements vscode.TextDocumentContentProvider {
|
|
||||||
readonly uri = vscode.Uri.parse('rust-analyzer://syntaxtree/tree.rast');
|
|
||||||
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
||||||
|
|
||||||
|
|
||||||
constructor(private readonly ctx: Ctx) {
|
|
||||||
vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
|
|
||||||
vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
|
|
||||||
if (isRustDocument(event.document)) {
|
|
||||||
// We need to order this after language server updates, but there's no API for that.
|
|
||||||
// Hence, good old sleep().
|
|
||||||
void sleep(10).then(() => this.eventEmitter.fire(this.uri));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
|
|
||||||
if (editor && isRustEditor(editor)) {
|
|
||||||
this.eventEmitter.fire(this.uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
provideTextDocumentContent(uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> {
|
|
||||||
const rustEditor = this.ctx.activeRustEditor;
|
|
||||||
if (!rustEditor) return '';
|
|
||||||
|
|
||||||
// When the range based query is enabled we take the range of the selection
|
|
||||||
const range = uri.query === 'range=true' && !rustEditor.selection.isEmpty
|
|
||||||
? this.ctx.client.code2ProtocolConverter.asRange(rustEditor.selection)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range, };
|
|
||||||
return this.ctx.client.sendRequest(ra.syntaxTree, params, ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
||||||
return this.eventEmitter.event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
import { Ctx, Disposable } from './ctx';
|
||||||
|
import { RustEditor, isRustEditor } from './util';
|
||||||
|
|
||||||
// FIXME: consider implementing this via the Tree View API?
|
// FIXME: consider implementing this via the Tree View API?
|
||||||
// https://code.visualstudio.com/api/extension-guides/tree-view
|
// https://code.visualstudio.com/api/extension-guides/tree-view
|
||||||
class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable {
|
export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable {
|
||||||
private readonly astDecorationType = vscode.window.createTextEditorDecorationType({
|
private readonly astDecorationType = vscode.window.createTextEditorDecorationType({
|
||||||
borderColor: new vscode.ThemeColor('rust_analyzer.syntaxTreeBorder'),
|
borderColor: new vscode.ThemeColor('rust_analyzer.syntaxTreeBorder'),
|
||||||
borderStyle: "solid",
|
borderStyle: "solid",
|
||||||
borderWidth: "2px",
|
borderWidth: "2px",
|
||||||
|
|
||||||
});
|
});
|
||||||
private rustEditor: undefined | RustEditor;
|
private rustEditor: undefined | RustEditor;
|
||||||
|
|
||||||
|
@ -113,7 +35,7 @@ class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, D
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(ctx: Ctx) {
|
constructor(ctx: Ctx) {
|
||||||
ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: AST_FILE_SCHEME }, this));
|
ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: 'rust-analyzer' }, this));
|
||||||
ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
|
ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
|
||||||
vscode.workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, ctx.subscriptions);
|
vscode.workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, ctx.subscriptions);
|
||||||
vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
|
vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
|
||||||
|
@ -146,7 +68,7 @@ class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, D
|
||||||
}
|
}
|
||||||
|
|
||||||
private findAstTextEditor(): undefined | vscode.TextEditor {
|
private findAstTextEditor(): undefined | vscode.TextEditor {
|
||||||
return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === AST_FILE_SCHEME);
|
return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === 'rust-analyzer');
|
||||||
}
|
}
|
||||||
|
|
||||||
private setRustEditor(newRustEditor: undefined | RustEditor) {
|
private setRustEditor(newRustEditor: undefined | RustEditor) {
|
370
editors/code/src/commands.ts
Normal file
370
editors/code/src/commands.ts
Normal file
|
@ -0,0 +1,370 @@
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import * as lc from 'vscode-languageclient';
|
||||||
|
import * as ra from './rust-analyzer-api';
|
||||||
|
|
||||||
|
import { Ctx, Cmd } from './ctx';
|
||||||
|
import { applySnippetWorkspaceEdit } from './snippets';
|
||||||
|
import { spawnSync } from 'child_process';
|
||||||
|
import { RunnableQuickPick, selectRunnable, createTask } from './run';
|
||||||
|
import { AstInspector } from './ast_inspector';
|
||||||
|
import { isRustDocument, sleep, isRustEditor } from './util';
|
||||||
|
|
||||||
|
export * from './ast_inspector';
|
||||||
|
export * from './run';
|
||||||
|
|
||||||
|
export function analyzerStatus(ctx: Ctx): Cmd {
|
||||||
|
const tdcp = new class implements vscode.TextDocumentContentProvider {
|
||||||
|
readonly uri = vscode.Uri.parse('rust-analyzer-status://status');
|
||||||
|
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
||||||
|
|
||||||
|
provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
|
||||||
|
if (!vscode.window.activeTextEditor) return '';
|
||||||
|
|
||||||
|
return ctx.client.sendRequest(ra.analyzerStatus, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
||||||
|
return this.eventEmitter.event;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
let poller: NodeJS.Timer | undefined = undefined;
|
||||||
|
|
||||||
|
ctx.pushCleanup(
|
||||||
|
vscode.workspace.registerTextDocumentContentProvider(
|
||||||
|
'rust-analyzer-status',
|
||||||
|
tdcp,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.pushCleanup({
|
||||||
|
dispose() {
|
||||||
|
if (poller !== undefined) {
|
||||||
|
clearInterval(poller);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
if (poller === undefined) {
|
||||||
|
poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000);
|
||||||
|
}
|
||||||
|
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
||||||
|
return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function matchingBrace(ctx: Ctx): Cmd {
|
||||||
|
return async () => {
|
||||||
|
const editor = ctx.activeRustEditor;
|
||||||
|
const client = ctx.client;
|
||||||
|
if (!editor || !client) return;
|
||||||
|
|
||||||
|
const response = await client.sendRequest(ra.matchingBrace, {
|
||||||
|
textDocument: { uri: editor.document.uri.toString() },
|
||||||
|
positions: editor.selections.map(s =>
|
||||||
|
client.code2ProtocolConverter.asPosition(s.active),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
editor.selections = editor.selections.map((sel, idx) => {
|
||||||
|
const active = client.protocol2CodeConverter.asPosition(
|
||||||
|
response[idx],
|
||||||
|
);
|
||||||
|
const anchor = sel.isEmpty ? active : sel.anchor;
|
||||||
|
return new vscode.Selection(anchor, active);
|
||||||
|
});
|
||||||
|
editor.revealRange(editor.selection);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function joinLines(ctx: Ctx): Cmd {
|
||||||
|
return async () => {
|
||||||
|
const editor = ctx.activeRustEditor;
|
||||||
|
const client = ctx.client;
|
||||||
|
if (!editor || !client) return;
|
||||||
|
|
||||||
|
const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
|
||||||
|
ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
|
||||||
|
textDocument: { uri: editor.document.uri.toString() },
|
||||||
|
});
|
||||||
|
editor.edit((builder) => {
|
||||||
|
client.protocol2CodeConverter.asTextEdits(items).forEach((edit) => {
|
||||||
|
builder.replace(edit.range, edit.newText);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onEnter(ctx: Ctx): Cmd {
|
||||||
|
async function handleKeypress() {
|
||||||
|
const editor = ctx.activeRustEditor;
|
||||||
|
const client = ctx.client;
|
||||||
|
|
||||||
|
if (!editor || !client) return false;
|
||||||
|
|
||||||
|
const change = await client.sendRequest(ra.onEnter, {
|
||||||
|
textDocument: { uri: editor.document.uri.toString() },
|
||||||
|
position: client.code2ProtocolConverter.asPosition(
|
||||||
|
editor.selection.active,
|
||||||
|
),
|
||||||
|
}).catch(_error => {
|
||||||
|
// client.logFailedRequest(OnEnterRequest.type, error);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
if (!change) return false;
|
||||||
|
|
||||||
|
const workspaceEdit = client.protocol2CodeConverter.asWorkspaceEdit(change);
|
||||||
|
await applySnippetWorkspaceEdit(workspaceEdit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
if (await handleKeypress()) return;
|
||||||
|
|
||||||
|
await vscode.commands.executeCommand('default:type', { text: '\n' });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parentModule(ctx: Ctx): Cmd {
|
||||||
|
return async () => {
|
||||||
|
const editor = ctx.activeRustEditor;
|
||||||
|
const client = ctx.client;
|
||||||
|
if (!editor || !client) return;
|
||||||
|
|
||||||
|
const response = await client.sendRequest(ra.parentModule, {
|
||||||
|
textDocument: { uri: editor.document.uri.toString() },
|
||||||
|
position: client.code2ProtocolConverter.asPosition(
|
||||||
|
editor.selection.active,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
const loc = response[0];
|
||||||
|
if (loc == null) return;
|
||||||
|
|
||||||
|
const uri = client.protocol2CodeConverter.asUri(loc.uri);
|
||||||
|
const range = client.protocol2CodeConverter.asRange(loc.range);
|
||||||
|
|
||||||
|
const doc = await vscode.workspace.openTextDocument(uri);
|
||||||
|
const e = await vscode.window.showTextDocument(doc);
|
||||||
|
e.selection = new vscode.Selection(range.start, range.start);
|
||||||
|
e.revealRange(range, vscode.TextEditorRevealType.InCenter);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ssr(ctx: Ctx): Cmd {
|
||||||
|
return async () => {
|
||||||
|
const client = ctx.client;
|
||||||
|
if (!client) return;
|
||||||
|
|
||||||
|
const options: vscode.InputBoxOptions = {
|
||||||
|
value: "() ==>> ()",
|
||||||
|
prompt: "Enter request, for example 'Foo($a:expr) ==> Foo::new($a)' ",
|
||||||
|
validateInput: async (x: string) => {
|
||||||
|
try {
|
||||||
|
await client.sendRequest(ra.ssr, { query: x, parseOnly: true });
|
||||||
|
} catch (e) {
|
||||||
|
return e.toString();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const request = await vscode.window.showInputBox(options);
|
||||||
|
if (!request) return;
|
||||||
|
|
||||||
|
const edit = await client.sendRequest(ra.ssr, { query: request, parseOnly: false });
|
||||||
|
|
||||||
|
await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function serverVersion(ctx: Ctx): Cmd {
|
||||||
|
return async () => {
|
||||||
|
const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
|
||||||
|
const commitHash = stdout.slice(`rust-analyzer `.length).trim();
|
||||||
|
const { releaseTag } = ctx.config.package;
|
||||||
|
|
||||||
|
void vscode.window.showInformationMessage(
|
||||||
|
`rust-analyzer version: ${releaseTag ?? "unreleased"} (${commitHash})`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toggleInlayHints(ctx: Ctx): Cmd {
|
||||||
|
return async () => {
|
||||||
|
await vscode
|
||||||
|
.workspace
|
||||||
|
.getConfiguration(`${ctx.config.rootSection}.inlayHints`)
|
||||||
|
.update('enable', !ctx.config.inlayHints.enable, vscode.ConfigurationTarget.Workspace);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function run(ctx: Ctx): Cmd {
|
||||||
|
let prevRunnable: RunnableQuickPick | undefined;
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
const item = await selectRunnable(ctx, prevRunnable);
|
||||||
|
if (!item) return;
|
||||||
|
|
||||||
|
item.detail = 'rerun';
|
||||||
|
prevRunnable = item;
|
||||||
|
const task = createTask(item.runnable);
|
||||||
|
return await vscode.tasks.executeTask(task);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opens the virtual file that will show the syntax tree
|
||||||
|
//
|
||||||
|
// The contents of the file come from the `TextDocumentContentProvider`
|
||||||
|
export function syntaxTree(ctx: Ctx): Cmd {
|
||||||
|
const tdcp = new class implements vscode.TextDocumentContentProvider {
|
||||||
|
readonly uri = vscode.Uri.parse('rust-analyzer://syntaxtree/tree.rast');
|
||||||
|
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
||||||
|
constructor() {
|
||||||
|
vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
|
||||||
|
vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
|
||||||
|
if (isRustDocument(event.document)) {
|
||||||
|
// We need to order this after language server updates, but there's no API for that.
|
||||||
|
// Hence, good old sleep().
|
||||||
|
void sleep(10).then(() => this.eventEmitter.fire(this.uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
|
||||||
|
if (editor && isRustEditor(editor)) {
|
||||||
|
this.eventEmitter.fire(this.uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provideTextDocumentContent(uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> {
|
||||||
|
const rustEditor = ctx.activeRustEditor;
|
||||||
|
if (!rustEditor) return '';
|
||||||
|
|
||||||
|
// When the range based query is enabled we take the range of the selection
|
||||||
|
const range = uri.query === 'range=true' && !rustEditor.selection.isEmpty
|
||||||
|
? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range, };
|
||||||
|
return ctx.client.sendRequest(ra.syntaxTree, params, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
||||||
|
return this.eventEmitter.event;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void new AstInspector(ctx);
|
||||||
|
|
||||||
|
ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp));
|
||||||
|
ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
|
||||||
|
brackets: [["[", ")"]],
|
||||||
|
}));
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
const rangeEnabled = !!editor && !editor.selection.isEmpty;
|
||||||
|
|
||||||
|
const uri = rangeEnabled
|
||||||
|
? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`)
|
||||||
|
: tdcp.uri;
|
||||||
|
|
||||||
|
const document = await vscode.workspace.openTextDocument(uri);
|
||||||
|
|
||||||
|
tdcp.eventEmitter.fire(uri);
|
||||||
|
|
||||||
|
void await vscode.window.showTextDocument(document, {
|
||||||
|
viewColumn: vscode.ViewColumn.Two,
|
||||||
|
preserveFocus: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Opens the virtual file that will show the syntax tree
|
||||||
|
//
|
||||||
|
// The contents of the file come from the `TextDocumentContentProvider`
|
||||||
|
export function expandMacro(ctx: Ctx): Cmd {
|
||||||
|
function codeFormat(expanded: ra.ExpandedMacro): string {
|
||||||
|
let result = `// Recursive expansion of ${expanded.name}! macro\n`;
|
||||||
|
result += '// ' + '='.repeat(result.length - 3);
|
||||||
|
result += '\n\n';
|
||||||
|
result += expanded.expansion;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tdcp = new class implements vscode.TextDocumentContentProvider {
|
||||||
|
uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs');
|
||||||
|
eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
||||||
|
async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
const client = ctx.client;
|
||||||
|
if (!editor || !client) return '';
|
||||||
|
|
||||||
|
const position = editor.selection.active;
|
||||||
|
|
||||||
|
const expanded = await client.sendRequest(ra.expandMacro, {
|
||||||
|
textDocument: { uri: editor.document.uri.toString() },
|
||||||
|
position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (expanded == null) return 'Not available';
|
||||||
|
|
||||||
|
return codeFormat(expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
||||||
|
return this.eventEmitter.event;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
ctx.pushCleanup(
|
||||||
|
vscode.workspace.registerTextDocumentContentProvider(
|
||||||
|
'rust-analyzer',
|
||||||
|
tdcp,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
||||||
|
tdcp.eventEmitter.fire(tdcp.uri);
|
||||||
|
return vscode.window.showTextDocument(
|
||||||
|
document,
|
||||||
|
vscode.ViewColumn.Two,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function collectGarbage(ctx: Ctx): Cmd {
|
||||||
|
return async () => ctx.client.sendRequest(ra.collectGarbage, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showReferences(ctx: Ctx): Cmd {
|
||||||
|
return (uri: string, position: lc.Position, locations: lc.Location[]) => {
|
||||||
|
const client = ctx.client;
|
||||||
|
if (client) {
|
||||||
|
vscode.commands.executeCommand(
|
||||||
|
'editor.action.showReferences',
|
||||||
|
vscode.Uri.parse(uri),
|
||||||
|
client.protocol2CodeConverter.asPosition(position),
|
||||||
|
locations.map(client.protocol2CodeConverter.asLocation),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyActionGroup(_ctx: Ctx): Cmd {
|
||||||
|
return async (actions: { label: string; edit: vscode.WorkspaceEdit }[]) => {
|
||||||
|
const selectedAction = await vscode.window.showQuickPick(actions);
|
||||||
|
if (!selectedAction) return;
|
||||||
|
await applySnippetWorkspaceEdit(selectedAction.edit);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd {
|
||||||
|
return async (edit: vscode.WorkspaceEdit) => {
|
||||||
|
await applySnippetWorkspaceEdit(edit);
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,51 +0,0 @@
|
||||||
import * as vscode from 'vscode';
|
|
||||||
|
|
||||||
import * as ra from '../rust-analyzer-api';
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
|
||||||
|
|
||||||
// Shows status of rust-analyzer (for debugging)
|
|
||||||
export function analyzerStatus(ctx: Ctx): Cmd {
|
|
||||||
let poller: NodeJS.Timer | undefined = undefined;
|
|
||||||
const tdcp = new TextDocumentContentProvider(ctx);
|
|
||||||
|
|
||||||
ctx.pushCleanup(
|
|
||||||
vscode.workspace.registerTextDocumentContentProvider(
|
|
||||||
'rust-analyzer-status',
|
|
||||||
tdcp,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
ctx.pushCleanup({
|
|
||||||
dispose() {
|
|
||||||
if (poller !== undefined) {
|
|
||||||
clearInterval(poller);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return async () => {
|
|
||||||
if (poller === undefined) {
|
|
||||||
poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000);
|
|
||||||
}
|
|
||||||
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
|
||||||
return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class TextDocumentContentProvider implements vscode.TextDocumentContentProvider {
|
|
||||||
readonly uri = vscode.Uri.parse('rust-analyzer-status://status');
|
|
||||||
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
||||||
|
|
||||||
constructor(private readonly ctx: Ctx) {
|
|
||||||
}
|
|
||||||
|
|
||||||
provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
|
|
||||||
if (!vscode.window.activeTextEditor) return '';
|
|
||||||
|
|
||||||
return this.ctx.client.sendRequest(ra.analyzerStatus, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
||||||
return this.eventEmitter.event;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import * as ra from '../rust-analyzer-api';
|
|
||||||
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
|
||||||
|
|
||||||
// Opens the virtual file that will show the syntax tree
|
|
||||||
//
|
|
||||||
// The contents of the file come from the `TextDocumentContentProvider`
|
|
||||||
export function expandMacro(ctx: Ctx): Cmd {
|
|
||||||
const tdcp = new TextDocumentContentProvider(ctx);
|
|
||||||
ctx.pushCleanup(
|
|
||||||
vscode.workspace.registerTextDocumentContentProvider(
|
|
||||||
'rust-analyzer',
|
|
||||||
tdcp,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return async () => {
|
|
||||||
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
|
||||||
tdcp.eventEmitter.fire(tdcp.uri);
|
|
||||||
return vscode.window.showTextDocument(
|
|
||||||
document,
|
|
||||||
vscode.ViewColumn.Two,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function codeFormat(expanded: ra.ExpandedMacro): string {
|
|
||||||
let result = `// Recursive expansion of ${expanded.name}! macro\n`;
|
|
||||||
result += '// ' + '='.repeat(result.length - 3);
|
|
||||||
result += '\n\n';
|
|
||||||
result += expanded.expansion;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
class TextDocumentContentProvider
|
|
||||||
implements vscode.TextDocumentContentProvider {
|
|
||||||
uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs');
|
|
||||||
eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
||||||
|
|
||||||
constructor(private readonly ctx: Ctx) {
|
|
||||||
}
|
|
||||||
|
|
||||||
async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
const client = this.ctx.client;
|
|
||||||
if (!editor || !client) return '';
|
|
||||||
|
|
||||||
const position = editor.selection.active;
|
|
||||||
|
|
||||||
const expanded = await client.sendRequest(ra.expandMacro, {
|
|
||||||
textDocument: { uri: editor.document.uri.toString() },
|
|
||||||
position,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (expanded == null) return 'Not available';
|
|
||||||
|
|
||||||
return codeFormat(expanded);
|
|
||||||
}
|
|
||||||
|
|
||||||
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
||||||
return this.eventEmitter.event;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
import * as ra from '../rust-analyzer-api';
|
|
||||||
import * as lc from 'vscode-languageclient';
|
|
||||||
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
|
||||||
|
|
||||||
export function joinLines(ctx: Ctx): Cmd {
|
|
||||||
return async () => {
|
|
||||||
const editor = ctx.activeRustEditor;
|
|
||||||
const client = ctx.client;
|
|
||||||
if (!editor || !client) return;
|
|
||||||
|
|
||||||
const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
|
|
||||||
ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
|
|
||||||
textDocument: { uri: editor.document.uri.toString() },
|
|
||||||
});
|
|
||||||
editor.edit((builder) => {
|
|
||||||
client.protocol2CodeConverter.asTextEdits(items).forEach((edit) => {
|
|
||||||
builder.replace(edit.range, edit.newText);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import * as ra from '../rust-analyzer-api';
|
|
||||||
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
|
||||||
|
|
||||||
export function matchingBrace(ctx: Ctx): Cmd {
|
|
||||||
return async () => {
|
|
||||||
const editor = ctx.activeRustEditor;
|
|
||||||
const client = ctx.client;
|
|
||||||
if (!editor || !client) return;
|
|
||||||
|
|
||||||
const response = await client.sendRequest(ra.matchingBrace, {
|
|
||||||
textDocument: { uri: editor.document.uri.toString() },
|
|
||||||
positions: editor.selections.map(s =>
|
|
||||||
client.code2ProtocolConverter.asPosition(s.active),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
editor.selections = editor.selections.map((sel, idx) => {
|
|
||||||
const active = client.protocol2CodeConverter.asPosition(
|
|
||||||
response[idx],
|
|
||||||
);
|
|
||||||
const anchor = sel.isEmpty ? active : sel.anchor;
|
|
||||||
return new vscode.Selection(anchor, active);
|
|
||||||
});
|
|
||||||
editor.revealRange(editor.selection);
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import * as ra from '../rust-analyzer-api';
|
|
||||||
|
|
||||||
import { Cmd, Ctx } from '../ctx';
|
|
||||||
import { applySnippetWorkspaceEdit } from '.';
|
|
||||||
|
|
||||||
async function handleKeypress(ctx: Ctx) {
|
|
||||||
const editor = ctx.activeRustEditor;
|
|
||||||
const client = ctx.client;
|
|
||||||
|
|
||||||
if (!editor || !client) return false;
|
|
||||||
|
|
||||||
const change = await client.sendRequest(ra.onEnter, {
|
|
||||||
textDocument: { uri: editor.document.uri.toString() },
|
|
||||||
position: client.code2ProtocolConverter.asPosition(
|
|
||||||
editor.selection.active,
|
|
||||||
),
|
|
||||||
}).catch(_error => {
|
|
||||||
// client.logFailedRequest(OnEnterRequest.type, error);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
if (!change) return false;
|
|
||||||
|
|
||||||
const workspaceEdit = client.protocol2CodeConverter.asWorkspaceEdit(change);
|
|
||||||
await applySnippetWorkspaceEdit(workspaceEdit);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function onEnter(ctx: Ctx): Cmd {
|
|
||||||
return async () => {
|
|
||||||
if (await handleKeypress(ctx)) return;
|
|
||||||
|
|
||||||
await vscode.commands.executeCommand('default:type', { text: '\n' });
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import * as ra from '../rust-analyzer-api';
|
|
||||||
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
|
||||||
|
|
||||||
export function parentModule(ctx: Ctx): Cmd {
|
|
||||||
return async () => {
|
|
||||||
const editor = ctx.activeRustEditor;
|
|
||||||
const client = ctx.client;
|
|
||||||
if (!editor || !client) return;
|
|
||||||
|
|
||||||
const response = await client.sendRequest(ra.parentModule, {
|
|
||||||
textDocument: { uri: editor.document.uri.toString() },
|
|
||||||
position: client.code2ProtocolConverter.asPosition(
|
|
||||||
editor.selection.active,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
const loc = response[0];
|
|
||||||
if (loc == null) return;
|
|
||||||
|
|
||||||
const uri = client.protocol2CodeConverter.asUri(loc.uri);
|
|
||||||
const range = client.protocol2CodeConverter.asRange(loc.range);
|
|
||||||
|
|
||||||
const doc = await vscode.workspace.openTextDocument(uri);
|
|
||||||
const e = await vscode.window.showTextDocument(doc);
|
|
||||||
e.selection = new vscode.Selection(range.start, range.start);
|
|
||||||
e.revealRange(range, vscode.TextEditorRevealType.InCenter);
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
import * as vscode from "vscode";
|
|
||||||
import { spawnSync } from "child_process";
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
|
||||||
|
|
||||||
export function serverVersion(ctx: Ctx): Cmd {
|
|
||||||
return async () => {
|
|
||||||
const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
|
|
||||||
const commitHash = stdout.slice(`rust-analyzer `.length).trim();
|
|
||||||
const { releaseTag } = ctx.config.package;
|
|
||||||
|
|
||||||
void vscode.window.showInformationMessage(
|
|
||||||
`rust-analyzer version: ${releaseTag ?? "unreleased"} (${commitHash})`
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import * as ra from "../rust-analyzer-api";
|
|
||||||
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
|
||||||
|
|
||||||
export function ssr(ctx: Ctx): Cmd {
|
|
||||||
return async () => {
|
|
||||||
const client = ctx.client;
|
|
||||||
if (!client) return;
|
|
||||||
|
|
||||||
const options: vscode.InputBoxOptions = {
|
|
||||||
value: "() ==>> ()",
|
|
||||||
prompt: "Enter request, for example 'Foo($a:expr) ==> Foo::new($a)' ",
|
|
||||||
validateInput: async (x: string) => {
|
|
||||||
try {
|
|
||||||
await client.sendRequest(ra.ssr, { query: x, parseOnly: true });
|
|
||||||
} catch (e) {
|
|
||||||
return e.toString();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const request = await vscode.window.showInputBox(options);
|
|
||||||
if (!request) return;
|
|
||||||
|
|
||||||
const edit = await client.sendRequest(ra.ssr, { query: request, parseOnly: false });
|
|
||||||
|
|
||||||
await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit));
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
|
||||||
|
|
||||||
export function toggleInlayHints(ctx: Ctx): Cmd {
|
|
||||||
return async () => {
|
|
||||||
await vscode
|
|
||||||
.workspace
|
|
||||||
.getConfiguration(`${ctx.config.rootSection}.inlayHints`)
|
|
||||||
.update('enable', !ctx.config.inlayHints.enable, vscode.ConfigurationTarget.Workspace);
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -92,7 +92,6 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
ctx.registerCommand('runSingle', commands.runSingle);
|
ctx.registerCommand('runSingle', commands.runSingle);
|
||||||
ctx.registerCommand('debugSingle', commands.debugSingle);
|
ctx.registerCommand('debugSingle', commands.debugSingle);
|
||||||
ctx.registerCommand('showReferences', commands.showReferences);
|
ctx.registerCommand('showReferences', commands.showReferences);
|
||||||
ctx.registerCommand('applySourceChange', commands.applySourceChange);
|
|
||||||
ctx.registerCommand('applySnippetWorkspaceEdit', commands.applySnippetWorkspaceEditCommand);
|
ctx.registerCommand('applySnippetWorkspaceEdit', commands.applySnippetWorkspaceEditCommand);
|
||||||
ctx.registerCommand('applyActionGroup', commands.applyActionGroup);
|
ctx.registerCommand('applyActionGroup', commands.applyActionGroup);
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as lc from 'vscode-languageclient';
|
import * as lc from 'vscode-languageclient';
|
||||||
import * as ra from '../rust-analyzer-api';
|
import * as ra from './rust-analyzer-api';
|
||||||
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
import { Ctx, Cmd } from './ctx';
|
||||||
import { startDebugSession, getDebugConfiguration } from '../debug';
|
import { startDebugSession, getDebugConfiguration } from './debug';
|
||||||
|
|
||||||
const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }];
|
const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }];
|
||||||
|
|
||||||
async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
|
export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
|
||||||
const editor = ctx.activeRustEditor;
|
const editor = ctx.activeRustEditor;
|
||||||
const client = ctx.client;
|
const client = ctx.client;
|
||||||
if (!editor || !client) return;
|
if (!editor || !client) return;
|
||||||
|
@ -83,20 +83,6 @@ async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debugg
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function run(ctx: Ctx): Cmd {
|
|
||||||
let prevRunnable: RunnableQuickPick | undefined;
|
|
||||||
|
|
||||||
return async () => {
|
|
||||||
const item = await selectRunnable(ctx, prevRunnable);
|
|
||||||
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 {
|
export function runSingle(ctx: Ctx): Cmd {
|
||||||
return async (runnable: ra.Runnable) => {
|
return async (runnable: ra.Runnable) => {
|
||||||
const editor = ctx.activeRustEditor;
|
const editor = ctx.activeRustEditor;
|
||||||
|
@ -165,7 +151,7 @@ export function newDebugConfig(ctx: Ctx): Cmd {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class RunnableQuickPick implements vscode.QuickPickItem {
|
export class RunnableQuickPick implements vscode.QuickPickItem {
|
||||||
public label: string;
|
public label: string;
|
||||||
public description?: string | undefined;
|
public description?: string | undefined;
|
||||||
public detail?: string | undefined;
|
public detail?: string | undefined;
|
||||||
|
@ -184,7 +170,7 @@ interface CargoTaskDefinition extends vscode.TaskDefinition {
|
||||||
env?: { [key: string]: string };
|
env?: { [key: string]: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTask(spec: ra.Runnable): vscode.Task {
|
export function createTask(spec: ra.Runnable): vscode.Task {
|
||||||
const TASK_SOURCE = 'Rust';
|
const TASK_SOURCE = 'Rust';
|
||||||
const definition: CargoTaskDefinition = {
|
const definition: CargoTaskDefinition = {
|
||||||
type: 'cargo',
|
type: 'cargo',
|
|
@ -1,60 +1,6 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as lc from 'vscode-languageclient';
|
|
||||||
import * as ra from '../rust-analyzer-api';
|
|
||||||
|
|
||||||
import { Ctx, Cmd } from '../ctx';
|
import { assert } from './util';
|
||||||
import * as sourceChange from '../source_change';
|
|
||||||
import { assert } from '../util';
|
|
||||||
|
|
||||||
export * from './analyzer_status';
|
|
||||||
export * from './matching_brace';
|
|
||||||
export * from './join_lines';
|
|
||||||
export * from './on_enter';
|
|
||||||
export * from './parent_module';
|
|
||||||
export * from './syntax_tree';
|
|
||||||
export * from './expand_macro';
|
|
||||||
export * from './runnables';
|
|
||||||
export * from './ssr';
|
|
||||||
export * from './server_version';
|
|
||||||
export * from './toggle_inlay_hints';
|
|
||||||
|
|
||||||
export function collectGarbage(ctx: Ctx): Cmd {
|
|
||||||
return async () => ctx.client.sendRequest(ra.collectGarbage, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showReferences(ctx: Ctx): Cmd {
|
|
||||||
return (uri: string, position: lc.Position, locations: lc.Location[]) => {
|
|
||||||
const client = ctx.client;
|
|
||||||
if (client) {
|
|
||||||
vscode.commands.executeCommand(
|
|
||||||
'editor.action.showReferences',
|
|
||||||
vscode.Uri.parse(uri),
|
|
||||||
client.protocol2CodeConverter.asPosition(position),
|
|
||||||
locations.map(client.protocol2CodeConverter.asLocation),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function applySourceChange(ctx: Ctx): Cmd {
|
|
||||||
return async (change: ra.SourceChange) => {
|
|
||||||
await sourceChange.applySourceChange(ctx, change);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function applyActionGroup(_ctx: Ctx): Cmd {
|
|
||||||
return async (actions: { label: string; edit: vscode.WorkspaceEdit }[]) => {
|
|
||||||
const selectedAction = await vscode.window.showQuickPick(actions);
|
|
||||||
if (!selectedAction) return;
|
|
||||||
await applySnippetWorkspaceEdit(selectedAction.edit);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd {
|
|
||||||
return async (edit: vscode.WorkspaceEdit) => {
|
|
||||||
await applySnippetWorkspaceEdit(edit);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
|
export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
|
||||||
assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`);
|
assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`);
|
|
@ -1,54 +0,0 @@
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import * as lc from 'vscode-languageclient';
|
|
||||||
import * as ra from './rust-analyzer-api';
|
|
||||||
|
|
||||||
import { Ctx } from './ctx';
|
|
||||||
|
|
||||||
export async function applySourceChange(ctx: Ctx, change: ra.SourceChange) {
|
|
||||||
const client = ctx.client;
|
|
||||||
if (!client) return;
|
|
||||||
|
|
||||||
const wsEdit = client.protocol2CodeConverter.asWorkspaceEdit(
|
|
||||||
change.workspaceEdit,
|
|
||||||
);
|
|
||||||
let created;
|
|
||||||
let moved;
|
|
||||||
if (change.workspaceEdit.documentChanges) {
|
|
||||||
for (const docChange of change.workspaceEdit.documentChanges) {
|
|
||||||
if (lc.CreateFile.is(docChange)) {
|
|
||||||
created = docChange.uri;
|
|
||||||
} else if (lc.RenameFile.is(docChange)) {
|
|
||||||
moved = docChange.newUri;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const toOpen = created || moved;
|
|
||||||
const toReveal = change.cursorPosition;
|
|
||||||
await vscode.workspace.applyEdit(wsEdit);
|
|
||||||
if (toOpen) {
|
|
||||||
const toOpenUri = vscode.Uri.parse(toOpen);
|
|
||||||
const doc = await vscode.workspace.openTextDocument(toOpenUri);
|
|
||||||
await vscode.window.showTextDocument(doc);
|
|
||||||
} else if (toReveal) {
|
|
||||||
const uri = client.protocol2CodeConverter.asUri(
|
|
||||||
toReveal.textDocument.uri,
|
|
||||||
);
|
|
||||||
const position = client.protocol2CodeConverter.asPosition(
|
|
||||||
toReveal.position,
|
|
||||||
);
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
if (!editor || !editor.selection.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (editor.document.uri !== uri) {
|
|
||||||
const doc = await vscode.workspace.openTextDocument(uri);
|
|
||||||
await vscode.window.showTextDocument(doc);
|
|
||||||
}
|
|
||||||
editor.selection = new vscode.Selection(position, position);
|
|
||||||
editor.revealRange(
|
|
||||||
new vscode.Range(position, position),
|
|
||||||
vscode.TextEditorRevealType.Default,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue