diff --git a/packages/tailwindcss-language-server/src/server.ts b/packages/tailwindcss-language-server/src/server.ts index 04da9276a862fdbe75749045b8f8318c679ff8b1..463b3639274bdd51cad3d85e985a347296370a9e 100644 --- a/packages/tailwindcss-language-server/src/server.ts +++ b/packages/tailwindcss-language-server/src/server.ts @@ -25,7 +25,6 @@ BulkUnregistration, HoverRequest, DidChangeWatchedFilesNotification, FileChangeType, - Disposable, } from 'vscode-languageserver/node' import { TextDocument } from 'vscode-languageserver-textdocument' import { URI } from 'vscode-uri' @@ -74,7 +73,6 @@ import { debounce } from 'debounce' import { getModuleDependencies } from './util/getModuleDependencies' import assert from 'assert' // import postcssLoadConfig from 'postcss-load-config' -import * as parcel from './watcher/index.js' const CONFIG_FILE_GLOB = '{tailwind,tailwind.config}.{js,cjs}' const TRIGGER_CHARACTERS = [ @@ -153,7 +151,6 @@ interface ProjectService { state: State tryInit: () => Promise - dispose: () => void onUpdateSettings: (settings: any) => void onHover(params: TextDocumentPositionParams): Promise onCompletion(params: CompletionParams): Promise @@ -170,7 +167,6 @@ connection: Connection, params: InitializeParams, documentService: DocumentService ): Promise { - const disposables: Disposable[] = [] const state: State = { enabled: false, editor: { @@ -212,13 +208,7 @@ const documentSettingsCache: Map = new Map() let registrations: Promise - let chokidarWatcher: FSWatcher - let ignore = [ - '**/.git/objects/**', - '**/.git/subtree-cache/**', - '**/node_modules/**', - '**/.hg/store/**', - ] + let watcher: FSWatcher function onFileEvents(changes: Array<{ file: string; type: FileChangeType }>): void { let needsInit = false @@ -227,30 +217,22 @@ for (let change of changes) { let file = normalizePath(change.file) - for (let ignorePattern of ignore) { - if (minimatch(file, ignorePattern)) { - continue - } - } - - let isConfigFile = minimatch(file, `**/${CONFIG_FILE_GLOB}`) - let isPackageFile = minimatch(file, '**/package.json') - let isDependency = state.dependencies && state.dependencies.includes(change.file) - - if (!isConfigFile && !isPackageFile && !isDependency) continue - if (change.type === FileChangeType.Created) { needsInit = true break } else if (change.type === FileChangeType.Changed) { - if (!state.enabled || isPackageFile) { + if (!state.enabled || minimatch(file, '**/package.json')) { needsInit = true break } else { needsRebuild = true } } else if (change.type === FileChangeType.Deleted) { - if (!state.enabled || isPackageFile || isConfigFile) { + if ( + !state.enabled || + minimatch(file, '**/package.json') || + minimatch(file, `**/${CONFIG_FILE_GLOB}`) + ) { needsInit = true break } else { @@ -279,59 +261,34 @@ connection.client.register(DidChangeWatchedFilesNotification.type, { watchers: [{ globPattern: `**/${CONFIG_FILE_GLOB}` }, { globPattern: '**/package.json' }], }) - } else if (parcel.getBinding()) { - let typeMap = { - create: FileChangeType.Created, - update: FileChangeType.Changed, - delete: FileChangeType.Deleted, - } - - let subscription = await parcel.subscribe( - folder, - (err, events) => { - onFileEvents(events.map((event) => ({ file: event.path, type: typeMap[event.type] }))) - }, + } else { + watcher = chokidar.watch( + [ + normalizePath(`${folder}/**/${CONFIG_FILE_GLOB}`), + normalizePath(`${folder}/**/package.json`), + ], { - ignore: ignore.map((ignorePattern) => - path.resolve(folder, ignorePattern.replace(/^[*/]+/, '').replace(/[*/]+$/, '')) - ), + ignorePermissionErrors: true, + ignoreInitial: true, + ignored: ['**/node_modules/**'], + awaitWriteFinish: { + stabilityThreshold: 100, + pollInterval: 20, + }, } ) - disposables.push({ - dispose() { - subscription.unsubscribe() - }, - }) - } else { - chokidarWatcher = chokidar.watch([`**/${CONFIG_FILE_GLOB}`, '**/package.json'], { - cwd: folder, - ignorePermissionErrors: true, - ignoreInitial: true, - ignored: ignore, - awaitWriteFinish: { - stabilityThreshold: 100, - pollInterval: 20, - }, - }) - await new Promise((resolve) => { - chokidarWatcher.on('ready', () => resolve()) + watcher.on('ready', () => resolve()) }) - chokidarWatcher + 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 }])) - - disposables.push({ - dispose() { - chokidarWatcher.close() - }, - }) } - function registerCapabilities(watchFiles: string[] = []): void { + function registerCapabilities(watchFiles?: string[]): void { if (supportsDynamicRegistration(connection, params)) { if (registrations) { registrations.then((r) => r.dispose()) @@ -353,7 +310,7 @@ documentSelector: null, resolveProvider: true, triggerCharacters: [...TRIGGER_CHARACTERS, state.separator], }) - if (watchFiles.length > 0) { + if (watchFiles) { capabilities.add(DidChangeWatchedFilesNotification.type, { watchers: watchFiles.map((file) => ({ globPattern: file })), }) @@ -366,13 +323,13 @@ function resetState(): void { clearAllDiagnostics(state) Object.keys(state).forEach((key) => { - // Keep `dependencies` to ensure that they are still watched - if (key !== 'editor' && key !== 'dependencies') { + if (key !== 'editor') { delete state[key] } }) state.enabled = false - registerCapabilities(state.dependencies) + registerCapabilities() + // TODO reset watcher (remove config dependencies) } async function tryInit() { @@ -856,10 +813,10 @@ hook.unhook() } if (state.dependencies) { - chokidarWatcher?.unwatch(state.dependencies) + watcher?.unwatch(state.dependencies) } state.dependencies = getModuleDependencies(state.configPath) - chokidarWatcher?.add(state.dependencies) + watcher?.add(state.dependencies) state.configId = getConfigId(state.configPath, state.dependencies) @@ -880,11 +837,6 @@ return { state, tryInit, - dispose() { - for (let { dispose } of disposables) { - dispose() - } - }, onUpdateSettings(settings: any): void { documentSettingsCache.clear() if (state.enabled) { @@ -1327,9 +1279,7 @@ this.connection.listen() } dispose(): void { - for (let [, project] of this.projects) { - project.dispose() - } + // } } diff --git a/packages/tailwindcss-language-server/src/watcher/index.js b/packages/tailwindcss-language-server/src/watcher/index.js deleted file mode 100644 index fcaf7ffb7ce2d5a9928464ad5a9a787bff015f21..0000000000000000000000000000000000000000 --- a/packages/tailwindcss-language-server/src/watcher/index.js +++ /dev/null @@ -1,159 +0,0 @@ -const os = require('os') -const path = require('path') -const fs = require('fs') - -const vars = (process.config && process.config.variables) || {} -const arch = os.arch() -const platform = os.platform() -const abi = process.versions.modules -const runtime = isElectron() ? 'electron' : 'node' -const libc = process.env.LIBC || (isAlpine(platform) ? 'musl' : 'glibc') -const armv = process.env.ARM_VERSION || (arch === 'arm64' ? '8' : vars.arm_version) || '' -const uv = (process.versions.uv || '').split('.')[0] - -const prebuilds = { - 'darwin-x64': { - 'node.napi.glibc.node': () => require('./prebuilds/darwin-x64.node.napi.glibc.node'), - }, - 'linux-x64': { - 'node.napi.glibc.node': () => require('./prebuilds/linux-x64.node.napi.glibc.node'), - 'node.napi.musl.node': () => require('./prebuilds/linux-x64.node.napi.musl.node'), - }, - 'win32-x64': { - 'node.napi.glibc.node': () => require('./prebuilds/win32-x64.node.napi.glibc.node'), - }, -} - -let getBinding = () => { - let resolved = resolve() - getBinding = () => resolved - return resolved -} - -exports.getBinding = getBinding - -exports.writeSnapshot = (dir, snapshot, opts) => { - return getBinding().writeSnapshot( - path.resolve(dir), - path.resolve(snapshot), - normalizeOptions(dir, opts) - ) -} - -exports.getEventsSince = (dir, snapshot, opts) => { - return getBinding().getEventsSince( - path.resolve(dir), - path.resolve(snapshot), - normalizeOptions(dir, opts) - ) -} - -exports.subscribe = async (dir, fn, opts) => { - dir = path.resolve(dir) - opts = normalizeOptions(dir, opts) - await getBinding().subscribe(dir, fn, opts) - - return { - unsubscribe() { - return getBinding().unsubscribe(dir, fn, opts) - }, - } -} - -exports.unsubscribe = (dir, fn, opts) => { - return getBinding().unsubscribe(path.resolve(dir), fn, normalizeOptions(dir, opts)) -} - -function resolve() { - // Find most specific flavor first - var list = prebuilds[platform + '-' + arch] - var builds = Object.keys(list) - var parsed = builds.map(parseTags) - var candidates = parsed.filter(matchTags(runtime, abi)) - var winner = candidates.sort(compareTags(runtime))[0] - if (winner) return list[winner.file]() -} - -function parseTags(file) { - var arr = file.split('.') - var extension = arr.pop() - var tags = { file: file, specificity: 0 } - - if (extension !== 'node') return - - for (var i = 0; i < arr.length; i++) { - var tag = arr[i] - - if (tag === 'node' || tag === 'electron' || tag === 'node-webkit') { - tags.runtime = tag - } else if (tag === 'napi') { - tags.napi = true - } else if (tag.slice(0, 3) === 'abi') { - tags.abi = tag.slice(3) - } else if (tag.slice(0, 2) === 'uv') { - tags.uv = tag.slice(2) - } else if (tag.slice(0, 4) === 'armv') { - tags.armv = tag.slice(4) - } else if (tag === 'glibc' || tag === 'musl') { - tags.libc = tag - } else { - continue - } - - tags.specificity++ - } - - return tags -} - -function matchTags(runtime, abi) { - return function (tags) { - if (tags == null) return false - if (tags.runtime !== runtime && !runtimeAgnostic(tags)) return false - if (tags.abi !== abi && !tags.napi) return false - if (tags.uv && tags.uv !== uv) return false - if (tags.armv && tags.armv !== armv) return false - if (tags.libc && tags.libc !== libc) return false - - return true - } -} - -function runtimeAgnostic(tags) { - return tags.runtime === 'node' && tags.napi -} - -function compareTags(runtime) { - // Precedence: non-agnostic runtime, abi over napi, then by specificity. - return function (a, b) { - if (a.runtime !== b.runtime) { - return a.runtime === runtime ? -1 : 1 - } else if (a.abi !== b.abi) { - return a.abi ? -1 : 1 - } else if (a.specificity !== b.specificity) { - return a.specificity > b.specificity ? -1 : 1 - } else { - return 0 - } - } -} - -function normalizeOptions(dir, opts = {}) { - if (Array.isArray(opts.ignore)) { - opts = Object.assign({}, opts, { - ignore: opts.ignore.map((ignore) => path.resolve(dir, ignore)), - }) - } - - return opts -} - -function isElectron() { - if (process.versions && process.versions.electron) return true - if (process.env.ELECTRON_RUN_AS_NODE) return true - return typeof window !== 'undefined' && window.process && window.process.type === 'renderer' -} - -function isAlpine(platform) { - return platform === 'linux' && fs.existsSync('/etc/alpine-release') -} diff --git a/packages/tailwindcss-language-server/src/watcher/licenses/@parcel/watcher b/packages/tailwindcss-language-server/src/watcher/licenses/@parcel/watcher deleted file mode 100644 index 7fb9bc953e90740cb60a6401b25dc36d5a19cdfd..0000000000000000000000000000000000000000 --- a/packages/tailwindcss-language-server/src/watcher/licenses/@parcel/watcher +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017-present Devon Govett - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/tailwindcss-language-server/src/watcher/licenses/node-gyp-build b/packages/tailwindcss-language-server/src/watcher/licenses/node-gyp-build deleted file mode 100644 index 56fce0895e13ffe83650a7274d79fbcfb80d3e2f..0000000000000000000000000000000000000000 --- a/packages/tailwindcss-language-server/src/watcher/licenses/node-gyp-build +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Mathias Buus - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/packages/tailwindcss-language-server/src/watcher/prebuilds/darwin-x64.node.napi.glibc.node b/packages/tailwindcss-language-server/src/watcher/prebuilds/darwin-x64.node.napi.glibc.node deleted file mode 100644 index b96f68ca183afb097501a039daab87fce501d088..0000000000000000000000000000000000000000 Binary files a/packages/tailwindcss-language-server/src/watcher/prebuilds/darwin-x64.node.napi.glibc.node and /dev/null differ diff --git a/packages/tailwindcss-language-server/src/watcher/prebuilds/linux-x64.node.napi.glibc.node b/packages/tailwindcss-language-server/src/watcher/prebuilds/linux-x64.node.napi.glibc.node deleted file mode 100644 index af791d083e79cd5c19536b9e78292eb6b270546c..0000000000000000000000000000000000000000 Binary files a/packages/tailwindcss-language-server/src/watcher/prebuilds/linux-x64.node.napi.glibc.node and /dev/null differ diff --git a/packages/tailwindcss-language-server/src/watcher/prebuilds/linux-x64.node.napi.musl.node b/packages/tailwindcss-language-server/src/watcher/prebuilds/linux-x64.node.napi.musl.node deleted file mode 100644 index 7b62ac3479f4ef58272e20b5108b1fac223cec80..0000000000000000000000000000000000000000 Binary files a/packages/tailwindcss-language-server/src/watcher/prebuilds/linux-x64.node.napi.musl.node and /dev/null differ diff --git a/packages/tailwindcss-language-server/src/watcher/prebuilds/win32-x64.node.napi.glibc.node b/packages/tailwindcss-language-server/src/watcher/prebuilds/win32-x64.node.napi.glibc.node deleted file mode 100644 index 4bc689f13cebcfd982f81c38fdad6ba16e77b931..0000000000000000000000000000000000000000 Binary files a/packages/tailwindcss-language-server/src/watcher/prebuilds/win32-x64.node.napi.glibc.node and /dev/null differ diff --git a/packages/vscode-tailwindcss/.vscodeignore b/packages/vscode-tailwindcss/.vscodeignore index 23a3765012ba19ce42944e57493f1462fe5c191d..b3e111a8330f0802c463b444230549bb6d570188 100755 --- a/packages/vscode-tailwindcss/.vscodeignore +++ b/packages/vscode-tailwindcss/.vscodeignore @@ -8,4 +8,3 @@ **/*.ts **/*.map .gitignore **/tsconfig.json -**/*.node