use lsp file events when available

master
Brad Cornes 2021-06-05 15:44:21 +01:00
parent 405f22f339
commit 20da2b3e67
1 changed files with 88 additions and 41 deletions

View File

@ -23,6 +23,8 @@ import {
CodeActionRequest, CodeActionRequest,
BulkUnregistration, BulkUnregistration,
HoverRequest, HoverRequest,
DidChangeWatchedFilesNotification,
FileChangeType,
} from 'vscode-languageserver/node' } from 'vscode-languageserver/node'
import { TextDocument } from 'vscode-languageserver-textdocument' import { TextDocument } from 'vscode-languageserver-textdocument'
import { URI } from 'vscode-uri' import { URI } from 'vscode-uri'
@ -32,7 +34,7 @@ import normalizePath from 'normalize-path'
import * as path from 'path' import * as path from 'path'
import * as os from 'os' import * as os from 'os'
import * as fs from 'fs' import * as fs from 'fs'
import chokidar from 'chokidar' import chokidar, { FSWatcher } from 'chokidar'
import findUp from 'find-up' import findUp from 'find-up'
import minimatch from 'minimatch' import minimatch from 'minimatch'
import resolveFrom, { setPnpApi } from './util/resolveFrom' import resolveFrom, { setPnpApi } from './util/resolveFrom'
@ -206,47 +208,87 @@ async function createProjectService(
const documentSettingsCache: Map<string, Settings> = new Map() const documentSettingsCache: Map<string, Settings> = new Map()
let registrations: Promise<BulkUnregistration> let registrations: Promise<BulkUnregistration>
const watcher = chokidar.watch( let watcher: FSWatcher
[normalizePath(`${folder}/**/${CONFIG_FILE_GLOB}`), normalizePath(`${folder}/**/package.json`)],
{ function onFileEvents(changes: Array<{ file: string; type: FileChangeType }>): void {
ignorePermissionErrors: true, let needsInit = false
ignoreInitial: true, let needsRebuild = false
ignored: ['**/node_modules/**'],
awaitWriteFinish: { for (let change of changes) {
stabilityThreshold: 100, let file = normalizePath(change.file)
pollInterval: 20,
}, if (change.type === FileChangeType.Created) {
needsInit = true
break
} else if (change.type === FileChangeType.Changed) {
if (!state.enabled || minimatch(file, '**/package.json')) {
needsInit = true
break
} else {
needsRebuild = true
}
} else if (change.type === FileChangeType.Deleted) {
if (
!state.enabled ||
minimatch(file, '**/package.json') ||
minimatch(file, `**/${CONFIG_FILE_GLOB}`)
) {
needsInit = true
break
} else {
needsRebuild = true
}
}
} }
)
await new Promise<void>((resolve) => { if (needsInit) {
watcher.on('ready', () => resolve())
})
watcher
.on('add', () => {
tryInit() tryInit()
}) } else if (needsRebuild) {
.on('unlink', (file) => { tryRebuild()
if ( }
!state.enabled || }
minimatch(file, '**/package.json') ||
minimatch(file, `**/${CONFIG_FILE_GLOB}`) if (params.capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration) {
) { connection.onDidChangeWatchedFiles(({ changes }) => {
tryInit() onFileEvents(
} else { changes.map(({ uri, type }) => ({
tryRebuild() file: URI.parse(uri).fsPath,
} type,
}) }))
.on('change', (file) => { )
if (!state.enabled || minimatch(file, '**/package.json')) {
tryInit()
} else {
tryRebuild()
}
}) })
function registerCapabilities(): void { connection.client.register(DidChangeWatchedFilesNotification.type, {
watchers: [{ globPattern: `**/${CONFIG_FILE_GLOB}` }, { globPattern: '**/package.json' }],
})
} else {
watcher = chokidar.watch(
[
normalizePath(`${folder}/**/${CONFIG_FILE_GLOB}`),
normalizePath(`${folder}/**/package.json`),
],
{
ignorePermissionErrors: true,
ignoreInitial: true,
ignored: ['**/node_modules/**'],
awaitWriteFinish: {
stabilityThreshold: 100,
pollInterval: 20,
},
}
)
await new Promise<void>((resolve) => {
watcher.on('ready', () => resolve())
})
watcher
.on('add', (file) => onFileEvents([{ file, type: FileChangeType.Created }]))
.on('change', (file) => onFileEvents([{ file, type: FileChangeType.Changed }]))
.on('unlink', (file) => onFileEvents([{ file, type: FileChangeType.Deleted }]))
}
function registerCapabilities(watchFiles?: string[]): void {
if (supportsDynamicRegistration(connection, params)) { if (supportsDynamicRegistration(connection, params)) {
if (registrations) { if (registrations) {
registrations.then((r) => r.dispose()) registrations.then((r) => r.dispose())
@ -268,6 +310,11 @@ async function createProjectService(
resolveProvider: true, resolveProvider: true,
triggerCharacters: [...TRIGGER_CHARACTERS, state.separator], triggerCharacters: [...TRIGGER_CHARACTERS, state.separator],
}) })
if (watchFiles) {
capabilities.add(DidChangeWatchedFilesNotification.type, {
watchers: watchFiles.map((file) => ({ globPattern: file })),
})
}
registrations = connection.client.register(capabilities) registrations = connection.client.register(capabilities)
} }
@ -766,10 +813,10 @@ async function createProjectService(
} }
if (state.dependencies) { if (state.dependencies) {
watcher.unwatch(state.dependencies) watcher?.unwatch(state.dependencies)
} }
state.dependencies = getModuleDependencies(state.configPath) state.dependencies = getModuleDependencies(state.configPath)
watcher.add(state.dependencies) watcher?.add(state.dependencies)
state.configId = getConfigId(state.configPath, state.dependencies) state.configId = getConfigId(state.configPath, state.dependencies)
@ -784,7 +831,7 @@ async function createProjectService(
updateAllDiagnostics(state) updateAllDiagnostics(state)
registerCapabilities() registerCapabilities(state.dependencies)
} }
return { return {
@ -796,7 +843,7 @@ async function createProjectService(
updateAllDiagnostics(state) updateAllDiagnostics(state)
} }
if (settings.editor.colorDecorators) { if (settings.editor.colorDecorators) {
registerCapabilities() registerCapabilities(state.dependencies)
} else { } else {
connection.sendNotification('@/tailwindCSS/clearColors') connection.sendNotification('@/tailwindCSS/clearColors')
} }