Skip to content

Commit 20da2b3

Browse files
committed
use lsp file events when available
1 parent 405f22f commit 20da2b3

File tree

1 file changed

+85
-38
lines changed
  • packages/tailwindcss-language-server/src

1 file changed

+85
-38
lines changed

packages/tailwindcss-language-server/src/server.ts

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import {
2323
CodeActionRequest,
2424
BulkUnregistration,
2525
HoverRequest,
26+
DidChangeWatchedFilesNotification,
27+
FileChangeType,
2628
} from 'vscode-languageserver/node'
2729
import { TextDocument } from 'vscode-languageserver-textdocument'
2830
import { URI } from 'vscode-uri'
@@ -32,7 +34,7 @@ import normalizePath from 'normalize-path'
3234
import * as path from 'path'
3335
import * as os from 'os'
3436
import * as fs from 'fs'
35-
import chokidar from 'chokidar'
37+
import chokidar, { FSWatcher } from 'chokidar'
3638
import findUp from 'find-up'
3739
import minimatch from 'minimatch'
3840
import 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

Comments
 (0)