diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-12-30 19:25:01 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-12-30 19:25:01 +0000 |
commit | 17dda0972a68dd88a766c223390317dc2cb3ea00 (patch) | |
tree | 67ef26be75ec5db5fd66761a67b65a09e42d363e /editors/code/src/inlay_hints.ts | |
parent | 237abb85c40672e8cdafa423db6187c107369a09 (diff) | |
parent | 9ead314005afd835ca64b5db9117e1c495814e17 (diff) |
Merge #2693
2693: Encapsulate inlay hints activation r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'editors/code/src/inlay_hints.ts')
-rw-r--r-- | editors/code/src/inlay_hints.ts | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts new file mode 100644 index 000000000..4581e2278 --- /dev/null +++ b/editors/code/src/inlay_hints.ts | |||
@@ -0,0 +1,149 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as lc from 'vscode-languageclient'; | ||
3 | import { Server } from './server'; | ||
4 | import { Ctx } from './ctx'; | ||
5 | |||
6 | export function activateInlayHints(ctx: Ctx) { | ||
7 | const hintsUpdater = new HintsUpdater(); | ||
8 | hintsUpdater.refreshHintsForVisibleEditors().then(() => { | ||
9 | // vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors() | ||
10 | // so update the hints once when the focus changes to guarantee their presence | ||
11 | let editorChangeDisposable: vscode.Disposable | null = null; | ||
12 | editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor( | ||
13 | _ => { | ||
14 | if (editorChangeDisposable !== null) { | ||
15 | editorChangeDisposable.dispose(); | ||
16 | } | ||
17 | return hintsUpdater.refreshHintsForVisibleEditors(); | ||
18 | }, | ||
19 | ); | ||
20 | |||
21 | ctx.pushCleanup( | ||
22 | vscode.window.onDidChangeVisibleTextEditors(_ => | ||
23 | hintsUpdater.refreshHintsForVisibleEditors(), | ||
24 | ), | ||
25 | ); | ||
26 | ctx.pushCleanup( | ||
27 | vscode.workspace.onDidChangeTextDocument(e => | ||
28 | hintsUpdater.refreshHintsForVisibleEditors(e), | ||
29 | ), | ||
30 | ); | ||
31 | ctx.pushCleanup( | ||
32 | vscode.workspace.onDidChangeConfiguration(_ => | ||
33 | hintsUpdater.toggleHintsDisplay( | ||
34 | Server.config.displayInlayHints, | ||
35 | ), | ||
36 | ), | ||
37 | ); | ||
38 | }); | ||
39 | } | ||
40 | |||
41 | interface InlayHintsParams { | ||
42 | textDocument: lc.TextDocumentIdentifier; | ||
43 | } | ||
44 | |||
45 | interface InlayHint { | ||
46 | range: vscode.Range; | ||
47 | kind: string; | ||
48 | label: string; | ||
49 | } | ||
50 | |||
51 | const typeHintDecorationType = vscode.window.createTextEditorDecorationType({ | ||
52 | after: { | ||
53 | color: new vscode.ThemeColor('ralsp.inlayHint'), | ||
54 | }, | ||
55 | }); | ||
56 | |||
57 | class HintsUpdater { | ||
58 | private displayHints = true; | ||
59 | |||
60 | public async toggleHintsDisplay(displayHints: boolean): Promise<void> { | ||
61 | if (this.displayHints !== displayHints) { | ||
62 | this.displayHints = displayHints; | ||
63 | return this.refreshVisibleEditorsHints( | ||
64 | displayHints ? undefined : [], | ||
65 | ); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | public async refreshHintsForVisibleEditors( | ||
70 | cause?: vscode.TextDocumentChangeEvent, | ||
71 | ): Promise<void> { | ||
72 | if (!this.displayHints) return; | ||
73 | |||
74 | if ( | ||
75 | cause !== undefined && | ||
76 | (cause.contentChanges.length === 0 || | ||
77 | !this.isRustDocument(cause.document)) | ||
78 | ) { | ||
79 | return; | ||
80 | } | ||
81 | return this.refreshVisibleEditorsHints(); | ||
82 | } | ||
83 | |||
84 | private async refreshVisibleEditorsHints( | ||
85 | newDecorations?: vscode.DecorationOptions[], | ||
86 | ) { | ||
87 | const promises: Array<Promise<void>> = []; | ||
88 | |||
89 | for (const rustEditor of vscode.window.visibleTextEditors.filter( | ||
90 | editor => this.isRustDocument(editor.document), | ||
91 | )) { | ||
92 | if (newDecorations !== undefined) { | ||
93 | promises.push( | ||
94 | Promise.resolve( | ||
95 | rustEditor.setDecorations( | ||
96 | typeHintDecorationType, | ||
97 | newDecorations, | ||
98 | ), | ||
99 | ), | ||
100 | ); | ||
101 | } else { | ||
102 | promises.push(this.updateDecorationsFromServer(rustEditor)); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | for (const promise of promises) { | ||
107 | await promise; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | private isRustDocument(document: vscode.TextDocument): boolean { | ||
112 | return document && document.languageId === 'rust'; | ||
113 | } | ||
114 | |||
115 | private async updateDecorationsFromServer( | ||
116 | editor: vscode.TextEditor, | ||
117 | ): Promise<void> { | ||
118 | const newHints = await this.queryHints(editor.document.uri.toString()); | ||
119 | if (newHints !== null) { | ||
120 | const newDecorations = newHints.map(hint => ({ | ||
121 | range: hint.range, | ||
122 | renderOptions: { | ||
123 | after: { | ||
124 | contentText: `: ${hint.label}`, | ||
125 | }, | ||
126 | }, | ||
127 | })); | ||
128 | return editor.setDecorations( | ||
129 | typeHintDecorationType, | ||
130 | newDecorations, | ||
131 | ); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | private async queryHints(documentUri: string): Promise<InlayHint[] | null> { | ||
136 | const request: InlayHintsParams = { | ||
137 | textDocument: { uri: documentUri }, | ||
138 | }; | ||
139 | const client = Server.client; | ||
140 | return client | ||
141 | .onReady() | ||
142 | .then(() => | ||
143 | client.sendRequest<InlayHint[] | null>( | ||
144 | 'rust-analyzer/inlayHints', | ||
145 | request, | ||
146 | ), | ||
147 | ); | ||
148 | } | ||
149 | } | ||