@@ -23,6 +23,8 @@ import {
2323 CodeActionRequest ,
2424 BulkUnregistration ,
2525 HoverRequest ,
26+ DidChangeWatchedFilesNotification ,
27+ FileChangeType ,
2628} from 'vscode-languageserver/node'
2729import { TextDocument } from 'vscode-languageserver-textdocument'
2830import { URI } from 'vscode-uri'
@@ -32,7 +34,7 @@ import normalizePath from 'normalize-path'
3234import * as path from 'path'
3335import * as os from 'os'
3436import * as fs from 'fs'
35- import chokidar from 'chokidar'
37+ import chokidar , { FSWatcher } from 'chokidar'
3638import findUp from 'find-up'
3739import minimatch from 'minimatch'
3840import resolveFrom , { setPnpApi } from './util/resolveFrom'
@@ -206,47 +208,87 @@ async function createProjectService(
206208 const documentSettingsCache : Map < string , Settings > = new Map ( )
207209 let registrations : Promise < BulkUnregistration >
208210
209- const watcher = chokidar . watch (
210- [ normalizePath ( `${ folder } /**/${ CONFIG_FILE_GLOB } ` ) , normalizePath ( `${ folder } /**/package.json` ) ] ,
211- {
212- ignorePermissionErrors : true ,
213- ignoreInitial : true ,
214- ignored : [ '**/node_modules/**' ] ,
215- awaitWriteFinish : {
216- stabilityThreshold : 100 ,
217- pollInterval : 20 ,
218- } ,
219- }
220- )
211+ let watcher : FSWatcher
221212
222- await new Promise < void > ( ( resolve ) => {
223- watcher . on ( 'ready' , ( ) => resolve ( ) )
224- } )
213+ function onFileEvents ( changes : Array < { file : string ; type : FileChangeType } > ) : void {
214+ let needsInit = false
215+ let needsRebuild = false
216+
217+ for ( let change of changes ) {
218+ let file = normalizePath ( change . file )
219+
220+ if ( change . type === FileChangeType . Created ) {
221+ needsInit = true
222+ break
223+ } else if ( change . type === FileChangeType . Changed ) {
224+ if ( ! state . enabled || minimatch ( file , '**/package.json' ) ) {
225+ needsInit = true
226+ break
227+ } else {
228+ needsRebuild = true
229+ }
230+ } else if ( change . type === FileChangeType . Deleted ) {
231+ if (
232+ ! state . enabled ||
233+ minimatch ( file , '**/package.json' ) ||
234+ minimatch ( file , `**/${ CONFIG_FILE_GLOB } ` )
235+ ) {
236+ needsInit = true
237+ break
238+ } else {
239+ needsRebuild = true
240+ }
241+ }
242+ }
225243
226- watcher
227- . on ( 'add' , ( ) => {
244+ if ( needsInit ) {
228245 tryInit ( )
246+ } else if ( needsRebuild ) {
247+ tryRebuild ( )
248+ }
249+ }
250+
251+ if ( params . capabilities . workspace ?. didChangeWatchedFiles ?. dynamicRegistration ) {
252+ connection . onDidChangeWatchedFiles ( ( { changes } ) => {
253+ onFileEvents (
254+ changes . map ( ( { uri, type } ) => ( {
255+ file : URI . parse ( uri ) . fsPath ,
256+ type,
257+ } ) )
258+ )
229259 } )
230- . on ( 'unlink' , ( file ) => {
231- if (
232- ! state . enabled ||
233- minimatch ( file , '**/package.json' ) ||
234- minimatch ( file , `**/${ CONFIG_FILE_GLOB } ` )
235- ) {
236- tryInit ( )
237- } else {
238- tryRebuild ( )
239- }
260+
261+ connection . client . register ( DidChangeWatchedFilesNotification . type , {
262+ watchers : [ { globPattern : `**/${ CONFIG_FILE_GLOB } ` } , { globPattern : '**/package.json' } ] ,
240263 } )
241- . on ( 'change' , ( file ) => {
242- if ( ! state . enabled || minimatch ( file , '**/package.json' ) ) {
243- tryInit ( )
244- } else {
245- tryRebuild ( )
264+ } else {
265+ watcher = chokidar . watch (
266+ [
267+ normalizePath ( `${ folder } /**/${ CONFIG_FILE_GLOB } ` ) ,
268+ normalizePath ( `${ folder } /**/package.json` ) ,
269+ ] ,
270+ {
271+ ignorePermissionErrors : true ,
272+ ignoreInitial : true ,
273+ ignored : [ '**/node_modules/**' ] ,
274+ awaitWriteFinish : {
275+ stabilityThreshold : 100 ,
276+ pollInterval : 20 ,
277+ } ,
246278 }
279+ )
280+
281+ await new Promise < void > ( ( resolve ) => {
282+ watcher . on ( 'ready' , ( ) => resolve ( ) )
247283 } )
248284
249- function registerCapabilities ( ) : void {
285+ watcher
286+ . on ( 'add' , ( file ) => onFileEvents ( [ { file, type : FileChangeType . Created } ] ) )
287+ . on ( 'change' , ( file ) => onFileEvents ( [ { file, type : FileChangeType . Changed } ] ) )
288+ . on ( 'unlink' , ( file ) => onFileEvents ( [ { file, type : FileChangeType . Deleted } ] ) )
289+ }
290+
291+ function registerCapabilities ( watchFiles ?: string [ ] ) : void {
250292 if ( supportsDynamicRegistration ( connection , params ) ) {
251293 if ( registrations ) {
252294 registrations . then ( ( r ) => r . dispose ( ) )
@@ -268,6 +310,11 @@ async function createProjectService(
268310 resolveProvider : true ,
269311 triggerCharacters : [ ...TRIGGER_CHARACTERS , state . separator ] ,
270312 } )
313+ if ( watchFiles ) {
314+ capabilities . add ( DidChangeWatchedFilesNotification . type , {
315+ watchers : watchFiles . map ( ( file ) => ( { globPattern : file } ) ) ,
316+ } )
317+ }
271318
272319 registrations = connection . client . register ( capabilities )
273320 }
@@ -766,10 +813,10 @@ async function createProjectService(
766813 }
767814
768815 if ( state . dependencies ) {
769- watcher . unwatch ( state . dependencies )
816+ watcher ? .unwatch ( state . dependencies )
770817 }
771818 state . dependencies = getModuleDependencies ( state . configPath )
772- watcher . add ( state . dependencies )
819+ watcher ? .add ( state . dependencies )
773820
774821 state . configId = getConfigId ( state . configPath , state . dependencies )
775822
@@ -784,7 +831,7 @@ async function createProjectService(
784831
785832 updateAllDiagnostics ( state )
786833
787- registerCapabilities ( )
834+ registerCapabilities ( state . dependencies )
788835 }
789836
790837 return {
@@ -796,7 +843,7 @@ async function createProjectService(
796843 updateAllDiagnostics ( state )
797844 }
798845 if ( settings . editor . colorDecorators ) {
799- registerCapabilities ( )
846+ registerCapabilities ( state . dependencies )
800847 } else {
801848 connection . sendNotification ( '@/tailwindCSS/clearColors' )
802849 }
0 commit comments