]> git.lizzy.rs Git - rust.git/blob - editors/code/src/commands/syntax_tree.ts
Cleanup
[rust.git] / editors / code / src / commands / syntax_tree.ts
1 import * as vscode from 'vscode';
2 import * as lc from 'vscode-languageclient';
3
4 import { Ctx, Cmd } from '../ctx';
5
6 // Opens the virtual file that will show the syntax tree
7 //
8 // The contents of the file come from the `TextDocumentContentProvider`
9 export function syntaxTree(ctx: Ctx): Cmd {
10     const tdcp = new TextDocumentContentProvider(ctx);
11
12     ctx.pushCleanup(
13         vscode.workspace.registerTextDocumentContentProvider(
14             'rust-analyzer',
15             tdcp,
16         ),
17     );
18
19     vscode.workspace.onDidChangeTextDocument(
20         (event: vscode.TextDocumentChangeEvent) => {
21             const doc = event.document;
22             if (doc.languageId !== 'rust') return;
23             afterLs(() => tdcp.eventEmitter.fire(tdcp.uri));
24         },
25         ctx.subscriptions,
26     );
27
28     vscode.window.onDidChangeActiveTextEditor(
29         (editor: vscode.TextEditor | undefined) => {
30             if (!editor || editor.document.languageId !== 'rust') return;
31             tdcp.eventEmitter.fire(tdcp.uri);
32         },
33         ctx.subscriptions,
34     );
35
36     return async () => {
37         const editor = vscode.window.activeTextEditor;
38         const rangeEnabled = !!(editor && !editor.selection.isEmpty);
39
40         const uri = rangeEnabled
41             ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`)
42             : tdcp.uri;
43
44         const document = await vscode.workspace.openTextDocument(uri);
45
46         tdcp.eventEmitter.fire(uri);
47
48         return vscode.window.showTextDocument(
49             document,
50             vscode.ViewColumn.Two,
51             true,
52         );
53     };
54 }
55
56 // We need to order this after LS updates, but there's no API for that.
57 // Hence, good old setTimeout.
58 function afterLs(f: () => any) {
59     setTimeout(f, 10);
60 }
61
62 interface SyntaxTreeParams {
63     textDocument: lc.TextDocumentIdentifier;
64     range?: lc.Range;
65 }
66
67 class TextDocumentContentProvider
68     implements vscode.TextDocumentContentProvider {
69     ctx: Ctx;
70     uri = vscode.Uri.parse('rust-analyzer://syntaxtree');
71     eventEmitter = new vscode.EventEmitter<vscode.Uri>();
72     syntaxTree: string = 'Not available';
73
74     constructor(ctx: Ctx) {
75         this.ctx = ctx;
76     }
77
78     provideTextDocumentContent(uri: vscode.Uri): vscode.ProviderResult<string> {
79         const editor = vscode.window.activeTextEditor;
80         if (editor == null) return '';
81
82         let range: lc.Range | undefined;
83
84         // When the range based query is enabled we take the range of the selection
85         if (uri.query === 'range=true') {
86             range = editor.selection.isEmpty
87                 ? undefined
88                 : this.ctx.client.code2ProtocolConverter.asRange(
89                     editor.selection,
90                 );
91         }
92
93         const request: SyntaxTreeParams = {
94             textDocument: { uri: editor.document.uri.toString() },
95             range,
96         };
97         return this.ctx.client.sendRequest<string>(
98             'rust-analyzer/syntaxTree',
99             request,
100         );
101     }
102
103     get onDidChange(): vscode.Event<vscode.Uri> {
104         return this.eventEmitter.event;
105     }
106 }