11import fetch from "node-fetch" ;
22import { parse , walk } from "css-tree" ;
3- import { isAbsolute , join , dirname } from "path" ;
3+ import { basename , dirname , extname , isAbsolute , join } from "path" ;
44import {
55 CancellationToken ,
66 CompletionContext ,
@@ -16,19 +16,22 @@ import {
1616 Range ,
1717 TextDocument ,
1818 Uri ,
19- workspace
19+ workspace ,
2020} from "vscode" ;
2121
2222export class ClassCompletionItemProvider implements CompletionItemProvider , Disposable {
2323
2424 readonly none = "__!NONE!__" ;
2525 readonly start = new Position ( 0 , 0 ) ;
2626 readonly cache = new Map < string , Map < string , CompletionItem > > ( ) ;
27+ readonly empty = new Set < string > ( ) ;
28+ readonly extends = new Map < string , Set < string > > ( ) ;
2729 readonly disposables : Disposable [ ] = [ ] ;
2830 readonly isRemote = / ^ h t t p s ? : \/ \/ / i;
2931 readonly canComplete = / ( i d | c l a s s | c l a s s N a m e ) \s * = \s * ( [ " ' ] ) (?: (? ! \2) .) * $ / si;
3032 readonly findLinkRel = / r e l \s * = \s * ( [ " ' ] ) ( (?: (? ! \1) .) + ) \1/ si;
3133 readonly findLinkHref = / h r e f \s * = \s * ( [ " ' ] ) ( (?: (? ! \1) .) + ) \1/ si;
34+ readonly findExtends = / (?: { { <| { { > | { % ) \s * (?: e x t e n d s ) ? \s * " ? ( [ \. 0 - 9 _ a - z - A- Z ] + ) " ? \s * (?: % } | } } ) / i;
3235
3336 dispose ( ) {
3437 let e ;
@@ -38,6 +41,16 @@ export class ClassCompletionItemProvider implements CompletionItemProvider, Disp
3841 }
3942
4043 this . cache . clear ( ) ;
44+ this . extends . clear ( ) ;
45+ }
46+
47+ watchFile ( uri : Uri , listener : ( e : Uri ) => any ) {
48+ const watcher = workspace . createFileSystemWatcher ( uri . fsPath , true ) ;
49+
50+ this . disposables . push (
51+ watcher . onDidChange ( listener ) ,
52+ watcher . onDidDelete ( listener ) ,
53+ watcher ) ;
4154 }
4255
4356 getStyleSheets ( uri : Uri ) : string [ ] {
@@ -79,15 +92,9 @@ export class ClassCompletionItemProvider implements CompletionItemProvider, Disp
7992
8093 workspace . fs . readFile ( file ) . then ( content => {
8194 const items = new Map < string , CompletionItem > ( ) ;
82- this . parseTextToItems ( content . toString ( ) , items ) ;
83-
84- const watcher = workspace . createFileSystemWatcher ( file . fsPath , true ) ;
85- const updater = ( e : Uri ) => this . cache . delete ( key ) ;
86- this . disposables . push (
87- watcher . onDidChange ( updater ) ,
88- watcher . onDidDelete ( updater ) ,
89- watcher ) ;
9095
96+ this . parseTextToItems ( content . toString ( ) , items ) ;
97+ this . watchFile ( file , e => this . cache . delete ( key ) ) ;
9198 this . cache . set ( key , items ) ;
9299 resolve ( key ) ;
93100 } , ( ) => resolve ( this . none ) ) ;
@@ -180,6 +187,45 @@ export class ClassCompletionItemProvider implements CompletionItemProvider, Disp
180187 } ) ;
181188 }
182189
190+ findExtendedStyles ( uri : Uri , text : string ) : Thenable < Set < string > > {
191+ return new Promise ( resolve => {
192+ const parent = this . findExtends . exec ( text ) ;
193+
194+ if ( parent ) {
195+ const path = uri . fsPath ;
196+ const ext = extname ( path ) ;
197+ const key = join ( dirname ( path ) , basename ( parent [ 1 ] , ext ) + ext ) ;
198+ const extend = this . extends . get ( key ) ;
199+
200+ if ( extend ) {
201+ resolve ( extend ) ;
202+ } else {
203+ const file = Uri . file ( key ) ;
204+
205+ workspace . fs . readFile ( file ) . then ( content => {
206+ const text = content . toString ( ) ;
207+
208+ Promise . all ( [
209+ this . findDocumentLinks ( file , text ) ,
210+ this . findDocumentStyles ( file , text ) ,
211+ this . findExtendedStyles ( file , text )
212+ ] ) . then ( sets => {
213+ const keys = new Set < string > ( ) ;
214+
215+ sets . forEach ( set => set . forEach ( k => keys . add ( k ) ) ) ;
216+ this . watchFile ( file , e => this . extends . delete ( key ) ) ;
217+ this . extends . set ( key , keys ) ;
218+ resolve ( keys ) ;
219+ } ) ;
220+
221+ } , ( ) => resolve ( this . empty ) ) ;
222+ }
223+ } else {
224+ resolve ( this . empty ) ;
225+ }
226+ } ) ;
227+ }
228+
183229 buildItems ( sets : Set < string > [ ] , kind : CompletionItemKind ) : CompletionItem [ ] {
184230 const items = new Map < string , CompletionItem > ( ) ;
185231 const keys = new Set < string > ( ) ;
@@ -219,7 +265,8 @@ export class ClassCompletionItemProvider implements CompletionItemProvider, Disp
219265 Promise . all ( [
220266 this . findStyleSheets ( uri ) ,
221267 this . findDocumentLinks ( uri , text ) ,
222- this . findDocumentStyles ( uri , text )
268+ this . findDocumentStyles ( uri , text ) ,
269+ this . findExtendedStyles ( uri , text )
223270 ] ) . then ( keys => resolve ( this . buildItems ( keys , type ) ) ) ;
224271 } else {
225272 reject ( ) ;
0 commit comments