Flatten simple commands

This commit is contained in:
Aleksey Kladov 2020-05-25 11:10:31 +02:00
parent 4a013ec62d
commit 021b3da672
10 changed files with 242 additions and 301 deletions

View file

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

View file

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

View file

@ -4,18 +4,251 @@ import * as ra from '../rust-analyzer-api';
import { Ctx, Cmd } from '../ctx';
import { applySnippetWorkspaceEdit } from '../snippets';
import { spawnSync } from 'child_process';
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 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);
};
}
// 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);
@ -35,12 +268,6 @@ export function showReferences(ctx: Ctx): Cmd {
};
}
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);

View file

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

View file

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

View file

@ -1,35 +0,0 @@
import * as vscode from 'vscode';
import * as ra from '../rust-analyzer-api';
import { Cmd, Ctx } from '../ctx';
import { applySnippetWorkspaceEdit } from '../snippets';
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' });
};
}

View file

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

View file

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

View file

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

View file

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