@@ -10,193 +10,193 @@ import { InlayHint, InlayHintsParams, inlayHintsRequest } from './lspExtensions'
10
10
// this module providing custom decorations will no longer be needed!
11
11
12
12
export async function activateInlayHints (
13
- context : vscode . ExtensionContext ,
14
- client : langclient . LanguageClient
13
+ context : vscode . ExtensionContext ,
14
+ client : langclient . LanguageClient
15
15
) : Promise < void > {
16
- const config = vscode . workspace . getConfiguration ( 'sourcekit-lsp' ) ;
17
- let updater : HintsUpdater | null = null ;
18
-
19
- const onConfigChange = async ( ) => {
20
- const wasEnabled = updater !== null ;
21
- const isEnabled = config . get < boolean > ( 'inlayHints.enabled' , true ) ;
22
-
23
- if ( wasEnabled !== isEnabled ) {
24
- updater ?. dispose ( ) ;
25
- if ( isEnabled ) {
26
- updater = new HintsUpdater ( client ) ;
27
- } else {
28
- updater = null ;
29
- }
30
- }
31
- } ;
16
+ const config = vscode . workspace . getConfiguration ( 'sourcekit-lsp' ) ;
17
+ let updater : HintsUpdater | null = null ;
18
+
19
+ const onConfigChange = async ( ) => {
20
+ const wasEnabled = updater !== null ;
21
+ const isEnabled = config . get < boolean > ( 'inlayHints.enabled' , true ) ;
22
+
23
+ if ( wasEnabled !== isEnabled ) {
24
+ updater ?. dispose ( ) ;
25
+ if ( isEnabled ) {
26
+ updater = new HintsUpdater ( client ) ;
27
+ } else {
28
+ updater = null ;
29
+ }
30
+ }
31
+ } ;
32
32
33
- context . subscriptions . push ( vscode . workspace . onDidChangeConfiguration ( onConfigChange ) ) ;
34
- context . subscriptions . push ( { dispose : ( ) => updater ?. dispose ( ) } ) ;
33
+ context . subscriptions . push ( vscode . workspace . onDidChangeConfiguration ( onConfigChange ) ) ;
34
+ context . subscriptions . push ( { dispose : ( ) => updater ?. dispose ( ) } ) ;
35
35
36
- onConfigChange ( ) . catch ( console . error ) ;
36
+ onConfigChange ( ) . catch ( console . error ) ;
37
37
}
38
38
39
39
interface InlayHintStyle {
40
- decorationType : vscode . TextEditorDecorationType ;
40
+ decorationType : vscode . TextEditorDecorationType ;
41
41
42
- makeDecoration ( hint : InlayHint , converter : langclient . Protocol2CodeConverter ) : vscode . DecorationOptions ;
42
+ makeDecoration ( hint : InlayHint , converter : langclient . Protocol2CodeConverter ) : vscode . DecorationOptions ;
43
43
}
44
44
45
45
const hintStyle : InlayHintStyle = {
46
- decorationType : vscode . window . createTextEditorDecorationType ( {
47
- after : {
48
- color : new vscode . ThemeColor ( 'editorCodeLens.foreground' ) ,
49
- fontStyle : 'normal' ,
50
- fontWeight : 'normal'
51
- }
52
- } ) ,
53
-
54
- makeDecoration : ( hint , converter ) => ( {
55
- range : converter . asRange ( {
56
- start : hint . position ,
57
- end : { ...hint . position , character : hint . position . character + 1 } }
58
- ) ,
59
- renderOptions : {
60
- after : {
61
- // U+200C is a zero-width non-joiner to prevent the editor from
62
- // forming a ligature between the code and an inlay hint.
63
- contentText : `\u{200c}: ${ hint . label } `
64
- }
65
- }
66
- } )
46
+ decorationType : vscode . window . createTextEditorDecorationType ( {
47
+ after : {
48
+ color : new vscode . ThemeColor ( 'editorCodeLens.foreground' ) ,
49
+ fontStyle : 'normal' ,
50
+ fontWeight : 'normal'
51
+ }
52
+ } ) ,
53
+
54
+ makeDecoration : ( hint , converter ) => ( {
55
+ range : converter . asRange ( {
56
+ start : hint . position ,
57
+ end : { ...hint . position , character : hint . position . character + 1 } }
58
+ ) ,
59
+ renderOptions : {
60
+ after : {
61
+ // U+200C is a zero-width non-joiner to prevent the editor from
62
+ // forming a ligature between the code and an inlay hint.
63
+ contentText : `\u{200c}: ${ hint . label } `
64
+ }
65
+ }
66
+ } )
67
67
} ;
68
68
69
69
interface SourceFile {
70
- /** Source of the token for cancelling in-flight inlay hint requests. */
71
- inFlightInlayHints : null | vscode . CancellationTokenSource ;
70
+ /** Source of the token for cancelling in-flight inlay hint requests. */
71
+ inFlightInlayHints : null | vscode . CancellationTokenSource ;
72
72
73
- /** Most recently applied decorations. */
74
- cachedDecorations : null | vscode . DecorationOptions [ ] ;
73
+ /** Most recently applied decorations. */
74
+ cachedDecorations : null | vscode . DecorationOptions [ ] ;
75
75
76
- /** The source file document in question. */
77
- document : vscode . TextDocument ;
76
+ /** The source file document in question. */
77
+ document : vscode . TextDocument ;
78
78
}
79
79
80
80
class HintsUpdater implements vscode . Disposable {
81
- private readonly disposables : vscode . Disposable [ ] = [ ] ;
82
- private sourceFiles : Map < string , SourceFile > = new Map ( ) ; // uri -> SourceFile
83
-
84
- constructor ( private readonly client : langclient . LanguageClient ) {
85
- // Register listeners
86
- vscode . window . onDidChangeVisibleTextEditors ( this . onDidChangeVisibleTextEditors , this , this . disposables ) ;
87
- vscode . workspace . onDidChangeTextDocument ( this . onDidChangeTextDocument , this , this . disposables ) ;
88
-
89
- // Set up initial cache
90
- this . visibleSourceKitLSPEditors . forEach ( editor => this . sourceFiles . set (
91
- editor . document . uri . toString ( ) ,
92
- {
93
- document : editor . document ,
94
- inFlightInlayHints : null ,
95
- cachedDecorations : null
96
- }
97
- ) ) ;
98
-
99
- this . syncCacheAndRenderHints ( ) ;
100
- }
101
-
102
- private onDidChangeVisibleTextEditors ( ) : void {
103
- const newSourceFiles = new Map < string , SourceFile > ( ) ;
104
-
105
- // Rerender all, even up-to-date editors for simplicity
106
- this . visibleSourceKitLSPEditors . forEach ( async editor => {
107
- const uri = editor . document . uri . toString ( ) ;
108
- const file = this . sourceFiles . get ( uri ) ?? {
109
- document : editor . document ,
110
- inFlightInlayHints : null ,
111
- cachedDecorations : null
112
- } ;
113
- newSourceFiles . set ( uri , file ) ;
114
-
115
- // No text documents changed, so we may try to use the cache
116
- if ( ! file . cachedDecorations ) {
117
- const hints = await this . fetchHints ( file ) ;
118
- if ( ! hints ) return ;
119
- file . cachedDecorations = this . hintsToDecorations ( hints ) ;
120
- }
121
-
122
- this . renderDecorations ( editor , file . cachedDecorations ) ;
123
- } ) ;
124
-
125
- // Cancel requests for no longer visible (disposed) source files
126
- this . sourceFiles . forEach ( ( file , uri ) => {
127
- if ( ! newSourceFiles . has ( uri ) ) {
128
- file . inFlightInlayHints ?. cancel ( ) ;
129
- }
130
- } ) ;
81
+ private readonly disposables : vscode . Disposable [ ] = [ ] ;
82
+ private sourceFiles : Map < string , SourceFile > = new Map ( ) ; // uri -> SourceFile
83
+
84
+ constructor ( private readonly client : langclient . LanguageClient ) {
85
+ // Register listeners
86
+ vscode . window . onDidChangeVisibleTextEditors ( this . onDidChangeVisibleTextEditors , this , this . disposables ) ;
87
+ vscode . workspace . onDidChangeTextDocument ( this . onDidChangeTextDocument , this , this . disposables ) ;
88
+
89
+ // Set up initial cache
90
+ this . visibleSourceKitLSPEditors . forEach ( editor => this . sourceFiles . set (
91
+ editor . document . uri . toString ( ) ,
92
+ {
93
+ document : editor . document ,
94
+ inFlightInlayHints : null ,
95
+ cachedDecorations : null
96
+ }
97
+ ) ) ;
98
+
99
+ this . syncCacheAndRenderHints ( ) ;
100
+ }
131
101
132
- this . sourceFiles = newSourceFiles ;
133
- }
102
+ private onDidChangeVisibleTextEditors ( ) : void {
103
+ const newSourceFiles = new Map < string , SourceFile > ( ) ;
104
+
105
+ // Rerender all, even up-to-date editors for simplicity
106
+ this . visibleSourceKitLSPEditors . forEach ( async editor => {
107
+ const uri = editor . document . uri . toString ( ) ;
108
+ const file = this . sourceFiles . get ( uri ) ?? {
109
+ document : editor . document ,
110
+ inFlightInlayHints : null ,
111
+ cachedDecorations : null
112
+ } ;
113
+ newSourceFiles . set ( uri , file ) ;
114
+
115
+ // No text documents changed, so we may try to use the cache
116
+ if ( ! file . cachedDecorations ) {
117
+ const hints = await this . fetchHints ( file ) ;
118
+ if ( ! hints ) return ;
119
+ file . cachedDecorations = this . hintsToDecorations ( hints ) ;
120
+ }
121
+
122
+ this . renderDecorations ( editor , file . cachedDecorations ) ;
123
+ } ) ;
124
+
125
+ // Cancel requests for no longer visible (disposed) source files
126
+ this . sourceFiles . forEach ( ( file , uri ) => {
127
+ if ( ! newSourceFiles . has ( uri ) ) {
128
+ file . inFlightInlayHints ?. cancel ( ) ;
129
+ }
130
+ } ) ;
131
+
132
+ this . sourceFiles = newSourceFiles ;
133
+ }
134
134
135
- private onDidChangeTextDocument ( event : vscode . TextDocumentChangeEvent ) : void {
136
- if ( event . contentChanges . length !== 0 && this . isSourceKitLSPDocument ( event . document ) ) {
137
- this . syncCacheAndRenderHints ( ) ;
135
+ private onDidChangeTextDocument ( event : vscode . TextDocumentChangeEvent ) : void {
136
+ if ( event . contentChanges . length !== 0 && this . isSourceKitLSPDocument ( event . document ) ) {
137
+ this . syncCacheAndRenderHints ( ) ;
138
+ }
138
139
}
139
- }
140
140
141
- private syncCacheAndRenderHints ( ) : void {
142
- this . sourceFiles . forEach ( async ( file , uri ) => {
143
- const hints = await this . fetchHints ( file ) ;
144
- if ( ! hints ) return ;
141
+ private syncCacheAndRenderHints ( ) : void {
142
+ this . sourceFiles . forEach ( async ( file , uri ) => {
143
+ const hints = await this . fetchHints ( file ) ;
144
+ if ( ! hints ) return ;
145
145
146
- const decorations = this . hintsToDecorations ( hints ) ;
147
- file . cachedDecorations = decorations ;
146
+ const decorations = this . hintsToDecorations ( hints ) ;
147
+ file . cachedDecorations = decorations ;
148
148
149
- this . visibleSourceKitLSPEditors . forEach ( editor => {
150
- if ( editor . document . uri . toString ( ) === uri ) {
151
- this . renderDecorations ( editor , decorations ) ;
152
- }
153
- } ) ;
154
- } ) ;
155
- }
156
-
157
- private get visibleSourceKitLSPEditors ( ) : vscode . TextEditor [ ] {
158
- return vscode . window . visibleTextEditors . filter ( e => this . isSourceKitLSPDocument ( e . document ) ) ;
159
- }
160
-
161
- private isSourceKitLSPDocument ( document : vscode . TextDocument ) : boolean {
162
- // TODO: Add other SourceKit-LSP languages if/once we forward inlay
163
- // hint requests to clangd.
164
- return document . languageId === 'swift' && document . uri . scheme === 'file' ;
165
- }
166
-
167
- private renderDecorations ( editor : vscode . TextEditor , decorations : vscode . DecorationOptions [ ] ) : void {
168
- editor . setDecorations ( hintStyle . decorationType , decorations ) ;
169
- }
170
-
171
- private hintsToDecorations ( hints : InlayHint [ ] ) : vscode . DecorationOptions [ ] {
172
- const converter = this . client . protocol2CodeConverter ;
173
- return hints . map ( h => hintStyle . makeDecoration ( h , converter ) ) ;
174
- }
175
-
176
- private async fetchHints ( file : SourceFile ) : Promise < InlayHint [ ] > {
177
- file . inFlightInlayHints ?. cancel ( ) ;
178
-
179
- const tokenSource = new vscode . CancellationTokenSource ( ) ;
180
- file . inFlightInlayHints = tokenSource ;
181
-
182
- // TODO: Specify a range
183
- const params : InlayHintsParams = {
184
- textDocument : { uri : file . document . uri . toString ( ) }
149
+ this . visibleSourceKitLSPEditors . forEach ( editor => {
150
+ if ( editor . document . uri . toString ( ) === uri ) {
151
+ this . renderDecorations ( editor , decorations ) ;
152
+ }
153
+ } ) ;
154
+ } ) ;
155
+ }
156
+
157
+ private get visibleSourceKitLSPEditors ( ) : vscode . TextEditor [ ] {
158
+ return vscode . window . visibleTextEditors . filter ( e => this . isSourceKitLSPDocument ( e . document ) ) ;
185
159
}
186
160
187
- try {
188
- return await this . client . sendRequest ( inlayHintsRequest , params , tokenSource . token ) ;
189
- } catch ( e ) {
190
- this . client . outputChannel . appendLine ( `Could not fetch inlay hints: ${ e } ` ) ;
191
- return [ ] ;
192
- } finally {
193
- if ( file . inFlightInlayHints . token === tokenSource . token ) {
194
- file . inFlightInlayHints = null ;
195
- }
161
+ private isSourceKitLSPDocument ( document : vscode . TextDocument ) : boolean {
162
+ // TODO: Add other SourceKit-LSP languages if/once we forward inlay
163
+ // hint requests to clangd.
164
+ return document . languageId === 'swift' && document . uri . scheme === 'file' ;
196
165
}
197
- }
198
166
199
- dispose ( ) : void {
200
- this . disposables . forEach ( d => d . dispose ( ) ) ;
201
- }
167
+ private renderDecorations ( editor : vscode . TextEditor , decorations : vscode . DecorationOptions [ ] ) : void {
168
+ editor . setDecorations ( hintStyle . decorationType , decorations ) ;
169
+ }
170
+
171
+ private hintsToDecorations ( hints : InlayHint [ ] ) : vscode . DecorationOptions [ ] {
172
+ const converter = this . client . protocol2CodeConverter ;
173
+ return hints . map ( h => hintStyle . makeDecoration ( h , converter ) ) ;
174
+ }
175
+
176
+ private async fetchHints ( file : SourceFile ) : Promise < InlayHint [ ] > {
177
+ file . inFlightInlayHints ?. cancel ( ) ;
178
+
179
+ const tokenSource = new vscode . CancellationTokenSource ( ) ;
180
+ file . inFlightInlayHints = tokenSource ;
181
+
182
+ // TODO: Specify a range
183
+ const params : InlayHintsParams = {
184
+ textDocument : { uri : file . document . uri . toString ( ) }
185
+ }
186
+
187
+ try {
188
+ return await this . client . sendRequest ( inlayHintsRequest , params , tokenSource . token ) ;
189
+ } catch ( e ) {
190
+ this . client . outputChannel . appendLine ( `Could not fetch inlay hints: ${ e } ` ) ;
191
+ return [ ] ;
192
+ } finally {
193
+ if ( file . inFlightInlayHints . token === tokenSource . token ) {
194
+ file . inFlightInlayHints = null ;
195
+ }
196
+ }
197
+ }
198
+
199
+ dispose ( ) : void {
200
+ this . disposables . forEach ( d => d . dispose ( ) ) ;
201
+ }
202
202
}
0 commit comments