1+ import type { Disposable } from 'vscode-languageserver/node'
12import type { ServerSettings } from './types'
2- import { fileURLToPath } from 'node:url'
3+ import path from 'node:path'
4+ import process from 'node:process'
5+ import { fileURLToPath , pathToFileURL } from 'node:url'
36import { INCLUDE_COMMENT_IDE } from '#integration/constants'
47import { isCssId } from '#integration/utils'
58import { TextDocument } from 'vscode-languageserver-textdocument'
69import {
710 createConnection ,
11+ DidChangeWatchedFilesNotification ,
812 ProposedFeatures ,
913 TextDocuments ,
1014 TextDocumentSyncKind ,
15+ WatchKind ,
1116} from 'vscode-languageserver/node'
1217import { registerColorProvider } from './capabilities/colorProvider'
1318import { registerCompletion , resetAutoCompleteCache } from './capabilities/completion'
@@ -22,6 +27,46 @@ const documents = new TextDocuments(TextDocument)
2227
2328let settings : ServerSettings = { ...defaultSettings }
2429let contextManager : ContextManager
30+ let hasWatchedFilesCapability = false
31+ let serverInitialized = false
32+ let watcherDisposable : Disposable | undefined
33+
34+ async function updateConfigWatchers ( ) : Promise < void > {
35+ if ( ! hasWatchedFilesCapability || ! serverInitialized || ! contextManager )
36+ return
37+
38+ watcherDisposable ?. dispose ( )
39+ watcherDisposable = undefined
40+
41+ const sourceFiles = contextManager . contexts . flatMap ( ctx => ctx . getConfigFileList ( ) )
42+
43+ watcherDisposable = await connection . client . register (
44+ DidChangeWatchedFilesNotification . type ,
45+ {
46+ watchers : sourceFiles . length
47+ ? sourceFiles . map ( file => ( {
48+ globPattern : {
49+ baseUri : pathToFileURL ( path . dirname ( file ) ) . href ,
50+ pattern : path . basename ( file ) ,
51+ } ,
52+ kind : WatchKind . Create | WatchKind . Change | WatchKind . Delete ,
53+ } ) )
54+ : [ {
55+ globPattern : '**/{uno,unocss,vite,svelte,astro,nuxt,iles}.config.{js,mjs,cjs,ts,mts,cts}' ,
56+ kind : WatchKind . Create | WatchKind . Change | WatchKind . Delete ,
57+ } ] ,
58+ } ,
59+ )
60+ }
61+
62+ // Don't crash the server.
63+ process . on ( 'unhandledRejection' , ( reason ) => {
64+ connection . console . error ( `[unocss] Unhandled rejection: ${ String ( reason ) } ` )
65+ } )
66+ // Same as above.
67+ process . on ( 'uncaughtException' , ( err ) => {
68+ connection . console . error ( `[unocss] Uncaught exception: ${ err . message } ` )
69+ } )
2570
2671function getSettings ( ) {
2772 return settings
@@ -32,6 +77,8 @@ function getContextManager() {
3277}
3378
3479connection . onInitialize ( ( params ) => {
80+ hasWatchedFilesCapability = ! ! params . capabilities . workspace ?. didChangeWatchedFiles ?. dynamicRegistration
81+
3582 const workspaceFolders = params . workspaceFolders
3683 const rootUri = workspaceFolders ?. [ 0 ] ?. uri || params . rootUri
3784
@@ -48,6 +95,9 @@ connection.onInitialize((params) => {
4895 contextManager . events . on ( 'unload' , ( ctx ) => {
4996 resetAutoCompleteCache ( ctx )
5097 } )
98+ contextManager . events . on ( 'contextLoaded' , ( ) => {
99+ void updateConfigWatchers ( )
100+ } )
51101 }
52102
53103 // Register all LSP capabilities
@@ -71,9 +121,26 @@ connection.onInitialize((params) => {
71121} )
72122
73123connection . onInitialized ( async ( ) => {
124+ serverInitialized = true
74125 if ( contextManager )
75126 await contextManager . ready
76127 connection . console . log ( '✅ UnoCSS Language Server initialized' )
128+ await updateConfigWatchers ( )
129+ } )
130+
131+ let configReloadTimer : ReturnType < typeof setTimeout > | undefined
132+
133+ connection . onDidChangeWatchedFiles ( ( _change ) => {
134+ clearTimeout ( configReloadTimer )
135+ configReloadTimer = setTimeout ( async ( ) => {
136+ if ( ! contextManager )
137+ return
138+ connection . console . log ( '🔄 Config file changed, reloading UnoCSS...' )
139+ clearAllCache ( )
140+ await contextManager . reload ( )
141+ connection . console . log ( '🔵 Reloaded.' )
142+ await updateConfigWatchers ( )
143+ } , 500 )
77144} )
78145
79146connection . onDidChangeConfiguration ( ( change ) => {
0 commit comments