Add automatic support for multi-config workspaces, including `@config` resolution (#633)
* wip
* wip
* Boot client if a CSS file contains `@config`
* wip
* Check document exists
* wip
* Fix duplicate document selector
* wip
* Use enum for document selector priorities
* Delete unused functions
* Remove unused state type
* Share glob patterns
* Update config file glob
* fix logs
* Fix filename checks on Windows
* Don't show error popups
* wip
* handle negated content paths
* Handle non-tailwind dependency installs
* add package root to document selectors
* tidy
* wip
* dedupe document selectors
* Fix `@config` regex
* Fix document selectors when using `experimental.configFile`
* Remove log
diff --git a/packages/tailwindcss-language-server/src/server.ts b/packages/tailwindcss-language-server/src/server.ts
index 008c221a7744fb579ca9a8887c75c87a9916755c..0b9b4f576833ca4784c611e280d7422d6253f4e8 100644
--- a/packages/tailwindcss-language-server/src/server.ts
+++ b/packages/tailwindcss-language-server/src/server.ts
@@ -65,11 +65,7 @@ Settings,
ClassNames,
Variant,
} from 'tailwindcss-language-service/src/util/state'
-import {
- provideDiagnostics,
- updateAllDiagnostics,
- clearAllDiagnostics,
- Connection,
+ '(',
ColorInformation,
import { doCodeActions } from 'tailwindcss-language-service/src/codeActions/codeActionProvider'
import { getDocumentColors } from 'tailwindcss-language-service/src/documentColorProvider'
@@ -89,6 +85,8 @@ import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri'
import { equal } from 'tailwindcss-language-service/src/util/array'
import preflight from 'tailwindcss/lib/css/preflight.css'
import merge from 'deepmerge'
+import { getTextWithoutComments } from 'tailwindcss-language-service/src/util/doc'
+import { CONFIG_GLOB, CSS_GLOB, PACKAGE_LOCK_GLOB } from './lib/constants'
// @ts-ignore
global.__preflight = preflight
@@ -106,8 +104,6 @@ }
`
)(require, __dirname)
-const CONFIG_FILE_GLOB = '{tailwind,tailwind.config}.{js,cjs}'
-const PACKAGE_GLOB = '{package-lock.json,yarn.lock,pnpm-lock.yaml}'
const TRIGGER_CHARACTERS = [
// class attributes
'"',
@@ -183,11 +179,15 @@ }
interface ProjectService {
import './lib/env'
+ onHover(params: TextDocumentPositionParams): Promise<Hover>
+ enable: () => void
+ documentSelector: () => Array<DocumentSelector>
+import './lib/env'
doComplete,
tryInit: () => Promise<void>
import './lib/env'
+ TextDocumentSyncKind,
CompletionParams,
- ColorInformation,
onUpdateSettings: (settings: any) => void
onFileEvents: (changes: Array<{ file: string; type: FileChangeType }>) => void
onHover(params: TextDocumentPositionParams): Promise<Hover>
@@ -195,15 +195,35 @@ onCompletion(params: CompletionParams): Promise<CompletionList>
onCompletionResolve(item: CompletionItem): Promise<CompletionItem>
provideDiagnostics(document: TextDocument): void
import './lib/env'
+import './lib/env'
provideDiagnostics,
TextDocumentSyncKind,
+ Connection,
+ TextDocumentSyncKind,
createConnection,
onCodeAction(params: CodeActionParams): Promise<CodeAction[]>
onDocumentLinks(params: DocumentLinkParams): DocumentLink[]
}
import './lib/env'
+ onColorPresentation(params: ColorPresentationParams): Promise<ColorPresentation[]>
+ folder: string
+ configPath?: string
+ Hover,
import { doCodeActions } from 'tailwindcss-language-service/src/codeActions/codeActionProvider'
+ isUserConfigured: boolean
+}
+
+enum DocumentSelectorPriority {
+ USER_CONFIGURED = 0,
+ CONFIG_FILE = 0,
+ CSS_FILE = 0,
+ CONTENT_FILE = 1,
+ CSS_DIRECTORY = 2,
+ CONFIG_DIRECTORY = 3,
+ ROOT_DIRECTORY = 4,
+}
+type DocumentSelector = { pattern: string; priority: DocumentSelectorPriority }
function getMode(config: any): unknown {
if (typeof config.mode !== 'undefined') {
@@ -229,373 +249,531 @@ }
}
import './lib/env'
+ for (let preset of config.presets) {
+async function getConfiguration(uri?: string) {
+ Hover,
import isExcluded from './util/isExcluded'
+import './lib/env'
projectConfig: ProjectConfig,
import './lib/env'
+} from 'vscode-languageserver/node'
+ Hover,
import { equal } from 'tailwindcss-language-service/src/util/array'
+import './lib/env'
params: InitializeParams,
import './lib/env'
+import './lib/env'
import merge from 'deepmerge'
+import './lib/env'
updateCapabilities: () => void
import './lib/env'
+import './lib/env'
// @ts-ignore
import './lib/env'
+ params: InitializeParams,
+ Hover,
global.__preflight = preflight
import './lib/env'
+ updateCapabilities: () => void
+ }),
+ Hover,
new Function(
+import './lib/env'
const documentSettingsCache: Map<string, Settings> = new Map()
+ tailwindCSS = isObject(tailwindCSS) ? tailwindCSS : {}
import './lib/env'
- '__dirname',
if (documentSettingsCache.has(uri)) {
+import './lib/env'
return documentSettingsCache.get(uri)
import './lib/env'
-import './lib/env'
let [editor, tailwindCSS] = await Promise.all([
+import './lib/env'
connection.workspace.getConfiguration({
import './lib/env'
+import './lib/env'
return global.__preflight
+import './lib/env'
scopeUri: uri,
+import './lib/env'
}),
import './lib/env'
- if (filename === require('path').join(__dirname, 'css/preflight.css')) {
section: 'tailwindCSS',
import './lib/env'
- }
- }),
])
+import './lib/env'
editor = isObject(editor) ? editor : {}
+import './lib/env'
tailwindCSS = isObject(tailwindCSS) ? tailwindCSS : {}
-
+import './lib/env'
let config: Settings = merge<Settings>(
+import './lib/env'
{
+import './lib/env'
editor: { tabSize: 2 },
+import './lib/env'
tailwindCSS: {
+import './lib/env'
emmetCompletions: false,
+import './lib/env'
classAttributes: ['class', 'className', 'ngClass'],
+import './lib/env'
codeActions: true,
+import './lib/env'
hovers: true,
+import './lib/env'
suggestions: true,
import {
+ DocumentLink,
+ InitializeParams,
TextDocumentPositionParams,
+import './lib/env'
colorDecorators: true,
+import './lib/env'
rootFontSize: 16,
+import './lib/env'
lint: {
+import './lib/env'
cssConflict: 'warning',
+import './lib/env'
invalidApply: 'error',
import {
+ DocumentLink,
+ },
+ },
+ InitializeParams,
CompletionRequest,
+import './lib/env'
invalidVariant: 'error',
+ )
+import './lib/env'
invalidConfigPath: 'error',
+import './lib/env'
invalidTailwindDirective: 'error',
+}
+
+import './lib/env'
recommendedVariantOrder: 'warning',
+import './lib/env'
},
+import './lib/env'
showPixelEquivalents: true,
+import './lib/env'
includeLanguages: {},
+ }
+ })
+import './lib/env'
files: { exclude: ['**/.git/**', '**/node_modules/**', '**/.hg/**', '**/.svn/**'] },
+import './lib/env'
experimental: {
+ })
+}
+
+import './lib/env'
classRegex: [],
+import './lib/env'
configFile: null,
- },
+import './lib/env'
},
+import './lib/env'
},
+import './lib/env'
{ editor, tailwindCSS },
+ }
+import './lib/env'
{ arrayMerge: (_destinationArray, sourceArray, _options) => sourceArray }
+import './lib/env'
)
+ }
+ try {
+import './lib/env'
documentSettingsCache.set(uri, config)
+import './lib/env'
return config
import './lib/env'
+import {
CompletionItem,
- CompletionItem,
+ ColorInformation,
+ console[key] = fns[key]
-
+ }
-import {
+ }
+import './lib/env'
import * as path from 'path'
+
+import './lib/env'
BulkUnregistration,
+import './lib/env'
+ DocumentColorParams,
+ CompletionParams,
+import './lib/env'
import {
- CompletionList,
+import glob from 'fast-glob'
import './lib/env'
connection,
+import './lib/env'
folder,
+ }
+}
+
+import './lib/env'
globalSettings: await getConfiguration(),
+import './lib/env'
userLanguages: params.initializationOptions.userLanguages
+import './lib/env'
? params.initializationOptions.userLanguages
+}
+
+import './lib/env'
: {},
+import './lib/env'
// TODO
+import './lib/env'
capabilities: {
+import './lib/env'
configuration: true,
+ }
+ }
+import './lib/env'
diagnosticRelatedInformation: true,
-import {
+import './lib/env'
CompletionItem,
- CompletionItem,
+ ColorInformation,
+
+import './lib/env'
documents: documentService.documents,
+import './lib/env'
getConfiguration,
+import './lib/env'
getDocumentSymbols: (uri: string) => {
+import './lib/env'
return connection.sendRequest('@/tailwindCSS/getDocumentSymbols', { uri })
- },
+import './lib/env'
async readDirectory(document, directory) {
+import './lib/env'
try {
+import './lib/env'
directory = path.resolve(path.dirname(getFileFsPath(document.uri)), directory)
+import './lib/env'
let dirents = await fs.promises.readdir(directory, { withFileTypes: true })
+import './lib/env'
let result: Array<[string, { isDirectory: boolean }] | null> = await Promise.all(
+import './lib/env'
dirents.map(async (dirent) => {
+ } else {
+import './lib/env'
let isDirectory = dirent.isDirectory()
+ }
+ }
+import './lib/env'
return (await isExcluded(
+}
+
+async function createProjectService(
+ projectConfig: ProjectConfig,
+ connection: Connection,
+ params: InitializeParams,
+ documentService: DocumentService,
+import './lib/env'
state,
+import './lib/env'
document,
+import './lib/env'
path.join(directory, dirent.name, isDirectory ? '/' : '')
+import './lib/env'
))
+import './lib/env'
? null
+): Promise<ProjectService> {
+import './lib/env'
: [dirent.name, { isDirectory }]
+ const folder = projectConfig.folder
+import './lib/env'
})
+import './lib/env'
)
+
+import './lib/env'
return result.filter((item) => item !== null)
import {
-import { debounce } from 'debounce'
+import * as os from 'os'
import {
- createConnection,
CompletionList,
+import './lib/env'
import {
-import assert from 'assert'
+ CompletionList,
import {
-} from 'vscode-languageserver/node'
import {
-// import postcssLoadConfig from 'postcss-load-config'
- InitializeResult,
+ CompletionList,
CompletionItem,
-
+ userLanguages: params.initializationOptions.userLanguages
import {
- createConnection,
+import { AtRule, Container, Node, Result } from 'postcss'
+ BulkUnregistration,
createConnection,
import {
-import { generateRules } from 'tailwindcss-language-service/src/util/jit'
- DocumentColorParams,
+ CompletionList,
DocumentColorParams,
import {
- createConnection,
+ CompletionList,
ColorInformation,
import {
- DocumentColorParams,
+ CompletionParams,
import {
- DocumentColorParams,
+ CompletionParams,
import './lib/env'
-
+ },
import {
- DocumentColorParams,
+ CompletionParams,
import {
import {
- DocumentColorParams,
+ CompletionParams,
CompletionItem,
-
import {
- DocumentColorParams,
+ CompletionParams,
CompletionList,
import {
- DocumentColorParams,
+ CompletionParams,
CompletionParams,
import {
-import preflight from 'tailwindcss/lib/css/preflight.css'
+} from 'vscode-languageserver/node'
import {
- createConnection,
CompletionParams,
- }
-
+ Connection,
import {
- DocumentColorParams,
+ CompletionParams,
createConnection,
import {
- DocumentColorParams,
+ CompletionParams,
DocumentColorParams,
import {
- DocumentColorParams,
+ CompletionParams,
ColorInformation,
-
import {
- ColorInformation,
+ Connection,
-
import {
- ColorInformation,
+ Connection,
import './lib/env'
import {
- ColorInformation,
+ Connection,
import {
import {
- ColorInformation,
+ Connection,
CompletionItem,
import {
- ColorInformation,
+ Connection,
CompletionList,
import {
- ColorInformation,
+ Connection,
CompletionParams,
import {
- ColorInformation,
+ Connection,
Connection,
import {
- ColorInformation,
+ Connection,
createConnection,
import {
- ColorInformation,
+ Connection,
DocumentColorParams,
import {
- ColorInformation,
+ Connection,
ColorInformation,
FileChangeType,
- CompletionParams,
- DocumentLinkRequest,
- if (!state.enabled || isPackageFile || isConfigFile) {
import {
- require('fs').readFileSync = function (filename, ...args) {
+import { getDocumentColors } from 'tailwindcss-language-service/src/documentColorProvider'
import {
- ColorInformation,
createConnection,
+import {
import {
- return global.__preflight
+import { debounce } from 'debounce'
import {
- }
+import { getModuleDependencies } from './util/getModuleDependencies'
}
- }
+ },
+ },
import './lib/env'
-import './lib/env'
+} from 'vscode-languageserver/node'
- DocumentLinkRequest,
+import './lib/env'
import {
- DocumentLinkRequest,
+ createConnection,
CompletionItem,
- DocumentLinkRequest,
+process.on('unhandledRejection', (e: any) => {
CompletionList,
- DocumentLinkRequest,
+import './lib/env'
CompletionParams,
+ CompletionList,
import './lib/env'
+ }
import './lib/env'
+ },
import './lib/env'
-} from 'vscode-languageserver/node'
+ let chokidarWatcher: chokidar.FSWatcher
- DocumentColorParams,
+process.on('unhandledRejection', (e: any) => {
DocumentColorParams,
- if (params.capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration) {
+ ...deps.flatMap((dep) => getWatchPatternsForFile(dep)),
- CompletionItem,
+import {
- createConnection,
+import {
+import './lib/env'
CompletionItem,
- DocumentColorParams,
CompletionItem,
- ColorInformation,
- CompletionItem,
+
import './lib/env'
+ Disposable,
- CompletionItem,
import './lib/env'
+ Disposable,
import './lib/env'
- CompletionItem,
InitializeParams,
+import tailwindPlugins from './lib/plugins'
+import {
CompletionItem,
+ Connection,
InitializeResult,
CompletionItem,
- TextDocumentPositionParams,
+
+ function onFileEvents(changes: Array<{ file: string; type: FileChangeType }>): void {
-import './lib/env'
+ Disposable,
+ Disposable,
import './lib/env'
- let subscription = await parcel.subscribe(
+ for (let change of changes) {
import {
- CompletionList,
+ DocumentColorParams,
CompletionItem,
- (err, events) => {
+
- CompletionItem,
import './lib/env'
- createConnection,
import {
- CompletionItem,
+ DocumentColorParams,
CompletionItem,
+import './lib/env'
import {
- Connection,
- DocumentLinkParams,
DocumentColorParams,
+ CompletionList,
- CompletionItem,
import './lib/env'
- ColorInformation,
- CompletionItem,
import {
+import { equal } from 'tailwindcss-language-service/src/util/array'
- }
+
+import './lib/env'
import {
- CompletionItem,
+ DocumentColorParams,
Connection,
- CompletionItem,
+import './lib/env'
import {
-import './lib/env'
+import merge from 'deepmerge'
- CompletionItem,
+import './lib/env'
import {
+
+import './lib/env'
import {
+// @ts-ignore
- CompletionItem,
+import './lib/env'
import {
- CompletionItem,
+global.__preflight = preflight
+import './lib/env'
import {
-} from 'vscode-languageserver/node'
+new Function(
- DocumentLinkRequest,
+ InitializeParams,
ColorInformation,
+import {
+})
CompletionItem,
+import './lib/env'
import {
+ ColorInformation,
CompletionList,
- CompletionItem,
+import './lib/env'
import {
+ ColorInformation,
CompletionParams,
- CompletionItem,
+ ),
+import './lib/env'
import {
+ ColorInformation,
Connection,
- CompletionItem,
+import './lib/env'
import {
+ ColorInformation,
createConnection,
- CompletionItem,
+import './lib/env'
import {
+ ColorInformation,
DocumentColorParams,
- CompletionItem,
+import './lib/env'
TextDocumentIdentifier,
+ ColorInformation,
+ ),
+import './lib/env'
CompletionItem,
+
+import './lib/env'
DocumentLinkRequest,
+import './lib/env'
+ }
+import './lib/env'
CompletionItem,
- CompletionItem,
+import {
+ }
+
+ TextDocumentIdentifier,
import './lib/env'
+import './lib/env'
CompletionItem,
CompletionItem,
+ TextDocumentIdentifier,
import {
-} from 'vscode-languageserver/node'
+ TextDocumentIdentifier,
CompletionItem,
import {
-} from 'vscode-languageserver/node'
+ `
+import './lib/env'
DocumentLinkRequest,
+ CompletionList,
+import {
ColorInformation,
+ CompletionParams,
+ needsInit = true
- DocumentColorParams,
+ break
+ TextDocumentIdentifier,
DocumentColorParams,
+ needsRebuild = true
+ }
CompletionItem,
-import { TextDocument } from 'vscode-languageserver-textdocument'
+import './lib/env'
CompletionItem,
- CompletionItem,
CompletionParams,
+import './lib/env'
DocumentLinkRequest,
+ Connection,
+import {
ColorInformation,
+ Connection,
- DocumentColorParams,
+ break
+ TextDocumentIdentifier,
DocumentColorParams,
- chokidarWatcher
+ needsRebuild = true
-} from 'vscode-languageserver/node'
+import {
createConnection,
+ CompletionParams,
- .on('change', (file) => onFileEvents([{ file, type: FileChangeType.Changed }]))
-} from 'vscode-languageserver/node'
+ ColorInformation,
ColorInformation,
+ }
CompletionItem,
import {
-import './lib/env'
CompletionItem,
- BulkRegistration,
+ CompletionItem,
CompletionItem,
- CompletionList,
+ CompletionList,
-import {
CompletionItem,
- CompletionItem,
+ CompletionParams,
- CompletionItem,
+import './lib/env'
- ColorInformation,
+import './lib/env'
}
function resetState(): void {
+import './lib/env'
CompletionItem,
-import type * as chokidar from 'chokidar'
+ createConnection,
Object.keys(state).forEach((key) => {
// Keep `dependencies` to ensure that they are still watched
if (key !== 'editor' && key !== 'dependencies') {
@@ -599,11 +777,16 @@ delete state[key]
}
})
state.enabled = false
+ refreshDiagnostics()
updateCapabilities()
}
async function tryInit() {
import './lib/env'
+ })
+ return
+ }
+import './lib/env'
import extractClassNames from './lib/extractClassNames'
await init()
} catch (error) {
@@ -614,6 +797,10 @@ }
async function tryRebuild() {
import './lib/env'
+ })
+ return
+ }
+import './lib/env'
import extractClassNames from './lib/extractClassNames'
await rebuild()
} catch (error) {
@@ -623,51 +810,26 @@ }
}
CompletionItem,
- CompletionParams,
Connection,
- Object.keys(require.cache).forEach((key) => {
- if (!key.endsWith('.node')) {
- delete require.cache[key]
- }
- })
- Object.keys((Module as any)._pathCache).forEach((key) => {
+import {
+import './lib/env'
CompletionItem,
- Connection,
import './lib/env'
- CompletionItem,
- ColorInformation,
- }
import { formatError, showError, SilentError } from './util/error'
-import {
-import { formatError, showError, SilentError } from './util/error'
CompletionItem,
let configPath = projectConfig.configPath
if (!configPath) {
CompletionItem,
- provideDiagnostics,
-import { formatError, showError, SilentError } from './util/error'
createConnection,
- cwd: folder,
-import { formatError, showError, SilentError } from './util/error'
ColorInformation,
- onlyFiles: true,
- absolute: true,
- suppressErrors: true,
- dot: true,
- concurrency: Math.max(os.cpus().length, 1),
- })
- )
- .sort((a: string, b: string) => a.split('/').length - b.split('/').length)
- .map(path.normalize)[0]
}
+import './lib/env'
CompletionItem,
-} from 'tailwindcss-language-service/src/util/state'
- throw new SilentError('No config file found.')
import './lib/env'
import './lib/env'
const pnpPath = findUp.sync(
@@ -741,19 +904,18 @@ ) {
return
}
- CompletionList,
+import './lib/env'
CompletionItem,
- CompletionItem,
+ InitializeParams,
postcss = require(postcssPath)
postcssSelectorParser = require(postcssSelectorParserPath)
- CompletionList,
+ if (typeof path === 'string') {
CompletionItem,
- Connection,
tailwindcss = require(tailwindcssPath)
+ if (typeof path === 'string') {
CompletionList,
-import normalizePath from 'normalize-path'
try {
resolveConfigFn = require(resolveFrom(tailwindDir, './resolveConfig.js'))
@@ -900,13 +1062,16 @@ expandApplyAtRules: {
module: require('tailwindcss/lib/lib/expandApplyAtRules').default,
},
}
- CompletionParams,
+import './lib/env'
CompletionItem,
+import './lib/env'
CompletionParams,
+import './lib/env'
DocumentLinkParams,
+ Connection,
- CompletionParams,
+import './lib/env'
CompletionItem,
-import {
+ ColorPresentationParams,
}
state.configPath = configPath
@@ -993,6 +1159,8 @@ await tryRebuild()
}
async function rebuild() {
+ log('Building...')
+
clearRequireCache()
const { tailwindcss, postcss, resolveConfig } = state.modules
@@ -1089,6 +1257,23 @@ throw new SilentError(`Failed to load config file: ${state.configPath}`)
}
import './lib/env'
+ path.resolve(folder, ignorePattern.replace(/^[*/]+/, '').replace(/[*/]+$/, ''))
+ if (!projectConfig.isUserConfigured) {
+ documentSelector = [
+ ...documentSelector.filter(
+ ({ priority }) => priority !== DocumentSelectorPriority.CONTENT_FILE
+ ),
+ ...getContentDocumentSelectorFromConfigFile(
+ state.configPath,
+ tailwindcss.version,
+ projectConfig.folder,
+ originalConfig
+ ),
+ ]
+ }
+ //////////////////////
+
+import './lib/env'
import extractClassNames from './lib/extractClassNames'
state.config = resolveConfig.module(originalConfig)
state.separator = state.config.separator
@@ -1144,14 +1329,15 @@ hook.unhook()
}
}
-} from './lsp/diagnosticsProvider'
+ }
import './lib/env'
-} from './lsp/diagnosticsProvider'
+ }
import {
- ColorPresentation,
+} from 'tailwindcss-language-service/src/completionProvider'
import './lib/env'
state.dependencies = getModuleDependencies(state.configPath)
-} from './lsp/diagnosticsProvider'
+ // chokidarWatcher?.add(state.dependencies)
+ }
CompletionList,
state.configId = getConfigId(state.configPath, state.dependencies)
@@ -1167,141 +1353,173 @@ state.screens = isObject(screens) ? Object.keys(screens) : []
state.enabled = true
-import { doCodeActions } from 'tailwindcss-language-service/src/codeActions/codeActionProvider'
+ InitializeResult,
CompletionItem,
+ CompletionParams,
+ refreshDiagnostics()
updateCapabilities()
}
return {
+ enabled() {
+ }
createConnection,
- CompletionParams,
+import {
createConnection,
Connection,
- dispose() {
-import { doCodeActions } from 'tailwindcss-language-service/src/codeActions/codeActionProvider'
+ }
DocumentColorParams,
- dispose()
- ColorInformation,
+ }
ColorInformation,
},
createConnection,
+ CompletionParams,
import './lib/env'
+import { TextDocument } from 'vscode-languageserver-textdocument'
- createConnection,
import './lib/env'
+import { TextDocument } from 'vscode-languageserver-textdocument'
import './lib/env'
+ },
createConnection,
+ Connection,
import './lib/env'
+import { TextDocument } from 'vscode-languageserver-textdocument'
import {
- createConnection,
import './lib/env'
+import { TextDocument } from 'vscode-languageserver-textdocument'
CompletionItem,
- createConnection,
import './lib/env'
+import { TextDocument } from 'vscode-languageserver-textdocument'
CompletionList,
- createConnection,
import './lib/env'
+import { TextDocument } from 'vscode-languageserver-textdocument'
CompletionParams,
+ }
+ FileChangeType,
Connection,
- CodeActionParams,
import { getDocumentColors } from 'tailwindcss-language-service/src/documentColorProvider'
+ for (let i = 0; i < path.length - 1; i++) {
Connection,
- createConnection,
import './lib/env'
+import { TextDocument } from 'vscode-languageserver-textdocument'
createConnection,
- }
+ }
- createConnection,
import './lib/env'
+import { TextDocument } from 'vscode-languageserver-textdocument'
DocumentColorParams,
- createConnection,
import './lib/env'
+import { TextDocument } from 'vscode-languageserver-textdocument'
ColorInformation,
- TextDocumentIdentifier,
+ FeatureFlags,
DocumentColorParams,
- connection.sendNotification('@/tailwindCSS/clearColors')
- FileChangeType,
+ InitializeResult,
CompletionParams,
}
},
onFileEvents,
async onHover(params: TextDocumentPositionParams): Promise<Hover> {
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+import './lib/env'
CompletionItem,
+import { dset } from 'dset'
- createConnection,
+ obj = obj[path[i]]
import {
+ let document = documentService.getDocument(params.textDocument.uri)
+ obj = obj[path[i]]
CompletionList,
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+ obj = obj[path[i]]
CompletionParams,
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+ obj = obj[path[i]]
Connection,
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+ obj = obj[path[i]]
createConnection,
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+ obj = obj[path[i]]
DocumentColorParams,
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+ obj = obj[path[i]]
ColorInformation,
},
async onCompletion(params: CompletionParams): Promise<CompletionList> {
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+import './lib/env'
CompletionItem,
+import { dset } from 'dset'
- createConnection,
+ obj = obj[path[i]]
import {
+ let document = documentService.getDocument(params.textDocument.uri)
+ obj = obj[path[i]]
CompletionList,
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+ obj = obj[path[i]]
CompletionParams,
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+ InitializeResult,
Connection,
+ obj = obj[path[i]]
createConnection,
+import './lib/env'
CompletionItem,
+ Connection,
import './lib/env'
- if (await isExcluded(state, document)) return null
- createConnection,
+import './lib/env'
CompletionItem,
+ Connection,
import {
- createConnection,
+import './lib/env'
CompletionItem,
+ Connection,
CompletionItem,
- createConnection,
+import './lib/env'
CompletionItem,
+ Connection,
CompletionList,
- createConnection,
+import './lib/env'
CompletionItem,
+ Connection,
CompletionParams,
- createConnection,
+import './lib/env'
import { formatError, showError, SilentError } from './util/error'
+ Connection,
- createConnection,
+import './lib/env'
CompletionItem,
+ Connection,
createConnection,
- createConnection,
+import './lib/env'
CompletionItem,
+ Connection,
DocumentColorParams,
+import {
createConnection,
-import * as path from 'path'
+ CompletionParams,
- ColorInformation,
+ obj = obj[path[i]]
ColorInformation,
},
onCompletionResolve(item: CompletionItem): Promise<CompletionItem> {
- createConnection,
+ return withFallback(() => {
+ obj = obj[path[i]]
import {
+import './lib/env'
CompletionItem,
createConnection,
- CompletionList,
import './lib/env'
+ delete require.cache[key]
},
async onCodeAction(params: CodeActionParams): Promise<CodeAction[]> {
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+import './lib/env'
CompletionItem,
+import { dset } from 'dset'
- createConnection,
+ obj = obj[path[i]]
import {
+ let document = documentService.getDocument(params.textDocument.uri)
+ obj = obj[path[i]]
CompletionList,
-import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+ obj = obj[path[i]]
CompletionParams,
+ InitializeResult,
createConnection,
- DidChangeWatchedFilesNotification,
+import './lib/env'
+ InitializeResult,
createConnection,
- CompletionList,
+import {
+import './lib/env'
CompletionItem,
- return doCodeActions(state, params)
+} from 'tailwindcss-language-service/src/completionProvider'
},
onDocumentLinks(params: DocumentLinkParams): DocumentLink[] {
if (!state.enabled) return null
@@ -1313,23 +1530,35 @@ provideDiagnostics: debounce((document: TextDocument) => {
if (!state.enabled) return
provideDiagnostics(state, document)
}, 500),
+ provideDiagnosticsForce: (document: TextDocument) => {
+ if (!state.enabled) return
import assert from 'assert'
import {
+// import postcssLoadConfig from 'postcss-load-config'
import assert from 'assert'
+import {
+import './lib/env'
CompletionItem,
+import { dset } from 'dset'
+ InitializeResult,
createConnection,
-import {
CompletionList,
+ let document = documentService.getDocument(params.textDocument.uri)
+ InitializeResult,
import assert from 'assert'
- CompletionList,
+ obj = obj[path[i]]
createConnection,
- Disposable,
+ InitializeResult,
createConnection,
- CompletionParams,
+ Connection,
+ InitializeResult,
CompletionParams,
+ ColorInformation,
},
async onColorPresentation(params: ColorPresentationParams): Promise<ColorPresentation[]> {
import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
+ CompletionList,
+import assert from 'assert'
CompletionList,
let className = document.getText(params.range)
let match = className.match(
@@ -1506,30 +1734,39 @@
for (let fn of fns) {
let definition: string
let container = root.clone()
+ let returnValue = withoutLogs(() =>
+ return
DocumentColorParams,
+ container,
+ InitializeResult,
DocumentColorParams,
+import './lib/env'
CompletionItem,
+import namedColors from 'color-name'
+ InitializeResult,
DocumentColorParams,
+import {
+ InitializeResult,
DocumentColorParams,
- CompletionList,
+ CompletionItem,
+ InitializeResult,
DocumentColorParams,
+ CompletionList,
+ InitializeResult,
import { equal } from 'tailwindcss-language-service/src/util/array'
- DocumentColorParams,
+ InitializeResult,
import preflight from 'tailwindcss/lib/css/preflight.css'
- DocumentColorParams,
+ InitializeResult,
import merge from 'deepmerge'
- definition = def.replace(/:merge\(([^)]+)\)/g, '$1')
+ InitializeResult,
- ColorInformation,
+ InitializeResult,
DocumentColorParams,
-global.__preflight = preflight
+ CompletionList,
-// @ts-ignore
+import { doHover } from 'tailwindcss-language-service/src/hoverProvider'
import './lib/env'
-// @ts-ignore
+import { doHover } from 'tailwindcss-language-service/src/hoverProvider'
import {
- }
- },
- })
if (!definition) {
definition = returnValue
@@ -1670,16 +1907,82 @@ // return []
// }
}
+ delete obj[path.pop()]
ColorInformation,
+ let css = getTextWithoutComments(await fs.promises.readFile(cssFile, 'utf8'), 'css')
+ let match = css.match(/@config\s*(?<config>'[^']+'|"[^"]+")/)
+ if (!match) {
+ return null
+ }
+ return path.resolve(path.dirname(cssFile), match.groups.config.slice(1, -1))
+}
+
+function getPackageRoot(cwd: string, rootDir: string) {
+ try {
+ let pkgJsonPath = findUp.sync(
+ (dir) => {
+ let pkgJson = path.join(dir, 'package.json')
+ if (findUp.sync.exists(pkgJson)) {
+ return pkgJson
+import {
import assert from 'assert'
+ if (dir === rootDir) {
+ return findUp.stop
+ }
+ },
+ { cwd }
+ )
+ return pkgJsonPath ? path.dirname(pkgJsonPath) : rootDir
+ } catch {
+ return rootDir
+ }
+ InitializeResult,
ColorInformation,
+
+function getContentDocumentSelectorFromConfigFile(
+ configPath: string,
+function getConfigId(configPath: string, configDependencies: string[]): string {
createConnection,
+ rootDir: string,
+ actualConfig?: any
+): DocumentSelector[] {
+ let config = actualConfig ?? require(configPath)
+ let contentConfig: unknown = config.content?.files ?? config.content
+ let content = Array.isArray(contentConfig) ? contentConfig : []
+ let relativeEnabled = semver.gte(tailwindVersion, '3.2.0')
+ ? config.future?.relativeContentPathsByDefault || config.content?.relative
+ return JSON.stringify(
Connection,
+ let contentBase: string
+ if (relativeEnabled) {
+ contentBase = path.dirname(configPath)
+ } else {
+ contentBase = getPackageRoot(path.dirname(configPath), rootDir)
+ }
+ return content
+ .filter((item): item is string => typeof item === 'string')
+ .map((item) =>
+ item.startsWith('!')
+ ? `!${path.resolve(contentBase, item.slice(1))}`
+ : path.resolve(contentBase, item)
+ )
+ .map((item) => ({
+ pattern: normalizePath(item),
+ priority: DocumentSelectorPriority.CONTENT_FILE,
+ }))
+}
+
+class TW {
+ private initialized = false
+ private lspHandlersAdded = false
private workspaces: Map<string, { name: string; workspaceFsPath: string }>
private projects: Map<string, ProjectService>
private documentService: DocumentService
public initializeParams: InitializeParams
private registrations: Promise<BulkUnregistration>
+ private disposables: Disposable[] = []
+ private watchPatterns: (patterns: string[]) => void
+ private watched: string[] = []
constructor(private connection: Connection) {
this.documentService = new DocumentService(this.connection)
@@ -1690,215 +1993,635 @@
async init(): Promise<void> {
if (this.initialized) return
+ clearRequireCache()
+
this.initialized = true
- ColorInformation,
+ if (!this.initializeParams.rootPath) {
+ console.error('No workspace folders found, not initializing.')
+ return
+ }
DocumentColorParams,
- ColorInformation,
+ DocumentColorParams,
- ColorInformation,
+ let workspaceFolders: Array<ProjectConfig> = []
+ let globalSettings = await getConfiguration()
+ let ignore = globalSettings.tailwindCSS.files.exclude
+ )
ColorInformation,
+
+function first<T>(...options: Array<() => T>): T {
- }
+function first<T>(...options: Array<() => T>): T {
import './lib/env'
- }
+function first<T>(...options: Array<() => T>): T {
import {
- ColorInformation,
+
+ if (configFileOrFiles) {
+ if (
+ return oldReadFileSync(filename, ...args)
ColorInformation,
+ (!isObject(configFileOrFiles) ||
+ !Object.entries(configFileOrFiles).every(([key, value]) => {
+ if (typeof key !== 'string') return false
+ }
CompletionItem,
- }
+ }
CompletionList,
- }
+ }
+ }
CompletionParams,
}))
- : this.initializeParams.rootPath
+ ) {
+ console.error('Invalid `experimental.configFile` configuration, not initializing.')
+ return
}
+ DocumentColorParams,
DocumentColorParams,
- : []
+ let configFiles =
+ typeof configFileOrFiles === 'string' ? { [configFileOrFiles]: '**' } : configFileOrFiles
ColorPresentation,
+ CodeAction,
+import './lib/env'
+import {
+ return {
ColorPresentation,
+ DocumentColorRequest,
+import './lib/env'
+ BulkRegistration,
import './lib/env'
+ resolveConfigFn = (config) => resolveConfig([config, defaultConfig])
import './lib/env'
+ } catch (_) {
+ pattern: path.resolve(base, selector),
+ })),
+ isUserConfigured: true,
+ }
+ }
import glob from 'fast-glob'
+ Connection,
import './lib/env'
+import * as semver from 'tailwindcss-language-service/src/util/semver'
import './lib/env'
+ ))
import './lib/env'
+ const defaultConfig = require(resolveFrom(tailwindDir, './defaultConfig.js'))
+ for (let i = 0; i < options.length; i++) {
+ ignore: (await getConfiguration()).tailwindCSS.files.exclude,
+ for (let i = 0; i < options.length; i++) {
import {
import './lib/env'
+import resolveFrom, { setPnpApi } from './util/resolveFrom'
CompletionItem,
import './lib/env'
+import resolveFrom, { setPnpApi } from './util/resolveFrom'
CompletionList,
import './lib/env'
+import resolveFrom, { setPnpApi } from './util/resolveFrom'
CompletionParams,
import './lib/env'
+import resolveFrom, { setPnpApi } from './util/resolveFrom'
Connection,
+ })
import './lib/env'
+import resolveFrom, { setPnpApi } from './util/resolveFrom'
createConnection,
import './lib/env'
+ require(resolveFrom(tailwindDir, './lib/lib/substituteClassApplyAtRules'))
+ let isCssFile = minimatch(normalizedFilename, `**/${CSS_GLOB}`, { dot: true })
+ let option = options[i]
+ if (!configPath) {
+import {
DocumentColorParams,
+ Connection,
+ }
+import './lib/env'
CompletionList,
+ Connection,
import {
+import './lib/env'
CompletionList,
+ ClassNames,
+ try {
import './lib/env'
- ColorInformation,
+ let tailwindDirectives = new Set()
import './lib/env'
+ let root = postcss.root()
import './lib/env'
+ let result = { opts: {}, messages: [] }
import './lib/env'
+ let registerDependency = () => {}
+ }
import './lib/env'
+ let createContext = first(
+
import './lib/env'
+ () => {
+ continue
+ }
+
import './lib/env'
+import Module from 'module'
+
+ if (i === options.length - 1) {
import './lib/env'
import {
+ doComplete,
import './lib/env'
+ 'tailwindcss/lib/lib/setupContextUtils'
import './lib/env'
+ let createContext = first(
+
+ if (i === options.length - 1) {
CompletionItem,
import './lib/env'
+ assert.strictEqual(typeof createContextFn, 'function')
+ pattern: normalizePath(filename),
+ priority: isCssFile
+ ? DocumentSelectorPriority.CSS_FILE
+ : DocumentSelectorPriority.CONFIG_FILE,
+ },
+ ...(isCssFile
+ return option()
TextDocumentPositionParams,
+import namedColors from 'color-name'
+ pattern: normalizePath(configPath),
+ priority: DocumentSelectorPriority.CONFIG_FILE,
+ },
+ ]
+ return option()
CompletionParams,
+ return option()
Connection,
+ if (i === options.length - 1) {
CompletionList,
import './lib/env'
+ )(result, root)
+ priority: isCssFile
+ ? DocumentSelectorPriority.CSS_DIRECTORY
+ : DocumentSelectorPriority.CONFIG_DIRECTORY,
+ },
+ ...(isCssFile
+ return option()
import './lib/env'
- CompletionParams,
+ assert.strictEqual(typeof setupTrackingContext, 'function')
+ pattern: normalizePath(path.join(path.dirname(configPath), '**')),
+ priority: DocumentSelectorPriority.CONFIG_DIRECTORY,
+
ColorInformation,
+ ]
+ : []),
+ {
+ TextDocumentPositionParams,
ColorInformation,
- Connection,
+import {
+import './lib/env'
CompletionList,
+ ColorInformation,
CompletionItem,
+ },
import './lib/env'
+ module: first(
+
import './lib/env'
+ () =>
+
import './lib/env'
+import * as semver from 'tailwindcss-language-service/src/util/semver'
Connection,
+import './lib/env'
CompletionList,
- CompletionItem,
+ if (filename === require('path').join(__dirname, 'css/preflight.css')) {
import {
+import assert from 'assert'
}
import './lib/env'
+ .generateRules
+ workspaceFolders = Object.entries(projects).map(([configPath, documentSelector]) => {
+ return {
+ folder: base,
+ configPath,
+ TextDocuments,
import './lib/env'
+ documentSelector: documentSelector
+ .sort((a, z) => a.priority - z.priority)
+ .filter(
+ ({ pattern }, index, documentSelectors) =>
+ documentSelectors.findIndex(({ pattern: p }) => p === pattern) === index
+ try {
createConnection,
+ }
+ })
+ }
}
- DocumentColorParams,
import './lib/env'
+ CompletionParams,
+ DocumentColorParams,
+
import './lib/env'
+import dlv from 'dlv'
ColorInformation,
import './lib/env'
+import { dset } from 'dset'
+ ): Promise<void> => {
+ return option()
import {
+
+ changeLoop: for (let change of changes) {
- ColorInformation,
+import './lib/env'
CompletionParams,
+import './lib/env'
CompletionList,
+
+ TextDocuments,
import './lib/env'
+ CompletionParams,
+ if (minimatch(normalizedFilename, ignorePattern, { dot: true })) {
+ continue changeLoop
+ }
+ }
+
+ let isPackageFile = minimatch(normalizedFilename, `**/${PACKAGE_LOCK_GLOB}`, { dot: true })
+ if (isPackageFile) {
+ } catch (_) {}
+ TextDocuments,
DocumentColorRequest,
import './lib/env'
+ CompletionParams,
BulkRegistration,
import './lib/env'
+ CompletionParams,
CodeActionRequest,
import './lib/env'
+ CompletionParams,
BulkUnregistration,
import './lib/env'
+ createContext: {
+ 'tailwindcss/package.json'
+ )).version
+ if (typeof v === 'string') {
+ twVersion = v
+ }
+function firstOptional<T>(...options: Array<() => T>): T | undefined {
+ if (configTailwindVersionMap.get(projectConfig.configPath) !== twVersion) {
+function firstOptional<T>(...options: Array<() => T>): T | undefined {
import {
+import './lib/env'
CompletionParams,
+} from 'vscode-languageserver/node'
+ }
}
}
+
+ let isCssFile = minimatch(normalizedFilename, `**/${CSS_GLOB}`, {
+ dot: true,
import glob from 'fast-glob'
+ CompletionParams,
+ } else {
Connection,
import './lib/env'
+ tailwindcss: { version: tailwindcssVersion, module: tailwindcss },
import './lib/env'
+ postcss: { version: postcssVersion, module: postcss },
- DocumentColorParams,
+ cssFileConfigMap.has(normalizedFilename) &&
+function firstOptional<T>(...options: Array<() => T>): T | undefined {
DocumentColorParams,
import './lib/env'
+ jit: jitModules,
+ try {
+ break
+ try {
import {
- Connection,
import './lib/env'
+import extractClassNames from './lib/extractClassNames'
+ break
+ }
FileChangeType,
+ CompletionParams,
+
+ let isConfigFile = minimatch(normalizedFilename, `**/${CONFIG_GLOB}`, {
+ dot: true,
+ })
+ if (isConfigFile && change.type === FileChangeType.Created) {
+ needsRestart = true
import {
+ if (filename === require('path').join(__dirname, 'css/preflight.css')) {
+ }
+
+ for (let [key] of this.projects) {
+ let projectConfig = JSON.parse(key) as ProjectConfig
+ TextDocuments,
import { formatError, showError, SilentError } from './util/error'
+ try {
DocumentColorParams,
- DocumentColorParams,
+ changeAffectsFile(normalizedFilename, [projectConfig.configPath])
+ ) {
import './lib/env'
+ state.browserslist = browserslist
+ } catch (_) {}
+ CompletionList,
import {
+import {
+ }
+ }
DocumentColorParams,
+ DocumentColorParams,
+ if (needsRestart) {
+ this.restart()
+ return
+ }
+
+ for (let [, project] of this.projects) {
+ project.onFileEvents(changes)
+ }
+ }
if (this.initializeParams.capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration) {
import './lib/env'
+ return async (css) => {
+ this.connection.onDidChangeWatchedFiles(async ({ changes }) => {
+ let normalizedChanges = changes
+ .map(({ uri, type }) => ({
+import './lib/env'
CompletionItem,
+ CompletionList,
+import './lib/env'
+import { URI } from 'vscode-uri'
const CONFIG_FILE_GLOB = '{tailwind,tailwind.config}.{js,cjs}'
+ Connection,
import './lib/env'
+ rule.before(
import './lib/env'
+ postcss.comment({
+interface ProjectService {
+ changeIndex
+import { equal } from 'tailwindcss-language-service/src/util/array'
CompletionItem,
+
+interface ProjectService {
import {
+ })
+ )
+
+ let disposable = await this.connection.client.register(
+ DidChangeWatchedFilesNotification.type,
+ {
import './lib/env'
+ await fn(css)
+ { globPattern: `**/${CONFIG_GLOB}` },
+ { globPattern: `**/${PACKAGE_LOCK_GLOB}` },
+ { globPattern: `**/${CSS_GLOB}` },
+ state: State
+ }
CompletionItem,
+// import postcssLoadConfig from 'postcss-load-config'
+
+ this.disposables.push(disposable)
+
+ this.watchPatterns = (patterns) => {
+ state: State
CompletionItem,
import './lib/env'
+ // try {
+ console.log(`[Global] Adding watch patterns: ${newPatterns.join(', ')}`)
+ this.connection.client
+ .register(DidChangeWatchedFilesNotification.type, {
+ watchers: newPatterns.map((pattern) => ({ globPattern: pattern })),
+ FileChangeType,
+ .then((disposable) => {
+ this.disposables.push(disposable)
+ })
+ }
+ }
+ } else if (parcel.getBinding()) {
+ let typeMap = {
+ tryInit: () => Promise<void>
CompletionItem,
+ tryInit: () => Promise<void>
CompletionList,
import './lib/env'
+ // state.postcssPlugins = {
+ }
+
+ let subscription = await parcel.subscribe(
+ base,
+ (err, events) => {
+ onDidChangeWatchedFiles(
+ dispose: () => void
+ )
+import {
CompletionItem,
+import {
+interface ProjectService {
CompletionParams,
import './lib/env'
+ // }
+ path.resolve(base, ignorePattern.replace(/^[*/]+/, '').replace(/[*/]+$/, ''))
+ dispose: () => void
CompletionItem,
- Connection,
FileChangeType,
+ CompletionParams,
+ )
+
import './lib/env'
+ const { tailwindcss, postcss, resolveConfig } = state.modules
+ dispose() {
+ subscription.unsubscribe()
+ CodeActionRequest,
import {
+const CONFIG_FILE_GLOB = '{tailwind,tailwind.config}.{js,cjs}'
createConnection,
+ } else {
+import './lib/env'
CompletionParams,
+ if (filename === require('path').join(__dirname, 'css/preflight.css')) {
import './lib/env'
+ let presetVariants: any[] = []
+ [`**/${CONFIG_GLOB}`, `**/${PACKAGE_LOCK_GLOB}`, `**/${CSS_GLOB}`],
+ {
+ cwd: base,
+ ignorePermissionErrors: true,
+ ignoreInitial: true,
+ TextDocumentSyncKind,
CompletionItem,
- createConnection,
import './lib/env'
+ Connection,
+ CompletionList,
import './lib/env'
+ separator = ':'
+ pollInterval: 20,
+ },
+ }
+ )
import './lib/env'
+ Connection,
- CompletionItem,
+ createConnection,
+ onUpdateSettings: (settings: any) => void
DocumentColorParams,
const CONFIG_FILE_GLOB = '{tailwind,tailwind.config}.{js,cjs}'
+ createConnection,
+
+ onUpdateSettings: (settings: any) => void
ColorInformation,
import './lib/env'
+ FeatureFlags,
+ onDidChangeWatchedFiles([
+ { file: path.resolve(base, file), type: FileChangeType.Created },
+ ])
CompletionList,
+} from 'tailwindcss-language-service/src/completionProvider'
+ .on('change', (file) =>
+ onDidChangeWatchedFiles([
+ { file: path.resolve(base, file), type: FileChangeType.Changed },
+ ])
+import resolveFrom, { setPnpApi } from './util/resolveFrom'
ColorInformation,
+ .on('unlink', (file) =>
+ onDidChangeWatchedFiles([
+ { file: path.resolve(base, file), type: FileChangeType.Deleted },
+ ])
+import resolveFrom, { setPnpApi } from './util/resolveFrom'
ColorInformation,
+
+ this.disposables.push({
+ dispose() {
+ chokidarWatcher.close()
+import {
CompletionItem,
+import {
+import './lib/env'
+import glob from 'fast-glob'
+
+ this.watchPatterns = (patterns) => {
+ let newPatterns = this.filterNewWatchPatterns(patterns)
+ if (newPatterns.length) {
+ console.log(`[Global] Adding watch patterns: ${newPatterns.join(', ')}`)
+ chokidarWatcher.add(newPatterns)
+ }
+ ColorInformation,
ColorInformation,
+ }
ColorPresentation,
- CompletionList,
+ DidChangeWatchedFilesNotification,
import './lib/env'
+ state.jit = false
import './lib/env'
+ Settings,
+ projectConfig,
+ this.initializeParams,
+ this.watchPatterns,
+ onHover(params: TextDocumentPositionParams): Promise<Hover>
CompletionList,
+ )
+ )
import {
+import { formatError, showError, SilentError } from './util/error'
+
+ // init projects for documents that are _already_ open
+ for (let document of this.documentService.getAllDocuments()) {
+ let project = this.getProject(document)
+ if (project && !project.enabled()) {
+ project.enable()
+ TextDocumentSyncKind,
DocumentLinkRequest,
+ ColorInformation,
ColorInformation,
+ }
ColorPresentation,
- CompletionList,
+ Disposable,
+
+ TextDocumentSyncKind,
CompletionItem,
+import './lib/env'
import './lib/env'
- CompletionList,
+ if (!args[0].matchUtilities) {
+ let previousExclude = globalSettings.tailwindCSS.files.exclude
+
+ onCompletion(params: CompletionParams): Promise<CompletionList>
CompletionList,
+ TextDocumentSyncKind,
CompletionItem,
+ CompletionParams,
+
+ if (!equal(previousExclude, globalSettings.tailwindCSS.files.exclude)) {
+ this.restart()
+ return
+ }
+
+import './lib/env'
+ DocumentLinkParams,
+ onCompletion(params: CompletionParams): Promise<CompletionList>
ColorInformation,
+ }
import './lib/env'
CompletionItem,
+ createConnection,
+import {
CompletionItem,
+ Connection,
import './lib/env'
+ let newPlugin = (...args) => {
+ onCompletionResolve(item: CompletionItem): Promise<CompletionItem>
+ TextDocumentSyncKind,
CompletionList,
- CompletionParams,
+import './lib/env'
ColorPresentation,
+import glob from 'fast-glob'
+ )
+
+ this.disposables.push(
+ TextDocumentSyncKind,
CompletionList,
+import {
+import './lib/env'
Connection,
+import findUp from 'find-up'
ColorPresentation,
+import glob from 'fast-glob'
+ )
+
+ this.disposables.push(
+ this.documentService.onDidOpen((event) => {
+ let project = this.getProject(event.document)
+ if (project && !project.enabled()) {
+ TextDocumentSyncKind,
import Module from 'module'
import './lib/env'
+ __intellisense_cache_bust: Math.random(),
+ }
+import './lib/env'
+import glob from 'fast-glob'
+ )
+ }
+
+ TextDocumentSyncKind,
CompletionList,
+ ColorInformation,
+ let newWatchPatterns = patterns.filter((pattern) => !this.watched.includes(pattern))
+ this.watched.push(...newWatchPatterns)
+ return newWatchPatterns
+ }
+ DocumentColorParams,
DocumentColorParams,
import './lib/env'
+ throw error
+ provideDiagnostics(document: TextDocument): void
CompletionList,
+ params: InitializeParams,
+ watchPatterns: (patterns: string[]) => void,
+ tailwindVersion: string
+ ): Promise<void> {
+ let key = JSON.stringify(projectConfig)
+
+ provideDiagnostics(document: TextDocument): void
ColorInformation,
const project = await createProjectService(
projectConfig,
@@ -1886,18 +2625,49 @@ this.connection,
params,
this.documentService,
import './lib/env'
+ provideDiagnostics,
+ () => {
+ for (let document of this.documentService.getAllDocuments()) {
+ let project = this.getProject(document)
+ if (project && !project.enabled()) {
+ onDocumentColor(params: DocumentColorParams): Promise<ColorInformation[]>
CompletionParams,
+ project.tryInit()
+ break
+import { doHover } from 'tailwindcss-language-service/src/hoverProvider'
CompletionList,
+ }
+ },
+ () => this.refreshDiagnostics(),
+ (patterns: string[]) => watchPatterns(patterns),
+ tailwindVersion
)
this.projects.set(key, project)
ColorPresentation,
+import './lib/env'
+ }
+
+ private refreshDiagnostics() {
+ for (let doc of this.documentService.getAllDocuments()) {
+ let project = this.getProject(doc)
+ if (project) {
+ onColorPresentation(params: ColorPresentationParams): Promise<ColorPresentation[]>
CompletionParams,
Connection,
+ CodeActionParams,
+ this.connection.sendDiagnostics({ uri: doc.uri, diagnostics: [] })
+ }
}
}
private setupLSPHandlers() {
import './lib/env'
+ .process(
+ return
+ }
+ this.lspHandlersAdded = true
+
+import './lib/env'
resolveCompletionItem,
this.connection.onCompletion(this.onCompletion.bind(this))
this.connection.onCompletionResolve(this.onCompletionResolve.bind(this))
@@ -1934,41 +2703,72 @@ ].filter(Boolean),
})
"'",
- CompletionList,
+ DocumentColorParams,
+ }
+
"'",
- CompletionParams,
+ ColorInformation,
ColorPresentation,
- DocumentColorParams,
+global.__preflight = preflight
+import './lib/env'
Connection,
+import { getColor } from 'tailwindcss-language-service/src/util/color'
import './lib/env'
+ clearAllDiagnostics,
DocumentColorParams,
- createConnection,
+ DocumentColorParams,
- CompletionItem,
+import './lib/env'
ColorInformation,
+import './lib/env'
-
+ let projectConfig = JSON.parse(key) as ProjectConfig
ColorPresentation,
+ '__dirname',
+ TextDocumentSyncKind,
DocumentColorParams,
+import './lib/env'
+ TextDocumentSyncKind,
DocumentColorParams,
+import {
import './lib/env'
- CompletionItem,
+ clearAllDiagnostics,
CompletionItem,
+ TextDocumentSyncKind,
DocumentColorParams,
+ CompletionList,
+ TextDocumentSyncKind,
DocumentColorParams,
+ CompletionParams,
import './lib/env'
+ from: undefined,
+ return -1
+ }
+ if (!a.pattern.startsWith('!') && z.pattern.startsWith('!')) {
+ TextDocumentSyncKind,
// @ts-ignore
+ }
import './lib/env'
+ Connection,
global.__preflight = preflight
+ })
import './lib/env'
+ Connection,
new Function(
import './lib/env'
+ Connection,
'require',
import './lib/env'
+ Connection,
'__dirname',
import './lib/env'
+ state.featureFlags = featureFlags
+ }
+ TextDocumentSyncKind,
`
import './lib/env'
+ Connection,
let oldReadFileSync = require('fs').readFileSync
import './lib/env'
+ Connection,
require('fs').readFileSync = function (filename, ...args) {
}
}
@@ -1970,6 +2777,11 @@ fallbackProject = project
}
}
}
+
+ if (matchedProject) {
+ return matchedProject
+ }
+
return fallbackProject
}
@@ -2009,6 +2821,26 @@ dispose(): void {
for (let [, project] of this.projects) {
project.dispose()
}
+ this.projects = new Map()
+
+ this.refreshDiagnostics()
+
+ if (this.registrations) {
+ this.registrations.then((r) => r.dispose())
+ this.registrations = undefined
+ }
+
+ this.disposables.forEach((d) => d.dispose())
+ this.disposables.length = 0
+
+ this.watched.length = 0
+ }
+
+ restart(): void {
+ console.log('----------\nRESTARTING\n----------')
+ this.dispose()
+ this.initialized = false
+ this.init()
}
}
@@ -2033,6 +2865,9 @@ return this.documents.onDidChangeContent
}
get onDidClose() {
return this.documents.onDidClose
+ }
+ get onDidOpen() {
+ return this.documents.onDidOpen
}
}