@@ -20,7 +20,6 @@ import {
20
20
import * as fs from 'fs' ;
21
21
import * as path from 'path' ;
22
22
import fastGlob from 'fast-glob' ;
23
- import lineColumn from 'line-column' ;
24
23
25
24
import * as culori from 'culori' ;
26
25
@@ -36,6 +35,12 @@ import { Symbols } from 'vscode-css-languageservice/lib/umd/parser/cssSymbolScop
36
35
import isColor from './utils/isColor' ;
37
36
import { uriToPath } from './utils/protocol' ;
38
37
import { pathToFileURL } from 'url' ;
38
+ import { findAll } from './utils/findAll' ;
39
+ import { indexToPosition } from './utils/indexToPosition' ;
40
+ import { culoriColorToVscodeColor } from './utils/culoriColorToVscodeColor' ;
41
+ import { getCurrentWord } from './utils/getCurrentWord' ;
42
+ import { isInFunctionExpression } from './utils/isInFunctionExpression' ;
43
+ import Cache from './cache' ;
39
44
40
45
// Create a connection for the server, using Node's IPC as a transport.
41
46
// Also include all preview / proposed LSP features.
@@ -60,8 +65,6 @@ type CSSVariable = {
60
65
color ?: Color
61
66
}
62
67
63
- let cachedVariables : Record < string , Map < string , CSSVariable > > = { } ;
64
-
65
68
export const getLanguageService = ( fileExtension : string ) => {
66
69
switch ( fileExtension ) {
67
70
case '.less' :
@@ -74,51 +77,7 @@ export const getLanguageService = (fileExtension: string) => {
74
77
}
75
78
} ;
76
79
77
- function getCurrentWord ( document : TextDocument , offset : number ) : string {
78
- let left = offset - 1 ;
79
- let right = offset + 1 ;
80
- const text = document . getText ( ) ;
81
-
82
- while ( left >= 0 && ' \t\n\r":{[()]},*>+' . indexOf ( text . charAt ( left ) ) === - 1 ) {
83
- left -- ;
84
- }
85
-
86
- while (
87
- right <= text . length &&
88
- ' \t\n\r":{[()]},*>+' . indexOf ( text . charAt ( right ) ) === - 1
89
- ) {
90
- right ++ ;
91
- }
92
-
93
- return text . substring ( left , right ) ;
94
- }
95
-
96
- function isInFunctionExpression ( word : string ) : boolean {
97
- if ( word . length < 1 ) {
98
- return false ;
99
- }
100
-
101
- return '(' === word . charAt ( 0 ) ;
102
- }
103
-
104
- const toRgb = culori . converter ( 'rgb' ) ;
105
-
106
- export function culoriColorToVscodeColor ( color : culori . Color ) : Color {
107
- const rgb = toRgb ( color ) ;
108
- return { red : rgb . r , green : rgb . g , blue : rgb . b , alpha : rgb . alpha ?? 1 } ;
109
- }
110
-
111
- const clearFileCache = ( filePath : string ) => {
112
- cachedVariables [ filePath ] ?. forEach ( ( _ , key ) => {
113
- cachedVariables [ 'all' ] ?. delete ( key ) ;
114
- } ) ;
115
- cachedVariables [ filePath ] ?. clear ( ) ;
116
- } ;
117
-
118
- const clearAllCache = ( ) => {
119
- cachedVariables [ 'all' ] ?. clear ( ) ;
120
- cachedVariables = { } ;
121
- } ;
80
+ const cacheManager = new Cache < CSSVariable > ( ) ;
122
81
123
82
const parseCSSVariablesFromText = ( {
124
83
content,
@@ -129,7 +88,7 @@ const parseCSSVariablesFromText = ({
129
88
} ) => {
130
89
try {
131
90
// reset cache for this file
132
- clearFileCache ( filePath ) ;
91
+ cacheManager . clearFileCache ( filePath ) ;
133
92
134
93
const fileExtension = path . extname ( filePath ) ;
135
94
const languageService = getLanguageService ( fileExtension ) ;
@@ -145,13 +104,6 @@ const parseCSSVariablesFromText = ({
145
104
146
105
symbolContext . global . symbols . forEach ( ( symbol : CSSSymbol ) => {
147
106
if ( symbol . name . startsWith ( '--' ) ) {
148
- if ( ! cachedVariables [ filePath ] ) {
149
- cachedVariables [ filePath ] = new Map ( ) ;
150
- }
151
- if ( ! cachedVariables [ 'all' ] ) {
152
- cachedVariables [ 'all' ] = new Map ( ) ;
153
- }
154
-
155
107
const variable : CSSVariable = {
156
108
symbol,
157
109
definition : {
@@ -171,8 +123,7 @@ const parseCSSVariablesFromText = ({
171
123
}
172
124
173
125
// add to cache
174
- cachedVariables [ 'all' ] ?. set ( symbol . name , variable ) ;
175
- cachedVariables [ filePath ] . set ( symbol . name , variable ) ;
126
+ cacheManager . set ( filePath , symbol . name , variable ) ;
176
127
}
177
128
} ) ;
178
129
} catch ( error ) {
@@ -300,7 +251,7 @@ connection.onDidChangeConfiguration(async (change) => {
300
251
if ( hasConfigurationCapability ) {
301
252
// Reset all cached document settings
302
253
documentSettings . clear ( ) ;
303
- clearAllCache ( ) ;
254
+ cacheManager . clearAllCache ( ) ;
304
255
305
256
const validFolders = await connection . workspace
306
257
. getWorkspaceFolders ( )
@@ -346,8 +297,8 @@ connection.onDidChangeWatchedFiles((_change) => {
346
297
const filePath = uriToPath ( change . uri ) ;
347
298
if ( filePath ) {
348
299
// remove variables from cache
349
- if ( change . type === FileChangeType . Deleted && cachedVariables [ filePath ] ) {
350
- clearFileCache ( filePath ) ;
300
+ if ( change . type === FileChangeType . Deleted ) {
301
+ cacheManager . clearFileCache ( filePath ) ;
351
302
} else {
352
303
const content = fs . readFileSync ( filePath , 'utf8' ) ;
353
304
parseCSSVariablesFromText ( {
@@ -373,7 +324,7 @@ connection.onCompletion(
373
324
const isFunctionCall = isInFunctionExpression ( currentWord ) ;
374
325
375
326
const items : CompletionItem [ ] = [ ] ;
376
- cachedVariables [ 'all' ] ? .forEach ( ( variable ) => {
327
+ cacheManager . getAll ( ) . forEach ( ( variable ) => {
377
328
const varSymbol = variable . symbol ;
378
329
const insertText = isFunctionCall
379
330
? varSymbol . name
@@ -382,6 +333,7 @@ connection.onCompletion(
382
333
label : varSymbol . name ,
383
334
detail : varSymbol . value ,
384
335
documentation : varSymbol . value ,
336
+ commitCharacters : [ ' ' , ';' , '{' , '}' ] ,
385
337
insertText,
386
338
kind : isColor ( varSymbol . value )
387
339
? CompletionItemKind . Color
@@ -406,25 +358,6 @@ connection.onCompletionResolve((item: CompletionItem): CompletionItem => {
406
358
return item ;
407
359
} ) ;
408
360
409
- export function findAll ( re : RegExp , str : string ) : RegExpMatchArray [ ] {
410
- let match : RegExpMatchArray ;
411
- const matches : RegExpMatchArray [ ] = [ ] ;
412
- while ( ( match = re . exec ( str ) ) !== null ) {
413
- matches . push ( { ...match } ) ;
414
- }
415
- return matches ;
416
- }
417
-
418
- export function indexToPosition ( str : string , index : number ) : Position {
419
- const data = lineColumn ( str + '\n' , index ) ;
420
-
421
- if ( ! data ) {
422
- return { line : 0 , character : 0 } ;
423
- }
424
- const { line, col } = data ;
425
- return { line : line - 1 , character : col - 1 } ;
426
- }
427
-
428
361
connection . onDocumentColor ( ( params ) : ColorInformation [ ] => {
429
362
const document = documents . get ( params . textDocument . uri ) ;
430
363
if ( ! document ) {
@@ -442,7 +375,7 @@ connection.onDocumentColor((params): ColorInformation[] => {
442
375
const start = indexToPosition ( text , match . index + 4 ) ;
443
376
const end = indexToPosition ( text , match . index + match [ 0 ] . length ) ;
444
377
445
- const cssVariable = cachedVariables [ 'all' ] ? .get ( match . groups . varName ) ;
378
+ const cssVariable = cacheManager . getAll ( ) . get ( match . groups . varName ) ;
446
379
447
380
if ( cssVariable ?. color ) {
448
381
const range = {
@@ -482,7 +415,7 @@ connection.onHover((params) => {
482
415
483
416
const nornalizedWord = currentWord . slice ( 1 ) ;
484
417
485
- const cssVariable = cachedVariables [ 'all' ] ? .get ( nornalizedWord ) ;
418
+ const cssVariable = cacheManager . getAll ( ) . get ( nornalizedWord ) ;
486
419
487
420
if ( cssVariable ) {
488
421
return {
@@ -504,6 +437,7 @@ connection.onColorPresentation((params) => {
504
437
505
438
return [ ] ;
506
439
} ) ;
440
+
507
441
connection . onDefinition ( ( params ) => {
508
442
const doc = documents . get ( params . textDocument . uri ) ;
509
443
@@ -517,7 +451,7 @@ connection.onDefinition((params) => {
517
451
if ( ! currentWord ) return null ;
518
452
519
453
const nornalizedWord = currentWord . slice ( 1 ) ;
520
- const cssVariable = cachedVariables [ 'all' ] ? .get ( nornalizedWord ) ;
454
+ const cssVariable = cacheManager . getAll ( ) . get ( nornalizedWord ) ;
521
455
522
456
if ( cssVariable ) {
523
457
return cssVariable . definition ;
0 commit comments