From ca5c59507f76b8e30658d6c815b823c9636d786a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 30 Dec 2019 19:05:41 +0100 Subject: Refactor show syntax tree action --- editors/code/src/commands/syntax_tree.ts | 106 +++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 editors/code/src/commands/syntax_tree.ts (limited to 'editors/code/src/commands/syntax_tree.ts') diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/commands/syntax_tree.ts new file mode 100644 index 000000000..e61fb36df --- /dev/null +++ b/editors/code/src/commands/syntax_tree.ts @@ -0,0 +1,106 @@ +import * as vscode from 'vscode'; +import * as lc from 'vscode-languageclient'; + +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 syntaxTree(ctx: Ctx): Cmd { + const stcp = new SyntaxTreeContentProvider(ctx); + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider( + 'rust-analyzer', + stcp, + ), + ); + + vscode.workspace.onDidChangeTextDocument( + (event: vscode.TextDocumentChangeEvent) => { + const doc = event.document; + if (doc.languageId !== 'rust') return; + afterLs(() => stcp.eventEmitter.fire(stcp.uri)); + }, + ctx.subscriptions, + ); + + vscode.window.onDidChangeActiveTextEditor( + (editor: vscode.TextEditor | undefined) => { + if (!editor || editor.document.languageId !== 'rust') return; + stcp.eventEmitter.fire(stcp.uri); + }, + ctx.subscriptions, + ); + + return async () => { + const editor = vscode.window.activeTextEditor; + const rangeEnabled = !!(editor && !editor.selection.isEmpty); + + const uri = rangeEnabled + ? vscode.Uri.parse(`${stcp.uri.toString()}?range=true`) + : stcp.uri; + + const document = await vscode.workspace.openTextDocument(uri); + + stcp.eventEmitter.fire(uri); + + return vscode.window.showTextDocument( + document, + vscode.ViewColumn.Two, + true, + ); + }; +} + +// We need to order this after LS updates, but there's no API for that. +// Hence, good old setTimeout. +function afterLs(f: () => any) { + setTimeout(f, 10); +} + +interface SyntaxTreeParams { + textDocument: lc.TextDocumentIdentifier; + range?: lc.Range; +} + +export class SyntaxTreeContentProvider + implements vscode.TextDocumentContentProvider { + ctx: Ctx; + uri = vscode.Uri.parse('rust-analyzer://syntaxtree'); + eventEmitter = new vscode.EventEmitter(); + syntaxTree: string = 'Not available'; + + constructor(ctx: Ctx) { + this.ctx = ctx; + } + + provideTextDocumentContent(uri: vscode.Uri): vscode.ProviderResult { + const editor = vscode.window.activeTextEditor; + if (editor == null) return ''; + + let range: lc.Range | undefined; + + // When the range based query is enabled we take the range of the selection + if (uri.query === 'range=true') { + range = editor.selection.isEmpty + ? undefined + : this.ctx.client.code2ProtocolConverter.asRange( + editor.selection, + ); + } + + const request: SyntaxTreeParams = { + textDocument: { uri: editor.document.uri.toString() }, + range, + }; + return this.ctx.client.sendRequest( + 'rust-analyzer/syntaxTree', + request, + ); + } + + get onDidChange(): vscode.Event { + return this.eventEmitter.event; + } +} -- cgit v1.2.3