@@ -10,6 +10,8 @@ import {
10
10
TextDocuments ,
11
11
TextDocumentSyncKind ,
12
12
WorkspaceFolder ,
13
+ Disposable ,
14
+ ConfigurationRequest ,
13
15
} from 'vscode-languageserver/node'
14
16
import { TextDocument } from 'vscode-languageserver-textdocument'
15
17
import { Utils , URI } from 'vscode-uri'
@@ -116,15 +118,18 @@ function getDocumentContext(
116
118
async function withDocumentAndSettings < T > (
117
119
uri : string ,
118
120
augmentCss : boolean ,
119
- callback : ( result : { document : TextDocument ; settings : LanguageSettings } ) => T | Promise < T >
121
+ callback : ( result : {
122
+ document : TextDocument
123
+ settings : LanguageSettings | undefined
124
+ } ) => T | Promise < T >
120
125
) : Promise < T > {
121
126
let document = documents . get ( uri )
122
127
if ( ! document ) {
123
128
return null
124
129
}
125
130
return await callback ( {
126
131
document : augmentCss ? createVirtualCssDocument ( document ) : document ,
127
- settings : await getDocumentSettings ( uri ) ,
132
+ settings : await getDocumentSettings ( document ) ,
128
133
} )
129
134
}
130
135
@@ -135,14 +140,14 @@ connection.onCompletion(async ({ textDocument, position }, _token) =>
135
140
position ,
136
141
stylesheets . get ( document ) ,
137
142
getDocumentContext ( document . uri , workspaceFolders ) ,
138
- settings . completion
143
+ settings ? .completion
139
144
)
140
145
)
141
146
)
142
147
143
148
connection . onHover ( ( { textDocument, position } , _token ) =>
144
149
withDocumentAndSettings ( textDocument . uri , true , ( { document, settings } ) =>
145
- cssLanguageService . doHover ( document , position , stylesheets . get ( document ) , settings . hover )
150
+ cssLanguageService . doHover ( document , position , stylesheets . get ( document ) , settings ? .hover )
146
151
)
147
152
)
148
153
@@ -226,32 +231,70 @@ connection.onRenameRequest(({ textDocument, position, newName }) =>
226
231
)
227
232
)
228
233
229
- let documentSettings : Map < string , Thenable < LanguageSettings > > = new Map ( )
230
- function getDocumentSettings ( resource : string ) : Thenable < LanguageSettings > {
231
- let result = documentSettings . get ( resource )
232
- if ( ! result ) {
233
- result = connection . workspace . getConfiguration ( {
234
- scopeUri : resource ,
235
- section : 'css' ,
236
- } )
237
- documentSettings . set ( resource , result )
234
+ let documentSettings : { [ key : string ] : Thenable < LanguageSettings | undefined > } = { }
235
+ documents . onDidClose ( ( e ) => {
236
+ delete documentSettings [ e . document . uri ]
237
+ } )
238
+ function getDocumentSettings ( textDocument : TextDocument ) : Thenable < LanguageSettings | undefined > {
239
+ let promise = documentSettings [ textDocument . uri ]
240
+ if ( ! promise ) {
241
+ const configRequestParam = {
242
+ items : [ { scopeUri : textDocument . uri , section : 'css' } ] ,
243
+ }
244
+ promise = connection
245
+ . sendRequest ( ConfigurationRequest . type , configRequestParam )
246
+ . then ( ( s ) => s [ 0 ] )
247
+ documentSettings [ textDocument . uri ] = promise
238
248
}
239
- return result
249
+ return promise
240
250
}
241
251
242
- connection . onDidChangeConfiguration ( ( _change ) => {
243
- documentSettings . clear ( )
244
- documents . all ( ) . forEach ( validateTextDocument )
252
+ connection . onDidChangeConfiguration ( ( change ) => {
253
+ updateConfiguration ( < LanguageSettings > change . settings . css )
245
254
} )
246
255
256
+ function updateConfiguration ( settings : LanguageSettings ) {
257
+ cssLanguageService . configure ( settings )
258
+ // reset all document settings
259
+ documentSettings = { }
260
+ documents . all ( ) . forEach ( triggerValidation )
261
+ }
262
+
263
+ const pendingValidationRequests : { [ uri : string ] : Disposable } = { }
264
+ const validationDelayMs = 500
265
+
266
+ const timer = {
267
+ setTimeout ( callback : ( ...args : any [ ] ) => void , ms : number , ...args : any [ ] ) : Disposable {
268
+ const handle = setTimeout ( callback , ms , ...args )
269
+ return { dispose : ( ) => clearTimeout ( handle ) }
270
+ } ,
271
+ }
272
+
247
273
documents . onDidChangeContent ( ( change ) => {
248
- validateTextDocument ( change . document )
274
+ triggerValidation ( change . document )
249
275
} )
250
276
251
- documents . onDidClose ( ( e ) => {
252
- documentSettings . delete ( e . document . uri )
277
+ documents . onDidClose ( ( event ) => {
278
+ cleanPendingValidation ( event . document )
279
+ connection . sendDiagnostics ( { uri : event . document . uri , diagnostics : [ ] } )
253
280
} )
254
281
282
+ function cleanPendingValidation ( textDocument : TextDocument ) : void {
283
+ const request = pendingValidationRequests [ textDocument . uri ]
284
+ if ( request ) {
285
+ request . dispose ( )
286
+ delete pendingValidationRequests [ textDocument . uri ]
287
+ }
288
+ }
289
+
290
+ function triggerValidation ( textDocument : TextDocument ) : void {
291
+ cleanPendingValidation ( textDocument )
292
+ pendingValidationRequests [ textDocument . uri ] = timer . setTimeout ( ( ) => {
293
+ delete pendingValidationRequests [ textDocument . uri ]
294
+ validateTextDocument ( textDocument )
295
+ } , validationDelayMs )
296
+ }
297
+
255
298
function replace ( delta = 0 ) {
256
299
return ( _match : string , p1 : string ) => {
257
300
let lines = p1 . split ( '\n' )
@@ -281,7 +324,7 @@ function createVirtualCssDocument(textDocument: TextDocument): TextDocument {
281
324
async function validateTextDocument ( textDocument : TextDocument ) : Promise < void > {
282
325
textDocument = createVirtualCssDocument ( textDocument )
283
326
284
- let settings = await getDocumentSettings ( textDocument . uri )
327
+ let settings = await getDocumentSettings ( textDocument )
285
328
286
329
// let stylesheet = cssLanguageService.parseStylesheet(textDocument) as any
287
330
// stylesheet.acceptVisitor({
0 commit comments