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,8 +208,65 @@ 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 {
let needsInit = false
let needsRebuild = false
for (let change of changes) {
let file = normalizePath(change.file)
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
}
}
}
if (needsInit) {
tryInit()
} else if (needsRebuild) {
tryRebuild()
}
}
if (params.capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration) {
connection.onDidChangeWatchedFiles(({ changes }) => {
onFileEvents(
changes.map(({ uri, type }) => ({
file: URI.parse(uri).fsPath,
type,
}))
)
})
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, ignorePermissionErrors: true,
ignoreInitial: true, ignoreInitial: true,
@ -224,29 +283,12 @@ async function createProjectService(
}) })
watcher watcher
.on('add', () => { .on('add', (file) => onFileEvents([{ file, type: FileChangeType.Created }]))
tryInit() .on('change', (file) => onFileEvents([{ file, type: FileChangeType.Changed }]))
}) .on('unlink', (file) => onFileEvents([{ file, type: FileChangeType.Deleted }]))
.on('unlink', (file) => {
if (
!state.enabled ||
minimatch(file, '**/package.json') ||
minimatch(file, `**/${CONFIG_FILE_GLOB}`)
) {
tryInit()
} else {
tryRebuild()
} }
})
.on('change', (file) => {
if (!state.enabled || minimatch(file, '**/package.json')) {
tryInit()
} else {
tryRebuild()
}
})
function registerCapabilities(): void { 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')
} }