diff --git a/packages/tailwindcss-class-names/src/index.js b/packages/tailwindcss-class-names/src/index.js index 1835e66efab64cbc1e93c7335b0d9cadb7a836b1..f9f39c4c9e30d741c28f7e84e2e10fc642f46f89 100644 --- a/packages/tailwindcss-class-names/src/index.js +++ b/packages/tailwindcss-class-names/src/index.js @@ -17,7 +17,7 @@ return new Promise((resolve, reject) => { let g = new nodeGlob.Glob(pattern, options) let matches = [] let max = dlv(options, 'max', Infinity) - g.on('match', (match) => { + g.on('match', match => { matches.push(path.resolve(options.cwd || process.cwd(), match)) if (matches.length === max) { g.abort() @@ -38,35 +38,39 @@ JSON.stringify(arr2.concat([]).sort()) ) } -const CONFIG_GLOB = - '**/{tailwind,tailwind.config,tailwind-config,.tailwindrc}.js' - export default async function getClassNames( cwd = process.cwd(), { onChange = () => {} } = {} ) { - async function run() { - let configPath - let postcss - let tailwindcss - let version + let configPath + let postcss + let tailwindcss + let version - configPath = await glob(CONFIG_GLOB, { - cwd, - ignore: '**/node_modules/**', - max: 1, - }) + try { + configPath = await glob( + '**/{tailwind,tailwind.config,tailwind-config,.tailwindrc}.js', + { + cwd, + ignore: '**/node_modules/**', + max: 1 + } + ) invariant(configPath.length === 1, 'No Tailwind CSS config found.') configPath = configPath[0] postcss = importFrom(cwd, 'postcss') tailwindcss = importFrom(cwd, 'tailwindcss') version = importFrom(cwd, 'tailwindcss/package.json').version + } catch (_) { + return null + } + async function run() { const sepLocation = semver.gte(version, '0.99.0') ? ['separator'] : ['options', 'separator'] let userSeperator - let hook = Hook(configPath, (exports) => { + let hook = Hook(configPath, exports => { userSeperator = dlv(exports, sepLocation) dset(exports, sepLocation, '__TAILWIND_SEPARATOR__') return exports @@ -93,48 +97,35 @@ delete config[sepLocation] } return { - configPath, config: resolveConfig({ cwd, config }), separator: typeof userSeperator === 'undefined' ? ':' : userSeperator, classNames: await extractClassNames(ast), - dependencies: hook.deps, + dependencies: [configPath, ...hook.deps], plugins: getPlugins(config), - variants: getVariants({ config, version, postcss }), + variants: getVariants({ config, version, postcss }) } } let watcher - function watch(files = []) { + function watch(files) { if (watcher) watcher.close() watcher = chokidar - .watch([CONFIG_GLOB, ...files]) + .watch(files) .on('change', handleChange) .on('unlink', handleChange) } + + let result = await run() + watch(result.dependencies) async function handleChange() { - const prevDeps = result ? result.dependencies : [] - try { - result = await run() - } catch (_) { - onChange(null) - return - } + const prevDeps = result.dependencies + result = await run() if (!arraysEqual(prevDeps, result.dependencies)) { watch(result.dependencies) } onChange(result) } - - let result - try { - result = await run() - } catch (_) { - watch() - return null - } - - watch(result.dependencies) return result } diff --git a/packages/tailwindcss-language-server/src/server.ts b/packages/tailwindcss-language-server/src/server.ts index 729d1f0c30862343cf77f8ab1c278230155392d7..58fada32d5f70b0653c5bb9228fcd71053621143 100644 --- a/packages/tailwindcss-language-server/src/server.ts +++ b/packages/tailwindcss-language-server/src/server.ts @@ -18,7 +18,7 @@ TextDocumentPositionParams, DidChangeConfigurationNotification, } from 'vscode-languageserver' import getTailwindState from 'tailwindcss-class-names' -import { State, Settings, EditorState } from './util/state' +import { State, Settings } from './util/state' import { provideCompletions, resolveCompletionItem, @@ -27,7 +27,7 @@ import { provideHover } from './providers/hoverProvider' import { URI } from 'vscode-uri' import { getDocumentSettings } from './util/getDocumentSettings' -let state: State = { enabled: false } +let state: State = null let connection = createConnection(ProposedFeatures.all) let documents = new TextDocuments() let workspaceFolder: string | null @@ -46,43 +46,28 @@ documents.listen(connection) connection.onInitialize( async (params: InitializeParams): Promise => { - const capabilities = params.capabilities - - const editorState: EditorState = { - connection, - documents, - documentSettings, - globalSettings, - capabilities: { - configuration: - capabilities.workspace && !!capabilities.workspace.configuration, - }, - } - - const tailwindState = await getTailwindState( + state = await getTailwindState( params.rootPath || URI.parse(params.rootUri).path, { onChange: (newState: State): void => { - if (newState) { - state = { ...newState, enabled: true, editor: editorState } - connection.sendNotification('tailwindcss/configUpdated', [ - state.configPath, - state.config, - state.plugins, - ]) - } else { - state = { enabled: false, editor: editorState } - // TODO - // connection.sendNotification('tailwindcss/configUpdated', [null]) - } + state = { ...newState, editor: state.editor } + connection.sendNotification('tailwindcss/configUpdated', [ + state.dependencies[0], + state.config, + state.plugins, + ]) }, } ) - if (tailwindState) { - state = { enabled: true, editor: editorState, ...tailwindState } - } else { - state = { enabled: false, editor: editorState } + const capabilities = params.capabilities + + state.editor = { + connection, + documents, + documentSettings, + globalSettings, + capabilities: { configuration: capabilities.workspace && !!capabilities.workspace.configuration }, } return { @@ -94,20 +79,7 @@ // }, textDocumentSync: documents.syncKind, completionProvider: { resolveProvider: true, - triggerCharacters: [ - // class attributes - '"', - "'", - '`', - // between class names - ' ', - // @apply and emmet-style - '.', - // config/theme helper - '[', - // TODO: restart server if separater changes? - typeof state.separator === 'undefined' ? ':' : state.separator, - ], + triggerCharacters: ['"', "'", '`', ' ', '.', '[', state.separator], }, hoverProvider: true, }, @@ -125,7 +97,7 @@ ) } connection.sendNotification('tailwindcss/configUpdated', [ - state.configPath, + state.dependencies[0], state.config, state.plugins, ]) @@ -148,21 +120,18 @@ }) connection.onCompletion( (params: CompletionParams): Promise => { - if (!state.enabled) return null return provideCompletions(state, params) } ) connection.onCompletionResolve( (item: CompletionItem): CompletionItem => { - if (!state.enabled) return null return resolveCompletionItem(state, item) } ) connection.onHover( (params: TextDocumentPositionParams): Hover => { - if (!state.enabled) return null return provideHover(state, params) } ) diff --git a/packages/tailwindcss-language-server/src/util/state.ts b/packages/tailwindcss-language-server/src/util/state.ts index 175dade6ed563cc36605c1fc3c55f5b56e900573..4b258320520a2dc616f627a4d1e5f73ad3742383 100644 --- a/packages/tailwindcss-language-server/src/util/state.ts +++ b/packages/tailwindcss-language-server/src/util/state.ts @@ -28,15 +28,13 @@ emmetCompletions: boolean } export type State = null | { - enabled: boolean - configPath?: string - config?: any - separator?: string - plugins?: any[] - variants?: string[] - classNames?: ClassNames - dependencies?: string[] - editor?: EditorState + config: any + separator: string + plugins: any[] + variants: string[] + classNames: ClassNames + dependencies: string[] + editor: EditorState } export type DocumentClassList = {