2019-12-30 19:07:04 +00:00
|
|
|
import * as vscode from "vscode";
|
|
|
|
import * as lc from "vscode-languageclient";
|
2020-05-25 12:56:26 +00:00
|
|
|
import * as ra from "./lsp_ext";
|
2021-08-10 13:35:37 +00:00
|
|
|
import * as path from "path";
|
2022-05-17 17:15:06 +00:00
|
|
|
|
2023-09-05 16:20:08 +00:00
|
|
|
import type { Ctx, Cmd, CtxInit } from "./ctx";
|
2020-05-25 12:12:53 +00:00
|
|
|
import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
|
2020-05-25 09:10:31 +00:00
|
|
|
import { spawnSync } from "child_process";
|
2023-07-10 21:10:00 +00:00
|
|
|
import { type RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
|
2020-05-25 10:02:30 +00:00
|
|
|
import { AstInspector } from "./ast_inspector";
|
2023-04-05 17:57:01 +00:00
|
|
|
import {
|
|
|
|
isRustDocument,
|
|
|
|
isCargoTomlDocument,
|
|
|
|
sleep,
|
|
|
|
isRustEditor,
|
2023-07-10 21:10:00 +00:00
|
|
|
type RustEditor,
|
|
|
|
type RustDocument,
|
2023-04-05 17:57:01 +00:00
|
|
|
} from "./util";
|
2020-06-02 12:33:47 +00:00
|
|
|
import { startDebugSession, makeDebugConfig } from "./debug";
|
2023-07-10 21:10:00 +00:00
|
|
|
import type { LanguageClient } from "vscode-languageclient/node";
|
2022-05-16 18:53:00 +00:00
|
|
|
import { LINKED_COMMANDS } from "./client";
|
2023-07-10 21:10:00 +00:00
|
|
|
import type { DependencyId } from "./dependencies_provider";
|
2023-06-27 19:03:53 +00:00
|
|
|
import { unwrapUndefinable } from "./undefinable";
|
2023-10-08 01:52:15 +00:00
|
|
|
import { log } from "./util";
|
2022-05-17 17:15:06 +00:00
|
|
|
|
2020-05-25 10:02:30 +00:00
|
|
|
export * from "./ast_inspector";
|
|
|
|
export * from "./run";
|
2020-05-25 09:10:31 +00:00
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function analyzerStatus(ctx: CtxInit): Cmd {
|
2020-05-25 09:10:31 +00:00
|
|
|
const tdcp = new (class implements vscode.TextDocumentContentProvider {
|
|
|
|
readonly uri = vscode.Uri.parse("rust-analyzer-status://status");
|
|
|
|
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
|
2020-05-25 09:10:31 +00:00
|
|
|
if (!vscode.window.activeTextEditor) return "";
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-05-25 09:10:31 +00:00
|
|
|
|
2020-09-29 20:05:18 +00:00
|
|
|
const params: ra.AnalyzerStatusParams = {};
|
|
|
|
const doc = ctx.activeRustEditor?.document;
|
|
|
|
if (doc != null) {
|
2022-10-17 12:20:14 +00:00
|
|
|
params.textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(doc);
|
2020-09-29 20:05:18 +00:00
|
|
|
}
|
2022-10-17 12:20:14 +00:00
|
|
|
return await client.sendRequest(ra.analyzerStatus, params);
|
2020-05-25 09:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
|
|
return this.eventEmitter.event;
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
ctx.pushExtCleanup(
|
2023-07-11 13:35:10 +00:00
|
|
|
vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-status", tdcp),
|
2020-05-25 09:10:31 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
return async () => {
|
|
|
|
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
2021-08-09 16:24:43 +00:00
|
|
|
tdcp.eventEmitter.fire(tdcp.uri);
|
|
|
|
void (await vscode.window.showTextDocument(document, {
|
|
|
|
viewColumn: vscode.ViewColumn.Two,
|
|
|
|
preserveFocus: true,
|
|
|
|
}));
|
2020-05-25 09:10:31 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function memoryUsage(ctx: CtxInit): Cmd {
|
2020-07-07 10:10:14 +00:00
|
|
|
const tdcp = new (class implements vscode.TextDocumentContentProvider {
|
|
|
|
readonly uri = vscode.Uri.parse("rust-analyzer-memory://memory");
|
|
|
|
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
|
|
|
|
|
|
provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
|
|
|
|
if (!vscode.window.activeTextEditor) return "";
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => {
|
|
|
|
return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)";
|
|
|
|
});
|
2020-07-07 10:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
|
|
return this.eventEmitter.event;
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
ctx.pushExtCleanup(
|
2023-07-11 13:35:10 +00:00
|
|
|
vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-memory", tdcp),
|
2020-07-07 10:10:14 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
return async () => {
|
|
|
|
tdcp.eventEmitter.fire(tdcp.uri);
|
|
|
|
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
|
|
|
return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function shuffleCrateGraph(ctx: CtxInit): Cmd {
|
2021-12-07 14:38:12 +00:00
|
|
|
return async () => {
|
2022-10-28 22:44:37 +00:00
|
|
|
return ctx.client.sendRequest(ra.shuffleCrateGraph);
|
2021-12-07 14:38:12 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-14 13:45:48 +00:00
|
|
|
export function triggerParameterHints(_: CtxInit): Cmd {
|
|
|
|
return async () => {
|
2023-04-20 19:13:33 +00:00
|
|
|
const parameterHintsEnabled = vscode.workspace
|
|
|
|
.getConfiguration("editor")
|
|
|
|
.get<boolean>("parameterHints.enabled");
|
2023-04-20 16:41:15 +00:00
|
|
|
|
2023-04-20 19:13:33 +00:00
|
|
|
if (parameterHintsEnabled) {
|
2023-04-20 16:41:15 +00:00
|
|
|
await vscode.commands.executeCommand("editor.action.triggerParameterHints");
|
|
|
|
}
|
2023-02-14 13:45:48 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-03-10 09:13:30 +00:00
|
|
|
export function openLogs(ctx: CtxInit): Cmd {
|
|
|
|
return async () => {
|
|
|
|
if (ctx.client.outputChannel) {
|
|
|
|
ctx.client.outputChannel.show();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function matchingBrace(ctx: CtxInit): Cmd {
|
2020-05-25 09:10:31 +00:00
|
|
|
return async () => {
|
|
|
|
const editor = ctx.activeRustEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) return;
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-05-25 09:10:31 +00:00
|
|
|
|
|
|
|
const response = await client.sendRequest(ra.matchingBrace, {
|
2022-10-17 12:20:14 +00:00
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
|
2020-05-25 09:10:31 +00:00
|
|
|
positions: editor.selections.map((s) =>
|
2023-07-11 13:35:10 +00:00
|
|
|
client.code2ProtocolConverter.asPosition(s.active),
|
2020-05-25 09:10:31 +00:00
|
|
|
),
|
|
|
|
});
|
|
|
|
editor.selections = editor.selections.map((sel, idx) => {
|
2023-06-27 19:03:53 +00:00
|
|
|
const position = unwrapUndefinable(response[idx]);
|
|
|
|
const active = client.protocol2CodeConverter.asPosition(position);
|
2020-05-25 09:10:31 +00:00
|
|
|
const anchor = sel.isEmpty ? active : sel.anchor;
|
|
|
|
return new vscode.Selection(anchor, active);
|
|
|
|
});
|
|
|
|
editor.revealRange(editor.selection);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function joinLines(ctx: CtxInit): Cmd {
|
2020-05-25 09:10:31 +00:00
|
|
|
return async () => {
|
|
|
|
const editor = ctx.activeRustEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) return;
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-05-25 09:10:31 +00:00
|
|
|
|
|
|
|
const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
|
|
|
|
ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
|
2022-10-17 12:20:14 +00:00
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
|
2020-05-25 09:10:31 +00:00
|
|
|
});
|
2022-05-21 15:38:10 +00:00
|
|
|
const textEdits = await client.protocol2CodeConverter.asTextEdits(items);
|
|
|
|
await editor.edit((builder) => {
|
|
|
|
textEdits.forEach((edit: any) => {
|
2020-05-25 09:10:31 +00:00
|
|
|
builder.replace(edit.range, edit.newText);
|
|
|
|
});
|
2021-02-09 14:12:46 +00:00
|
|
|
});
|
2020-05-25 09:10:31 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function moveItemUp(ctx: CtxInit): Cmd {
|
2023-01-23 14:26:28 +00:00
|
|
|
return moveItem(ctx, "Up");
|
2021-03-16 12:37:00 +00:00
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function moveItemDown(ctx: CtxInit): Cmd {
|
2023-01-23 14:26:28 +00:00
|
|
|
return moveItem(ctx, "Down");
|
2021-03-16 12:37:00 +00:00
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function moveItem(ctx: CtxInit, direction: ra.Direction): Cmd {
|
2021-03-16 12:37:00 +00:00
|
|
|
return async () => {
|
|
|
|
const editor = ctx.activeRustEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) return;
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2021-03-16 12:37:00 +00:00
|
|
|
|
2021-04-13 18:32:45 +00:00
|
|
|
const lcEdits = await client.sendRequest(ra.moveItem, {
|
2021-03-16 12:37:00 +00:00
|
|
|
range: client.code2ProtocolConverter.asRange(editor.selection),
|
2022-10-17 12:20:14 +00:00
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
|
2021-03-16 12:37:00 +00:00
|
|
|
direction,
|
|
|
|
});
|
|
|
|
|
2021-04-13 18:32:45 +00:00
|
|
|
if (!lcEdits) return;
|
2021-03-16 14:57:14 +00:00
|
|
|
|
2022-04-08 11:24:28 +00:00
|
|
|
const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits);
|
2021-04-13 18:32:45 +00:00
|
|
|
await applySnippetTextEdits(editor, edits);
|
2021-03-16 12:37:00 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function onEnter(ctx: CtxInit): Cmd {
|
2020-05-25 09:10:31 +00:00
|
|
|
async function handleKeypress() {
|
|
|
|
const editor = ctx.activeRustEditor;
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) return false;
|
2020-05-25 09:10:31 +00:00
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-05-25 12:12:53 +00:00
|
|
|
const lcEdits = await client
|
|
|
|
.sendRequest(ra.onEnter, {
|
2022-10-17 12:20:14 +00:00
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
|
2023-07-11 13:35:10 +00:00
|
|
|
editor.document,
|
2020-09-29 20:05:18 +00:00
|
|
|
),
|
2020-05-25 09:10:31 +00:00
|
|
|
position: client.code2ProtocolConverter.asPosition(editor.selection.active),
|
2020-09-01 16:53:07 +00:00
|
|
|
})
|
|
|
|
.catch((_error: any) => {
|
|
|
|
// client.handleFailedRequest(OnEnterRequest.type, error, null);
|
2020-05-25 09:10:31 +00:00
|
|
|
return null;
|
|
|
|
});
|
2020-05-25 12:12:53 +00:00
|
|
|
if (!lcEdits) return false;
|
2020-05-25 09:10:31 +00:00
|
|
|
|
2022-04-08 11:24:28 +00:00
|
|
|
const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits);
|
2020-05-25 12:12:53 +00:00
|
|
|
await applySnippetTextEdits(editor, edits);
|
2020-05-25 09:10:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return async () => {
|
|
|
|
if (await handleKeypress()) return;
|
|
|
|
|
|
|
|
await vscode.commands.executeCommand("default:type", { text: "\n" });
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function parentModule(ctx: CtxInit): Cmd {
|
2020-05-25 09:10:31 +00:00
|
|
|
return async () => {
|
2021-10-03 02:58:10 +00:00
|
|
|
const editor = vscode.window.activeTextEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) return;
|
2021-10-03 02:58:10 +00:00
|
|
|
if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return;
|
2021-10-13 22:16:42 +00:00
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2022-10-17 12:20:14 +00:00
|
|
|
|
2021-03-15 14:49:20 +00:00
|
|
|
const locations = await client.sendRequest(ra.parentModule, {
|
2022-10-17 12:20:14 +00:00
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
|
2021-03-15 14:49:20 +00:00
|
|
|
position: client.code2ProtocolConverter.asPosition(editor.selection.active),
|
2020-05-25 09:10:31 +00:00
|
|
|
});
|
2021-10-13 22:16:42 +00:00
|
|
|
if (!locations) return;
|
2020-05-25 09:10:31 +00:00
|
|
|
|
2021-03-15 14:49:20 +00:00
|
|
|
if (locations.length === 1) {
|
2023-06-27 19:03:53 +00:00
|
|
|
const loc = unwrapUndefinable(locations[0]);
|
2020-05-25 09:10:31 +00:00
|
|
|
|
2021-03-15 14:49:20 +00:00
|
|
|
const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
|
|
|
|
const range = client.protocol2CodeConverter.asRange(loc.targetRange);
|
|
|
|
|
|
|
|
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);
|
|
|
|
} else {
|
|
|
|
const uri = editor.document.uri.toString();
|
|
|
|
const position = client.code2ProtocolConverter.asPosition(editor.selection.active);
|
|
|
|
await showReferencesImpl(
|
|
|
|
client,
|
|
|
|
uri,
|
|
|
|
position,
|
2023-07-11 13:35:10 +00:00
|
|
|
locations.map((loc) => lc.Location.create(loc.targetUri, loc.targetRange)),
|
2021-03-15 14:49:20 +00:00
|
|
|
);
|
|
|
|
}
|
2020-05-25 09:10:31 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function openCargoToml(ctx: CtxInit): Cmd {
|
2020-11-13 01:48:07 +00:00
|
|
|
return async () => {
|
|
|
|
const editor = ctx.activeRustEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) return;
|
2020-11-13 01:48:07 +00:00
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-11-13 01:48:07 +00:00
|
|
|
const response = await client.sendRequest(ra.openCargoToml, {
|
2022-10-17 12:20:14 +00:00
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
|
2020-11-13 01:48:07 +00:00
|
|
|
});
|
|
|
|
if (!response) return;
|
|
|
|
|
|
|
|
const uri = client.protocol2CodeConverter.asUri(response.uri);
|
|
|
|
const range = client.protocol2CodeConverter.asRange(response.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);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-02-26 00:37:55 +00:00
|
|
|
export function revealDependency(ctx: CtxInit): Cmd {
|
|
|
|
return async (editor: RustEditor) => {
|
2023-04-27 19:13:05 +00:00
|
|
|
if (!ctx.dependencies?.isInitialized()) {
|
|
|
|
return;
|
|
|
|
}
|
2022-02-26 00:37:55 +00:00
|
|
|
const documentPath = editor.document.uri.fsPath;
|
2023-04-03 00:58:20 +00:00
|
|
|
const dep = ctx.dependencies?.getDependency(documentPath);
|
2022-02-26 00:37:55 +00:00
|
|
|
if (dep) {
|
2023-04-03 00:58:20 +00:00
|
|
|
await ctx.treeView?.reveal(dep, { select: true, expand: true });
|
2022-02-26 00:37:55 +00:00
|
|
|
} else {
|
2023-04-05 17:57:01 +00:00
|
|
|
await revealParentChain(editor.document, ctx);
|
2022-02-26 00:37:55 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-04-05 17:57:01 +00:00
|
|
|
/**
|
|
|
|
* This function calculates the parent chain of a given file until it reaches it crate root contained in ctx.dependencies.
|
|
|
|
* This is need because the TreeView is Lazy, so at first it only has the root dependencies: For example if we have the following crates:
|
|
|
|
* - core
|
|
|
|
* - alloc
|
|
|
|
* - std
|
|
|
|
*
|
|
|
|
* if I want to reveal alloc/src/str.rs, I have to:
|
|
|
|
|
|
|
|
* 1. reveal every children of alloc
|
|
|
|
* - core
|
|
|
|
* - alloc\
|
|
|
|
*  |-beches\
|
|
|
|
*  |-src\
|
|
|
|
*  |- ...
|
|
|
|
* - std
|
|
|
|
* 2. reveal every children of src:
|
|
|
|
* core
|
|
|
|
* alloc\
|
|
|
|
*  |-beches\
|
|
|
|
*  |-src\
|
|
|
|
*   |- lib.rs\
|
|
|
|
*   |- str.rs <------- FOUND IT!\
|
|
|
|
*   |- ...\
|
|
|
|
*  |- ...\
|
|
|
|
* std
|
|
|
|
*/
|
|
|
|
async function revealParentChain(document: RustDocument, ctx: CtxInit) {
|
|
|
|
let documentPath = document.uri.fsPath;
|
|
|
|
const maxDepth = documentPath.split(path.sep).length - 1;
|
|
|
|
const parentChain: DependencyId[] = [{ id: documentPath.toLowerCase() }];
|
|
|
|
do {
|
|
|
|
documentPath = path.dirname(documentPath);
|
|
|
|
parentChain.push({ id: documentPath.toLowerCase() });
|
|
|
|
if (parentChain.length >= maxDepth) {
|
|
|
|
// this is an odd case that can happen when we change a crate version but we'd still have
|
|
|
|
// a open file referencing the old version
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} while (!ctx.dependencies?.contains(documentPath));
|
|
|
|
parentChain.reverse();
|
|
|
|
for (const idx in parentChain) {
|
2023-06-27 19:03:53 +00:00
|
|
|
const treeView = ctx.treeView;
|
|
|
|
if (!treeView) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const dependency = unwrapUndefinable(parentChain[idx]);
|
|
|
|
await treeView.reveal(dependency, { select: true, expand: true });
|
2023-04-05 17:57:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-26 00:37:55 +00:00
|
|
|
export async function execRevealDependency(e: RustEditor): Promise<void> {
|
2022-07-17 15:38:56 +00:00
|
|
|
await vscode.commands.executeCommand("rust-analyzer.revealDependency", e);
|
2022-02-26 00:37:55 +00:00
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function ssr(ctx: CtxInit): Cmd {
|
2020-05-25 09:10:31 +00:00
|
|
|
return async () => {
|
2020-07-22 05:00:28 +00:00
|
|
|
const editor = vscode.window.activeTextEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) return;
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-07-22 05:00:28 +00:00
|
|
|
|
|
|
|
const position = editor.selection.active;
|
2020-07-29 01:44:01 +00:00
|
|
|
const selections = editor.selections;
|
2022-10-17 12:20:14 +00:00
|
|
|
const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(
|
2023-07-11 13:35:10 +00:00
|
|
|
editor.document,
|
2020-09-29 20:05:18 +00:00
|
|
|
);
|
2020-05-25 09:10:31 +00:00
|
|
|
|
|
|
|
const options: vscode.InputBoxOptions = {
|
|
|
|
value: "() ==>> ()",
|
2020-09-15 11:32:56 +00:00
|
|
|
prompt: "Enter request, for example 'Foo($a) ==>> Foo::new($a)' ",
|
2020-05-25 09:10:31 +00:00
|
|
|
validateInput: async (x: string) => {
|
|
|
|
try {
|
2020-07-22 05:00:28 +00:00
|
|
|
await client.sendRequest(ra.ssr, {
|
2020-07-29 01:44:01 +00:00
|
|
|
query: x,
|
|
|
|
parseOnly: true,
|
|
|
|
textDocument,
|
|
|
|
position,
|
|
|
|
selections,
|
2020-07-22 05:00:28 +00:00
|
|
|
});
|
2020-05-25 09:10:31 +00:00
|
|
|
} catch (e) {
|
2023-07-10 14:03:08 +00:00
|
|
|
return String(e);
|
2020-05-25 09:10:31 +00:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const request = await vscode.window.showInputBox(options);
|
|
|
|
if (!request) return;
|
|
|
|
|
2021-02-09 14:12:46 +00:00
|
|
|
await vscode.window.withProgress(
|
|
|
|
{
|
2020-06-29 09:17:35 +00:00
|
|
|
location: vscode.ProgressLocation.Notification,
|
|
|
|
title: "Structured search replace in progress...",
|
|
|
|
cancellable: false,
|
2022-04-08 11:24:28 +00:00
|
|
|
},
|
|
|
|
async (_progress, token) => {
|
2020-07-22 05:00:28 +00:00
|
|
|
const edit = await client.sendRequest(ra.ssr, {
|
2020-07-29 01:44:01 +00:00
|
|
|
query: request,
|
|
|
|
parseOnly: false,
|
|
|
|
textDocument,
|
|
|
|
position,
|
|
|
|
selections,
|
2020-07-22 05:00:28 +00:00
|
|
|
});
|
2022-05-17 17:15:06 +00:00
|
|
|
|
2022-04-08 11:24:28 +00:00
|
|
|
await vscode.workspace.applyEdit(
|
2023-07-11 13:35:10 +00:00
|
|
|
await client.protocol2CodeConverter.asWorkspaceEdit(edit, token),
|
2022-04-08 11:24:28 +00:00
|
|
|
);
|
2023-07-11 13:35:10 +00:00
|
|
|
},
|
2021-02-09 14:12:46 +00:00
|
|
|
);
|
2020-05-25 09:10:31 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function serverVersion(ctx: CtxInit): Cmd {
|
2020-05-25 09:10:31 +00:00
|
|
|
return async () => {
|
2022-10-17 12:53:46 +00:00
|
|
|
if (!ctx.serverPath) {
|
|
|
|
void vscode.window.showWarningMessage(`rust-analyzer server is not running`);
|
|
|
|
return;
|
|
|
|
}
|
2020-05-25 09:10:31 +00:00
|
|
|
const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
|
2021-03-12 17:49:00 +00:00
|
|
|
const versionString = stdout.slice(`rust-analyzer `.length).trim();
|
2020-05-25 09:10:31 +00:00
|
|
|
|
|
|
|
void vscode.window.showInformationMessage(`rust-analyzer version: ${versionString}`);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-05-25 10:02:30 +00:00
|
|
|
// Opens the virtual file that will show the syntax tree
|
|
|
|
//
|
|
|
|
// The contents of the file come from the `TextDocumentContentProvider`
|
2022-10-28 22:44:37 +00:00
|
|
|
export function syntaxTree(ctx: CtxInit): Cmd {
|
2020-05-25 10:02:30 +00:00
|
|
|
const tdcp = new (class implements vscode.TextDocumentContentProvider {
|
2022-07-06 15:36:42 +00:00
|
|
|
readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast");
|
2020-05-25 10:02:30 +00:00
|
|
|
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
|
|
constructor() {
|
|
|
|
vscode.workspace.onDidChangeTextDocument(
|
|
|
|
this.onDidChangeTextDocument,
|
|
|
|
this,
|
2023-07-11 13:35:10 +00:00
|
|
|
ctx.subscriptions,
|
2020-05-25 10:02:30 +00:00
|
|
|
);
|
|
|
|
vscode.window.onDidChangeActiveTextEditor(
|
|
|
|
this.onDidChangeActiveTextEditor,
|
|
|
|
this,
|
2023-07-11 13:35:10 +00:00
|
|
|
ctx.subscriptions,
|
2020-05-25 10:02:30 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
async provideTextDocumentContent(
|
2020-05-25 10:02:30 +00:00
|
|
|
uri: vscode.Uri,
|
2023-07-11 13:35:10 +00:00
|
|
|
ct: vscode.CancellationToken,
|
2022-10-17 12:20:14 +00:00
|
|
|
): Promise<string> {
|
2020-05-25 10:02:30 +00:00
|
|
|
const rustEditor = ctx.activeRustEditor;
|
|
|
|
if (!rustEditor) return "";
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-05-25 10:02:30 +00:00
|
|
|
|
|
|
|
// When the range based query is enabled we take the range of the selection
|
|
|
|
const range =
|
|
|
|
uri.query === "range=true" && !rustEditor.selection.isEmpty
|
2022-10-17 12:20:14 +00:00
|
|
|
? client.code2ProtocolConverter.asRange(rustEditor.selection)
|
2020-05-25 10:02:30 +00:00
|
|
|
: null;
|
|
|
|
|
|
|
|
const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range };
|
2022-10-17 12:20:14 +00:00
|
|
|
return client.sendRequest(ra.syntaxTree, params, ct);
|
2020-05-25 10:02:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
|
|
return this.eventEmitter.event;
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2022-10-17 13:05:20 +00:00
|
|
|
ctx.pushExtCleanup(new AstInspector(ctx));
|
2022-10-17 12:20:14 +00:00
|
|
|
ctx.pushExtCleanup(
|
2023-07-11 13:35:10 +00:00
|
|
|
vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp),
|
2022-07-06 15:36:42 +00:00
|
|
|
);
|
2022-10-17 12:20:14 +00:00
|
|
|
ctx.pushExtCleanup(
|
2020-05-25 10:02:30 +00:00
|
|
|
vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
|
|
|
|
brackets: [["[", ")"]],
|
2023-07-11 13:35:10 +00:00
|
|
|
}),
|
2020-05-25 10:02:30 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
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,
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-26 12:34:41 +00:00
|
|
|
function viewHirOrMir(ctx: CtxInit, xir: "hir" | "mir"): Cmd {
|
|
|
|
const viewXir = xir === "hir" ? "viewHir" : "viewMir";
|
|
|
|
const requestType = xir === "hir" ? ra.viewHir : ra.viewMir;
|
2023-04-28 17:14:30 +00:00
|
|
|
const uri = `rust-analyzer-${xir}://${viewXir}/${xir}.rs`;
|
|
|
|
const scheme = `rust-analyzer-${xir}`;
|
|
|
|
return viewFileUsingTextDocumentContentProvider(ctx, requestType, uri, scheme, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
function viewFileUsingTextDocumentContentProvider(
|
|
|
|
ctx: CtxInit,
|
|
|
|
requestType: lc.RequestType<lc.TextDocumentPositionParams, string, void>,
|
|
|
|
uri: string,
|
|
|
|
scheme: string,
|
2023-07-11 13:35:10 +00:00
|
|
|
shouldUpdate: boolean,
|
2023-04-28 17:14:30 +00:00
|
|
|
): Cmd {
|
2020-12-28 18:29:58 +00:00
|
|
|
const tdcp = new (class implements vscode.TextDocumentContentProvider {
|
2023-04-28 17:14:30 +00:00
|
|
|
readonly uri = vscode.Uri.parse(uri);
|
2020-12-28 18:29:58 +00:00
|
|
|
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
|
|
constructor() {
|
|
|
|
vscode.workspace.onDidChangeTextDocument(
|
|
|
|
this.onDidChangeTextDocument,
|
|
|
|
this,
|
2023-07-11 13:35:10 +00:00
|
|
|
ctx.subscriptions,
|
2020-12-28 18:29:58 +00:00
|
|
|
);
|
|
|
|
vscode.window.onDidChangeActiveTextEditor(
|
|
|
|
this.onDidChangeActiveTextEditor,
|
|
|
|
this,
|
2023-07-11 13:35:10 +00:00
|
|
|
ctx.subscriptions,
|
2020-12-28 18:29:58 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
|
2023-04-28 17:14:30 +00:00
|
|
|
if (isRustDocument(event.document) && shouldUpdate) {
|
2020-12-28 18:29:58 +00:00
|
|
|
// 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) {
|
2023-04-28 17:14:30 +00:00
|
|
|
if (editor && isRustEditor(editor) && shouldUpdate) {
|
2020-12-28 18:29:58 +00:00
|
|
|
this.eventEmitter.fire(this.uri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
async provideTextDocumentContent(
|
2020-12-28 18:29:58 +00:00
|
|
|
_uri: vscode.Uri,
|
2023-07-11 13:35:10 +00:00
|
|
|
ct: vscode.CancellationToken,
|
2022-10-17 12:20:14 +00:00
|
|
|
): Promise<string> {
|
2020-12-28 18:29:58 +00:00
|
|
|
const rustEditor = ctx.activeRustEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!rustEditor) return "";
|
2020-12-28 18:29:58 +00:00
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-12-28 18:29:58 +00:00
|
|
|
const params = {
|
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
|
2023-07-11 13:35:10 +00:00
|
|
|
rustEditor.document,
|
2020-12-28 18:29:58 +00:00
|
|
|
),
|
2021-03-15 14:49:20 +00:00
|
|
|
position: client.code2ProtocolConverter.asPosition(rustEditor.selection.active),
|
2020-12-28 18:29:58 +00:00
|
|
|
};
|
2023-02-26 12:34:41 +00:00
|
|
|
return client.sendRequest(requestType, params, ct);
|
2020-12-28 18:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
|
|
return this.eventEmitter.event;
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2023-04-28 17:14:30 +00:00
|
|
|
ctx.pushExtCleanup(vscode.workspace.registerTextDocumentContentProvider(scheme, tdcp));
|
2022-03-31 12:50:33 +00:00
|
|
|
|
|
|
|
return async () => {
|
|
|
|
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
|
|
|
tdcp.eventEmitter.fire(tdcp.uri);
|
|
|
|
void (await vscode.window.showTextDocument(document, {
|
|
|
|
viewColumn: vscode.ViewColumn.Two,
|
|
|
|
preserveFocus: true,
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-26 12:34:41 +00:00
|
|
|
// Opens the virtual file that will show the HIR of the function containing the cursor position
|
|
|
|
//
|
|
|
|
// The contents of the file come from the `TextDocumentContentProvider`
|
|
|
|
export function viewHir(ctx: CtxInit): Cmd {
|
|
|
|
return viewHirOrMir(ctx, "hir");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Opens the virtual file that will show the MIR of the function containing the cursor position
|
|
|
|
//
|
|
|
|
// The contents of the file come from the `TextDocumentContentProvider`
|
|
|
|
export function viewMir(ctx: CtxInit): Cmd {
|
|
|
|
return viewHirOrMir(ctx, "mir");
|
|
|
|
}
|
|
|
|
|
2023-04-28 17:14:30 +00:00
|
|
|
// Opens the virtual file that will show the MIR of the function containing the cursor position
|
|
|
|
//
|
|
|
|
// The contents of the file come from the `TextDocumentContentProvider`
|
|
|
|
export function interpretFunction(ctx: CtxInit): Cmd {
|
|
|
|
const uri = `rust-analyzer-interpret-function://interpretFunction/result.log`;
|
|
|
|
return viewFileUsingTextDocumentContentProvider(
|
|
|
|
ctx,
|
|
|
|
ra.interpretFunction,
|
|
|
|
uri,
|
|
|
|
`rust-analyzer-interpret-function`,
|
2023-07-11 13:35:10 +00:00
|
|
|
false,
|
2023-04-28 17:14:30 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function viewFileText(ctx: CtxInit): Cmd {
|
2022-03-31 12:50:33 +00:00
|
|
|
const tdcp = new (class implements vscode.TextDocumentContentProvider {
|
2022-07-06 15:36:42 +00:00
|
|
|
readonly uri = vscode.Uri.parse("rust-analyzer-file-text://viewFileText/file.rs");
|
2022-03-31 12:50:33 +00:00
|
|
|
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
|
|
constructor() {
|
|
|
|
vscode.workspace.onDidChangeTextDocument(
|
|
|
|
this.onDidChangeTextDocument,
|
|
|
|
this,
|
2023-07-11 13:35:10 +00:00
|
|
|
ctx.subscriptions,
|
2022-03-31 12:50:33 +00:00
|
|
|
);
|
|
|
|
vscode.window.onDidChangeActiveTextEditor(
|
|
|
|
this.onDidChangeActiveTextEditor,
|
|
|
|
this,
|
2023-07-11 13:35:10 +00:00
|
|
|
ctx.subscriptions,
|
2022-03-31 12:50:33 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
async provideTextDocumentContent(
|
2022-03-31 12:50:33 +00:00
|
|
|
_uri: vscode.Uri,
|
2023-07-11 13:35:10 +00:00
|
|
|
ct: vscode.CancellationToken,
|
2022-10-17 12:20:14 +00:00
|
|
|
): Promise<string> {
|
2022-03-31 12:50:33 +00:00
|
|
|
const rustEditor = ctx.activeRustEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!rustEditor) return "";
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2022-03-31 12:50:33 +00:00
|
|
|
|
|
|
|
const params = client.code2ProtocolConverter.asTextDocumentIdentifier(
|
2023-07-11 13:35:10 +00:00
|
|
|
rustEditor.document,
|
2022-03-31 12:50:33 +00:00
|
|
|
);
|
|
|
|
return client.sendRequest(ra.viewFileText, params, ct);
|
|
|
|
}
|
|
|
|
|
|
|
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
|
|
return this.eventEmitter.event;
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
ctx.pushExtCleanup(
|
2023-07-11 13:35:10 +00:00
|
|
|
vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-file-text", tdcp),
|
2022-07-06 15:36:42 +00:00
|
|
|
);
|
2020-12-28 18:29:58 +00:00
|
|
|
|
|
|
|
return async () => {
|
2021-01-01 19:35:10 +00:00
|
|
|
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
|
|
|
tdcp.eventEmitter.fire(tdcp.uri);
|
2020-12-28 18:29:58 +00:00
|
|
|
void (await vscode.window.showTextDocument(document, {
|
|
|
|
viewColumn: vscode.ViewColumn.Two,
|
|
|
|
preserveFocus: true,
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
}
|
2020-05-25 10:02:30 +00:00
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function viewItemTree(ctx: CtxInit): Cmd {
|
2021-05-21 21:59:52 +00:00
|
|
|
const tdcp = new (class implements vscode.TextDocumentContentProvider {
|
2022-07-06 15:36:42 +00:00
|
|
|
readonly uri = vscode.Uri.parse("rust-analyzer-item-tree://viewItemTree/itemtree.rs");
|
2021-05-21 21:59:52 +00:00
|
|
|
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
|
|
constructor() {
|
|
|
|
vscode.workspace.onDidChangeTextDocument(
|
|
|
|
this.onDidChangeTextDocument,
|
|
|
|
this,
|
2023-07-11 13:35:10 +00:00
|
|
|
ctx.subscriptions,
|
2021-05-21 21:59:52 +00:00
|
|
|
);
|
|
|
|
vscode.window.onDidChangeActiveTextEditor(
|
|
|
|
this.onDidChangeActiveTextEditor,
|
|
|
|
this,
|
2023-07-11 13:35:10 +00:00
|
|
|
ctx.subscriptions,
|
2021-05-21 21:59:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
async provideTextDocumentContent(
|
2021-05-21 21:59:52 +00:00
|
|
|
_uri: vscode.Uri,
|
2023-07-11 13:35:10 +00:00
|
|
|
ct: vscode.CancellationToken,
|
2022-10-17 12:20:14 +00:00
|
|
|
): Promise<string> {
|
2021-05-21 21:59:52 +00:00
|
|
|
const rustEditor = ctx.activeRustEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!rustEditor) return "";
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2021-05-21 21:59:52 +00:00
|
|
|
|
|
|
|
const params = {
|
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
|
2023-07-11 13:35:10 +00:00
|
|
|
rustEditor.document,
|
2021-05-21 21:59:52 +00:00
|
|
|
),
|
|
|
|
};
|
|
|
|
return client.sendRequest(ra.viewItemTree, params, ct);
|
|
|
|
}
|
|
|
|
|
|
|
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
|
|
return this.eventEmitter.event;
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
ctx.pushExtCleanup(
|
2023-07-11 13:35:10 +00:00
|
|
|
vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-item-tree", tdcp),
|
2022-07-06 15:36:42 +00:00
|
|
|
);
|
2021-05-21 21:59:52 +00:00
|
|
|
|
|
|
|
return async () => {
|
|
|
|
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
|
|
|
tdcp.eventEmitter.fire(tdcp.uri);
|
|
|
|
void (await vscode.window.showTextDocument(document, {
|
|
|
|
viewColumn: vscode.ViewColumn.Two,
|
|
|
|
preserveFocus: true,
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
function crateGraph(ctx: CtxInit, full: boolean): Cmd {
|
2021-05-11 14:15:31 +00:00
|
|
|
return async () => {
|
2021-08-09 17:45:42 +00:00
|
|
|
const nodeModulesPath = vscode.Uri.file(path.join(ctx.extensionPath, "node_modules"));
|
2021-08-06 17:14:47 +00:00
|
|
|
|
2021-08-10 13:34:30 +00:00
|
|
|
const panel = vscode.window.createWebviewPanel(
|
|
|
|
"rust-analyzer.crate-graph",
|
|
|
|
"rust-analyzer crate graph",
|
|
|
|
vscode.ViewColumn.Two,
|
|
|
|
{
|
|
|
|
enableScripts: true,
|
2021-08-10 13:35:37 +00:00
|
|
|
retainContextWhenHidden: true,
|
2021-08-09 17:45:42 +00:00
|
|
|
localResourceRoots: [nodeModulesPath],
|
2023-07-11 13:35:10 +00:00
|
|
|
},
|
2021-08-10 13:35:37 +00:00
|
|
|
);
|
2021-07-01 22:08:05 +00:00
|
|
|
const params = {
|
|
|
|
full: full,
|
|
|
|
};
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2022-10-17 12:20:14 +00:00
|
|
|
const dot = await client.sendRequest(ra.viewCrateGraph, params);
|
2021-08-10 12:42:50 +00:00
|
|
|
const uri = panel.webview.asWebviewUri(nodeModulesPath);
|
2021-08-10 13:35:37 +00:00
|
|
|
|
2021-08-10 13:34:30 +00:00
|
|
|
const html = `
|
2021-08-09 07:01:42 +00:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<meta charset="utf-8">
|
|
|
|
<head>
|
|
|
|
<style>
|
|
|
|
/* Fill the entire view */
|
|
|
|
html, body { margin:0; padding:0; overflow:hidden }
|
|
|
|
svg { position:fixed; top:0; left:0; height:100%; width:100% }
|
|
|
|
|
2022-08-17 13:44:58 +00:00
|
|
|
/* Disable the graphviz background and fill the polygons */
|
2021-08-09 07:01:42 +00:00
|
|
|
.graph > polygon { display:none; }
|
|
|
|
:is(.node,.edge) polygon { fill: white; }
|
|
|
|
|
|
|
|
/* Invert the line colours for dark themes */
|
|
|
|
body:not(.vscode-light) .edge path { stroke: white; }
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
2021-08-10 12:42:50 +00:00
|
|
|
<script type="text/javascript" src="${uri}/d3/dist/d3.min.js"></script>
|
2023-04-13 15:38:12 +00:00
|
|
|
<script type="text/javascript" src="${uri}/@hpcc-js/wasm/dist/graphviz.umd.js"></script>
|
2021-08-10 12:42:50 +00:00
|
|
|
<script type="text/javascript" src="${uri}/d3-graphviz/build/d3-graphviz.min.js"></script>
|
2021-08-09 07:01:42 +00:00
|
|
|
<div id="graph"></div>
|
|
|
|
<script>
|
2023-04-13 20:01:57 +00:00
|
|
|
let dot = \`${dot}\`;
|
2021-08-09 07:01:42 +00:00
|
|
|
let graph = d3.select("#graph")
|
2023-04-13 15:38:12 +00:00
|
|
|
.graphviz({ useWorker: false, useSharedWorker: false })
|
2021-08-09 07:01:42 +00:00
|
|
|
.fit(true)
|
|
|
|
.zoomScaleExtent([0.1, Infinity])
|
2023-04-13 20:01:57 +00:00
|
|
|
.renderDot(dot);
|
2021-08-09 07:01:42 +00:00
|
|
|
|
|
|
|
d3.select(window).on("click", (event) => {
|
|
|
|
if (event.ctrlKey) {
|
|
|
|
graph.resetZoom(d3.transition().duration(100));
|
|
|
|
}
|
|
|
|
});
|
2023-04-13 20:01:57 +00:00
|
|
|
d3.select(window).on("copy", (event) => {
|
|
|
|
event.clipboardData.setData("text/plain", dot);
|
|
|
|
event.preventDefault();
|
|
|
|
});
|
2021-08-09 07:01:42 +00:00
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
`;
|
2021-08-10 13:34:30 +00:00
|
|
|
|
|
|
|
panel.webview.html = html;
|
2021-05-11 14:15:31 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function viewCrateGraph(ctx: CtxInit): Cmd {
|
2021-07-01 22:08:05 +00:00
|
|
|
return crateGraph(ctx, false);
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function viewFullCrateGraph(ctx: CtxInit): Cmd {
|
2021-07-01 22:08:05 +00:00
|
|
|
return crateGraph(ctx, true);
|
|
|
|
}
|
|
|
|
|
2020-05-25 09:10:31 +00:00
|
|
|
// Opens the virtual file that will show the syntax tree
|
|
|
|
//
|
|
|
|
// The contents of the file come from the `TextDocumentContentProvider`
|
2022-10-28 22:44:37 +00:00
|
|
|
export function expandMacro(ctx: CtxInit): Cmd {
|
2020-05-25 09:10:31 +00:00
|
|
|
function codeFormat(expanded: ra.ExpandedMacro): string {
|
2023-04-02 10:45:39 +00:00
|
|
|
let result = `// Recursive expansion of ${expanded.name} macro\n`;
|
2020-05-25 09:10:31 +00:00
|
|
|
result += "// " + "=".repeat(result.length - 3);
|
|
|
|
result += "\n\n";
|
|
|
|
result += expanded.expansion;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
const tdcp = new (class implements vscode.TextDocumentContentProvider {
|
2022-07-06 15:36:42 +00:00
|
|
|
uri = vscode.Uri.parse("rust-analyzer-expand-macro://expandMacro/[EXPANSION].rs");
|
2020-05-25 09:10:31 +00:00
|
|
|
eventEmitter = new vscode.EventEmitter<vscode.Uri>();
|
|
|
|
async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
|
|
|
|
const editor = vscode.window.activeTextEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) return "";
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-05-25 09:10:31 +00:00
|
|
|
|
|
|
|
const position = editor.selection.active;
|
|
|
|
|
|
|
|
const expanded = await client.sendRequest(ra.expandMacro, {
|
2022-10-17 12:20:14 +00:00
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
|
2023-07-11 13:35:10 +00:00
|
|
|
editor.document,
|
2020-09-29 20:05:18 +00:00
|
|
|
),
|
2020-05-25 09:10:31 +00:00
|
|
|
position,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (expanded == null) return "Not available";
|
|
|
|
|
|
|
|
return codeFormat(expanded);
|
|
|
|
}
|
|
|
|
|
|
|
|
get onDidChange(): vscode.Event<vscode.Uri> {
|
|
|
|
return this.eventEmitter.event;
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
ctx.pushExtCleanup(
|
2023-07-11 13:35:10 +00:00
|
|
|
vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-expand-macro", tdcp),
|
2022-07-06 15:36:42 +00:00
|
|
|
);
|
2020-05-25 09:10:31 +00:00
|
|
|
|
|
|
|
return async () => {
|
|
|
|
const document = await vscode.workspace.openTextDocument(tdcp.uri);
|
|
|
|
tdcp.eventEmitter.fire(tdcp.uri);
|
|
|
|
return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
|
|
|
|
};
|
|
|
|
}
|
2020-02-02 19:37:22 +00:00
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function reloadWorkspace(ctx: CtxInit): Cmd {
|
|
|
|
return async () => ctx.client.sendRequest(ra.reloadWorkspace);
|
2019-12-30 13:53:43 +00:00
|
|
|
}
|
|
|
|
|
2023-03-26 06:39:28 +00:00
|
|
|
export function rebuildProcMacros(ctx: CtxInit): Cmd {
|
|
|
|
return async () => ctx.client.sendRequest(ra.rebuildProcMacros);
|
2023-03-25 15:47:41 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 20:06:26 +00:00
|
|
|
export function addProject(ctx: CtxInit): Cmd {
|
|
|
|
return async () => {
|
2023-09-05 16:02:30 +00:00
|
|
|
const extensionName = ctx.config.discoverProjectRunner;
|
|
|
|
// this command shouldn't be enabled in the first place if this isn't set.
|
|
|
|
if (!extensionName) {
|
2023-03-09 20:06:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-05 16:02:30 +00:00
|
|
|
const command = `${extensionName}.discoverWorkspaceCommand`;
|
2023-09-05 16:34:11 +00:00
|
|
|
const project: JsonProject = await vscode.commands.executeCommand(command);
|
2023-03-09 20:06:26 +00:00
|
|
|
|
2023-09-05 16:02:30 +00:00
|
|
|
ctx.addToDiscoveredWorkspaces([project]);
|
2023-03-11 00:35:05 +00:00
|
|
|
|
|
|
|
// this is a workaround to avoid needing writing the `rust-project.json` into
|
|
|
|
// a workspace-level VS Code-specific settings folder. We'd like to keep the
|
|
|
|
// `rust-project.json` entirely in-memory.
|
|
|
|
await ctx.client?.sendNotification(lc.DidChangeConfigurationNotification.type, {
|
|
|
|
settings: "",
|
2023-03-09 20:06:26 +00:00
|
|
|
});
|
2023-03-09 20:27:24 +00:00
|
|
|
};
|
2023-03-09 20:06:26 +00:00
|
|
|
}
|
|
|
|
|
2021-02-27 17:04:43 +00:00
|
|
|
async function showReferencesImpl(
|
2022-10-17 12:20:14 +00:00
|
|
|
client: LanguageClient | undefined,
|
2021-02-27 17:04:43 +00:00
|
|
|
uri: string,
|
|
|
|
position: lc.Position,
|
2023-07-11 13:35:10 +00:00
|
|
|
locations: lc.Location[],
|
2021-02-27 17:04:43 +00:00
|
|
|
) {
|
|
|
|
if (client) {
|
|
|
|
await vscode.commands.executeCommand(
|
|
|
|
"editor.action.showReferences",
|
|
|
|
vscode.Uri.parse(uri),
|
|
|
|
client.protocol2CodeConverter.asPosition(position),
|
2023-07-11 13:35:10 +00:00
|
|
|
locations.map(client.protocol2CodeConverter.asLocation),
|
2021-02-27 17:04:43 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function showReferences(ctx: CtxInit): Cmd {
|
2021-02-09 14:12:46 +00:00
|
|
|
return async (uri: string, position: lc.Position, locations: lc.Location[]) => {
|
2022-10-28 22:44:37 +00:00
|
|
|
await showReferencesImpl(ctx.client, uri, position, locations);
|
2019-12-30 19:07:04 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function applyActionGroup(_ctx: CtxInit): Cmd {
|
2020-11-10 17:20:01 +00:00
|
|
|
return async (actions: { label: string; arguments: lc.CodeAction }[]) => {
|
2020-05-22 15:29:55 +00:00
|
|
|
const selectedAction = await vscode.window.showQuickPick(actions);
|
|
|
|
if (!selectedAction) return;
|
2021-02-09 14:12:46 +00:00
|
|
|
await vscode.commands.executeCommand(
|
2020-06-02 20:21:48 +00:00
|
|
|
"rust-analyzer.resolveCodeAction",
|
2023-07-11 13:35:10 +00:00
|
|
|
selectedAction.arguments,
|
2021-02-09 14:12:46 +00:00
|
|
|
);
|
2020-06-02 20:21:48 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function gotoLocation(ctx: CtxInit): Cmd {
|
2020-06-10 20:01:19 +00:00
|
|
|
return async (locationLink: lc.LocationLink) => {
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2022-10-17 12:20:14 +00:00
|
|
|
const uri = client.protocol2CodeConverter.asUri(locationLink.targetUri);
|
|
|
|
let range = client.protocol2CodeConverter.asRange(locationLink.targetSelectionRange);
|
|
|
|
// collapse the range to a cursor position
|
|
|
|
range = range.with({ end: range.start });
|
2020-06-10 20:01:19 +00:00
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
await vscode.window.showTextDocument(uri, { selection: range });
|
2020-06-10 20:01:19 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function openDocs(ctx: CtxInit): Cmd {
|
2020-08-30 08:02:29 +00:00
|
|
|
return async () => {
|
|
|
|
const editor = vscode.window.activeTextEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) {
|
2020-09-03 07:55:24 +00:00
|
|
|
return;
|
2020-08-30 08:02:29 +00:00
|
|
|
}
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-08-30 08:02:29 +00:00
|
|
|
|
|
|
|
const position = editor.selection.active;
|
|
|
|
const textDocument = { uri: editor.document.uri.toString() };
|
|
|
|
|
2023-10-08 01:52:15 +00:00
|
|
|
const doclinks = await client.sendRequest(ra.openDocs, { position, textDocument });
|
|
|
|
|
|
|
|
let fileType = vscode.FileType.Unknown;
|
|
|
|
if (typeof doclinks.local === "string") {
|
|
|
|
try {
|
|
|
|
fileType = (await vscode.workspace.fs.stat(vscode.Uri.parse(doclinks.local))).type;
|
|
|
|
} catch (e) {
|
|
|
|
log.debug("stat() threw error. Falling back to web version", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let doclink;
|
|
|
|
if (fileType & vscode.FileType.File) {
|
|
|
|
// file does exist locally
|
|
|
|
doclink = doclinks.local;
|
|
|
|
} else {
|
|
|
|
doclink = doclinks.web;
|
|
|
|
}
|
2020-08-30 08:02:29 +00:00
|
|
|
|
2020-09-01 08:26:10 +00:00
|
|
|
if (doclink != null) {
|
Use vscode.env.openExternal instead of the vscode.open command for docs
According to the VS Code documentation, the vscode.open command opens the URL
_in the editor_ (https://code.visualstudio.com/api/references/commands).
However, in reality, it seems to do so only for file:// URLs, falling back to
other applications for other URL schemes (at least for HTTP/HTTPS).
Until now, the URL to the documentation was always HTTP based, so using the
vscode.open command was perfectly fine. However, displaying local documentation
will be supported from now on (see next commit). Local documentation is not
HTTP-based, but instead addressed via a file:// URL. The file URL would
therefore be opened in VS Code instead of in the browser — this is definitely
not what the user wants.
Therefore, the vscode.env.openExternal function is used instead, this function
never opens the URL in VS Code.
2023-10-08 01:31:23 +00:00
|
|
|
await vscode.env.openExternal(vscode.Uri.parse(doclink));
|
2020-09-01 08:26:10 +00:00
|
|
|
}
|
2020-08-30 08:02:29 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function cancelFlycheck(ctx: CtxInit): Cmd {
|
2022-08-19 06:52:31 +00:00
|
|
|
return async () => {
|
2022-12-17 22:29:25 +00:00
|
|
|
await ctx.client.sendNotification(ra.cancelFlycheck);
|
2022-12-16 21:43:14 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-12-17 22:43:26 +00:00
|
|
|
export function clearFlycheck(ctx: CtxInit): Cmd {
|
|
|
|
return async () => {
|
|
|
|
await ctx.client.sendNotification(ra.clearFlycheck);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-12-16 21:43:14 +00:00
|
|
|
export function runFlycheck(ctx: CtxInit): Cmd {
|
|
|
|
return async () => {
|
|
|
|
const editor = ctx.activeRustEditor;
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2022-12-16 21:43:14 +00:00
|
|
|
const params = editor ? { uri: editor.document.uri.toString() } : null;
|
|
|
|
|
|
|
|
await client.sendNotification(ra.runFlycheck, { textDocument: params });
|
2022-08-19 06:52:31 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function resolveCodeAction(ctx: CtxInit): Cmd {
|
2020-11-10 17:20:01 +00:00
|
|
|
return async (params: lc.CodeAction) => {
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2020-11-10 17:20:01 +00:00
|
|
|
params.command = undefined;
|
2022-12-16 21:43:14 +00:00
|
|
|
const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!item?.edit) {
|
2020-06-02 20:21:48 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-12-29 14:43:17 +00:00
|
|
|
const itemEdit = item.edit;
|
2022-12-16 21:43:14 +00:00
|
|
|
const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
|
2020-12-29 14:43:17 +00:00
|
|
|
// filter out all text edits and recreate the WorkspaceEdit without them so we can apply
|
|
|
|
// snippet edits on our own
|
2021-02-05 20:26:14 +00:00
|
|
|
const lcFileSystemEdit = {
|
|
|
|
...itemEdit,
|
|
|
|
documentChanges: itemEdit.documentChanges?.filter((change) => "kind" in change),
|
|
|
|
};
|
2022-04-08 11:24:28 +00:00
|
|
|
const fileSystemEdit = await client.protocol2CodeConverter.asWorkspaceEdit(
|
2023-07-11 13:35:10 +00:00
|
|
|
lcFileSystemEdit,
|
2022-04-08 11:24:28 +00:00
|
|
|
);
|
2021-02-05 20:26:14 +00:00
|
|
|
await vscode.workspace.applyEdit(fileSystemEdit);
|
2020-12-29 14:43:17 +00:00
|
|
|
await applySnippetWorkspaceEdit(edit);
|
2022-04-19 16:37:18 +00:00
|
|
|
if (item.command != null) {
|
|
|
|
await vscode.commands.executeCommand(item.command.command, item.command.arguments);
|
|
|
|
}
|
2019-12-31 17:55:34 +00:00
|
|
|
};
|
2019-12-30 22:45:50 +00:00
|
|
|
}
|
2020-05-17 23:53:55 +00:00
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function applySnippetWorkspaceEditCommand(_ctx: CtxInit): Cmd {
|
2020-05-17 23:53:55 +00:00
|
|
|
return async (edit: vscode.WorkspaceEdit) => {
|
2020-05-21 12:26:44 +00:00
|
|
|
await applySnippetWorkspaceEdit(edit);
|
|
|
|
};
|
|
|
|
}
|
2020-06-02 12:33:47 +00:00
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function run(ctx: CtxInit): Cmd {
|
2020-06-02 12:33:47 +00:00
|
|
|
let prevRunnable: RunnableQuickPick | undefined;
|
|
|
|
|
|
|
|
return async () => {
|
|
|
|
const item = await selectRunnable(ctx, prevRunnable);
|
|
|
|
if (!item) return;
|
|
|
|
|
|
|
|
item.detail = "rerun";
|
|
|
|
prevRunnable = item;
|
2020-06-18 19:20:13 +00:00
|
|
|
const task = await createTask(item.runnable, ctx.config);
|
2020-06-02 12:33:47 +00:00
|
|
|
return await vscode.tasks.executeTask(task);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function peekTests(ctx: CtxInit): Cmd {
|
2021-02-27 17:04:43 +00:00
|
|
|
return async () => {
|
|
|
|
const editor = ctx.activeRustEditor;
|
2022-10-17 12:20:14 +00:00
|
|
|
if (!editor) return;
|
2022-10-28 22:44:37 +00:00
|
|
|
const client = ctx.client;
|
2021-02-27 17:04:43 +00:00
|
|
|
|
2021-02-27 18:07:23 +00:00
|
|
|
await vscode.window.withProgress(
|
|
|
|
{
|
|
|
|
location: vscode.ProgressLocation.Notification,
|
|
|
|
title: "Looking for tests...",
|
|
|
|
cancellable: false,
|
|
|
|
},
|
|
|
|
async (_progress, _token) => {
|
|
|
|
const uri = editor.document.uri.toString();
|
|
|
|
const position = client.code2ProtocolConverter.asPosition(editor.selection.active);
|
2022-05-17 17:15:06 +00:00
|
|
|
|
2021-02-27 18:07:23 +00:00
|
|
|
const tests = await client.sendRequest(ra.relatedTests, {
|
|
|
|
textDocument: { uri: uri },
|
|
|
|
position: position,
|
|
|
|
});
|
|
|
|
const locations: lc.Location[] = tests.map((it) =>
|
|
|
|
lc.Location.create(
|
|
|
|
it.runnable.location!.targetUri,
|
2023-07-11 13:35:10 +00:00
|
|
|
it.runnable.location!.targetSelectionRange,
|
|
|
|
),
|
2021-02-27 18:07:23 +00:00
|
|
|
);
|
2022-05-17 17:15:06 +00:00
|
|
|
|
2021-02-27 18:07:23 +00:00
|
|
|
await showReferencesImpl(client, uri, position, locations);
|
2023-07-11 13:35:10 +00:00
|
|
|
},
|
2021-02-27 18:07:23 +00:00
|
|
|
);
|
2021-02-27 17:04:43 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function runSingle(ctx: CtxInit): Cmd {
|
2020-06-02 12:33:47 +00:00
|
|
|
return async (runnable: ra.Runnable) => {
|
|
|
|
const editor = ctx.activeRustEditor;
|
|
|
|
if (!editor) return;
|
|
|
|
|
2020-06-18 19:20:13 +00:00
|
|
|
const task = await createTask(runnable, ctx.config);
|
2020-06-02 12:33:47 +00:00
|
|
|
task.group = vscode.TaskGroup.Build;
|
|
|
|
task.presentationOptions = {
|
|
|
|
reveal: vscode.TaskRevealKind.Always,
|
|
|
|
panel: vscode.TaskPanelKind.Dedicated,
|
|
|
|
clear: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
return vscode.tasks.executeTask(task);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function copyRunCommandLine(ctx: CtxInit) {
|
2021-02-10 11:28:13 +00:00
|
|
|
let prevRunnable: RunnableQuickPick | undefined;
|
|
|
|
return async () => {
|
|
|
|
const item = await selectRunnable(ctx, prevRunnable);
|
|
|
|
if (!item) return;
|
|
|
|
const args = createArgs(item.runnable);
|
|
|
|
const commandLine = ["cargo", ...args].join(" ");
|
|
|
|
await vscode.env.clipboard.writeText(commandLine);
|
|
|
|
await vscode.window.showInformationMessage("Cargo invocation copied to the clipboard.");
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function debug(ctx: CtxInit): Cmd {
|
2020-06-02 12:33:47 +00:00
|
|
|
let prevDebuggee: RunnableQuickPick | undefined;
|
|
|
|
|
|
|
|
return async () => {
|
|
|
|
const item = await selectRunnable(ctx, prevDebuggee, true);
|
|
|
|
if (!item) return;
|
|
|
|
|
|
|
|
item.detail = "restart";
|
|
|
|
prevDebuggee = item;
|
|
|
|
return await startDebugSession(ctx, item.runnable);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function debugSingle(ctx: CtxInit): Cmd {
|
2020-06-02 12:33:47 +00:00
|
|
|
return async (config: ra.Runnable) => {
|
|
|
|
await startDebugSession(ctx, config);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-28 22:44:37 +00:00
|
|
|
export function newDebugConfig(ctx: CtxInit): Cmd {
|
2020-06-02 12:33:47 +00:00
|
|
|
return async () => {
|
|
|
|
const item = await selectRunnable(ctx, undefined, true, false);
|
|
|
|
if (!item) return;
|
|
|
|
|
|
|
|
await makeDebugConfig(ctx, item.runnable);
|
|
|
|
};
|
|
|
|
}
|
2022-05-16 18:53:00 +00:00
|
|
|
|
2022-10-17 12:20:14 +00:00
|
|
|
export function linkToCommand(_: Ctx): Cmd {
|
2022-05-16 18:53:00 +00:00
|
|
|
return async (commandId: string) => {
|
|
|
|
const link = LINKED_COMMANDS.get(commandId);
|
2022-10-17 12:20:14 +00:00
|
|
|
if (link) {
|
2022-05-16 18:53:00 +00:00
|
|
|
const { command, arguments: args = [] } = link;
|
|
|
|
await vscode.commands.executeCommand(command, ...args);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2023-06-19 00:31:46 +00:00
|
|
|
|
|
|
|
export function viewMemoryLayout(ctx: CtxInit): Cmd {
|
|
|
|
return async () => {
|
|
|
|
const editor = vscode.window.activeTextEditor;
|
2023-06-19 04:27:53 +00:00
|
|
|
if (!editor) return;
|
2023-06-19 00:31:46 +00:00
|
|
|
const client = ctx.client;
|
|
|
|
|
|
|
|
const position = editor.selection.active;
|
|
|
|
const expanded = await client.sendRequest(ra.viewRecursiveMemoryLayout, {
|
2023-06-19 04:24:42 +00:00
|
|
|
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
|
2023-06-19 00:31:46 +00:00
|
|
|
position,
|
|
|
|
});
|
|
|
|
|
|
|
|
const document = vscode.window.createWebviewPanel(
|
|
|
|
"memory_layout",
|
|
|
|
"[Memory Layout]",
|
|
|
|
vscode.ViewColumn.Two,
|
2023-07-11 13:35:10 +00:00
|
|
|
{ enableScripts: true },
|
2023-06-19 04:24:42 +00:00
|
|
|
);
|
2023-06-19 00:31:46 +00:00
|
|
|
|
|
|
|
document.webview.html = `<!DOCTYPE html>
|
|
|
|
<html lang="en">
|
|
|
|
<head>
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<title>Document</title>
|
2023-07-10 14:03:08 +00:00
|
|
|
<style>
|
2023-06-19 00:31:46 +00:00
|
|
|
* {
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
|
|
|
|
|
|
|
body {
|
|
|
|
margin: 0;
|
|
|
|
overflow: hidden;
|
|
|
|
min-height: 100%;
|
|
|
|
height: 100vh;
|
|
|
|
padding: 32px;
|
|
|
|
position: relative;
|
|
|
|
display: block;
|
|
|
|
|
|
|
|
background-color: var(--vscode-editor-background);
|
|
|
|
font-family: var(--vscode-editor-font-family);
|
|
|
|
font-size: var(--vscode-editor-font-size);
|
|
|
|
color: var(--vscode-editor-foreground);
|
|
|
|
}
|
|
|
|
|
|
|
|
.container {
|
|
|
|
position: relative;
|
|
|
|
}
|
|
|
|
|
|
|
|
.trans {
|
|
|
|
transition: all 0.2s ease-in-out;
|
|
|
|
}
|
|
|
|
|
|
|
|
.grid {
|
|
|
|
height: 100%;
|
|
|
|
position: relative;
|
|
|
|
color: var(--vscode-commandCenter-activeBorder);
|
|
|
|
pointer-events: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.grid-line {
|
|
|
|
position: absolute;
|
|
|
|
width: 100%;
|
|
|
|
height: 1px;
|
|
|
|
background-color: var(--vscode-commandCenter-activeBorder);
|
|
|
|
}
|
|
|
|
|
|
|
|
#tooltip {
|
|
|
|
position: fixed;
|
|
|
|
display: none;
|
|
|
|
z-index: 1;
|
|
|
|
pointer-events: none;
|
|
|
|
padding: 4px 8px;
|
|
|
|
z-index: 2;
|
|
|
|
|
|
|
|
color: var(--vscode-editorHoverWidget-foreground);
|
|
|
|
background-color: var(--vscode-editorHoverWidget-background);
|
|
|
|
border: 1px solid var(--vscode-editorHoverWidget-border);
|
|
|
|
}
|
|
|
|
|
|
|
|
#tooltip b {
|
|
|
|
color: var(--vscode-editorInlayHint-typeForeground);
|
|
|
|
}
|
|
|
|
|
|
|
|
#tooltip ul {
|
|
|
|
margin-left: 0;
|
|
|
|
padding-left: 20px;
|
|
|
|
}
|
|
|
|
|
|
|
|
table {
|
|
|
|
position: absolute;
|
|
|
|
transform: rotateZ(90deg) rotateX(180deg);
|
|
|
|
transform-origin: top left;
|
|
|
|
border-collapse: collapse;
|
|
|
|
table-layout: fixed;
|
|
|
|
left: 48px;
|
|
|
|
top: 0;
|
|
|
|
max-height: calc(100vw - 64px - 48px);
|
|
|
|
z-index: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
td {
|
|
|
|
border: 1px solid var(--vscode-focusBorder);
|
|
|
|
writing-mode: vertical-rl;
|
|
|
|
text-orientation: sideways-right;
|
|
|
|
|
|
|
|
height: 80px;
|
|
|
|
}
|
|
|
|
|
|
|
|
td p {
|
|
|
|
height: calc(100% - 16px);
|
|
|
|
width: calc(100% - 8px);
|
|
|
|
margin: 8px 4px;
|
|
|
|
display: inline-block;
|
|
|
|
transform: rotateY(180deg);
|
|
|
|
pointer-events: none;
|
|
|
|
overflow: hidden;
|
|
|
|
}
|
|
|
|
|
|
|
|
td p * {
|
|
|
|
overflow: hidden;
|
|
|
|
white-space: nowrap;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
display: inline-block;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
td p b {
|
|
|
|
color: var(--vscode-editorInlayHint-typeForeground);
|
|
|
|
}
|
|
|
|
|
|
|
|
td:hover {
|
|
|
|
background-color: var(--vscode-editor-hoverHighlightBackground);
|
|
|
|
}
|
|
|
|
|
|
|
|
td:empty {
|
|
|
|
visibility: hidden;
|
|
|
|
border: 0;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id="tooltip"></div>
|
|
|
|
</body>
|
|
|
|
<script>(function() {
|
|
|
|
|
|
|
|
const data = ${JSON.stringify(expanded)}
|
|
|
|
|
|
|
|
if (!(data && data.nodes.length)) {
|
|
|
|
document.body.innerText = "Not Available"
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
data.nodes.map(n => {
|
|
|
|
n.typename = n.typename.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', ' & quot; ').replaceAll("'", ''')
|
|
|
|
return n
|
|
|
|
})
|
|
|
|
|
|
|
|
let height = window.innerHeight - 64
|
|
|
|
|
|
|
|
addEventListener("resize", e => {
|
|
|
|
const new_height = window.innerHeight - 64
|
|
|
|
height = new_height
|
|
|
|
container.classList.remove("trans")
|
|
|
|
table.classList.remove("trans")
|
|
|
|
locate()
|
|
|
|
setTimeout(() => { // give delay to redraw, annoying but needed
|
|
|
|
container.classList.add("trans")
|
|
|
|
table.classList.add("trans")
|
|
|
|
}, 0)
|
|
|
|
})
|
|
|
|
|
|
|
|
const container = document.createElement("div")
|
|
|
|
container.classList.add("container")
|
|
|
|
container.classList.add("trans")
|
|
|
|
document.body.appendChild(container)
|
|
|
|
|
|
|
|
const tooltip = document.getElementById("tooltip")
|
|
|
|
|
|
|
|
let y = 0
|
|
|
|
let zoom = 1.0
|
|
|
|
|
|
|
|
const table = document.createElement("table")
|
|
|
|
table.classList.add("trans")
|
|
|
|
container.appendChild(table)
|
|
|
|
const rows = []
|
|
|
|
|
|
|
|
function node_t(idx, depth, offset) {
|
|
|
|
if (!rows[depth]) {
|
|
|
|
rows[depth] = { el: document.createElement("tr"), offset: 0 }
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rows[depth].offset < offset) {
|
|
|
|
const pad = document.createElement("td")
|
|
|
|
pad.colSpan = offset - rows[depth].offset
|
|
|
|
rows[depth].el.appendChild(pad)
|
|
|
|
rows[depth].offset += offset - rows[depth].offset
|
|
|
|
}
|
|
|
|
|
|
|
|
const td = document.createElement("td")
|
|
|
|
td.innerHTML = '<p><span>' + data.nodes[idx].itemName + ':</span> <b>' + data.nodes[idx].typename + '</b></p>'
|
|
|
|
|
|
|
|
td.colSpan = data.nodes[idx].size
|
|
|
|
|
|
|
|
td.addEventListener("mouseover", e => {
|
|
|
|
const node = data.nodes[idx]
|
|
|
|
tooltip.innerHTML = node.itemName + ": <b>" + node.typename + "</b><br/>"
|
|
|
|
+ "<ul>"
|
|
|
|
+ "<li>size = " + node.size + "</li>"
|
|
|
|
+ "<li>align = " + node.alignment + "</li>"
|
|
|
|
+ "<li>field offset = " + node.offset + "</li>"
|
|
|
|
+ "</ul>"
|
|
|
|
+ "<i>double click to focus</i>"
|
|
|
|
|
|
|
|
tooltip.style.display = "block"
|
|
|
|
})
|
|
|
|
td.addEventListener("mouseleave", _ => tooltip.style.display = "none")
|
|
|
|
const total_offset = rows[depth].offset
|
|
|
|
td.addEventListener("dblclick", e => {
|
|
|
|
const node = data.nodes[idx]
|
|
|
|
zoom = data.nodes[0].size / node.size
|
|
|
|
y = -(total_offset) / data.nodes[0].size * zoom
|
|
|
|
x = 0
|
|
|
|
locate()
|
|
|
|
})
|
|
|
|
|
|
|
|
rows[depth].el.appendChild(td)
|
|
|
|
rows[depth].offset += data.nodes[idx].size
|
|
|
|
|
|
|
|
|
|
|
|
if (data.nodes[idx].childrenStart != -1) {
|
|
|
|
for (let i = 0; i < data.nodes[idx].childrenLen; i++) {
|
|
|
|
if (data.nodes[data.nodes[idx].childrenStart + i].size) {
|
|
|
|
node_t(data.nodes[idx].childrenStart + i, depth + 1, offset + data.nodes[data.nodes[idx].childrenStart + i].offset)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
node_t(0, 0, 0)
|
|
|
|
|
|
|
|
for (const row of rows) table.appendChild(row.el)
|
|
|
|
|
|
|
|
const grid = document.createElement("div")
|
|
|
|
grid.classList.add("grid")
|
|
|
|
container.appendChild(grid)
|
|
|
|
|
|
|
|
for (let i = 0; i < data.nodes[0].size / 8 + 1; i++) {
|
|
|
|
const el = document.createElement("div")
|
|
|
|
el.classList.add("grid-line")
|
|
|
|
el.style.top = (i / (data.nodes[0].size / 8) * 100) + "%"
|
|
|
|
el.innerText = i * 8
|
|
|
|
grid.appendChild(el)
|
|
|
|
}
|
|
|
|
|
|
|
|
addEventListener("mousemove", e => {
|
|
|
|
tooltip.style.top = e.clientY + 10 + "px"
|
|
|
|
tooltip.style.left = e.clientX + 10 + "px"
|
|
|
|
})
|
|
|
|
|
|
|
|
function locate() {
|
|
|
|
container.style.top = height * y + "px"
|
|
|
|
container.style.height = (height * zoom) + "px"
|
|
|
|
|
|
|
|
table.style.width = container.style.height
|
|
|
|
}
|
|
|
|
|
|
|
|
locate()
|
|
|
|
|
|
|
|
})()
|
|
|
|
</script>
|
2023-06-19 04:24:42 +00:00
|
|
|
</html>`;
|
2023-06-19 00:31:46 +00:00
|
|
|
|
|
|
|
ctx.pushExtCleanup(document);
|
|
|
|
};
|
|
|
|
}
|
2023-08-12 06:25:51 +00:00
|
|
|
|
|
|
|
export function toggleCheckOnSave(ctx: Ctx): Cmd {
|
|
|
|
return async () => {
|
|
|
|
await ctx.config.toggleCheckOnSave();
|
|
|
|
ctx.refreshServerStatus();
|
|
|
|
};
|
|
|
|
}
|