Add `files.exclude` setting

master
Brad Cornes 2022-01-07 17:13:11 +00:00
parent 6fdef8616a
commit ff52e815b6
8 changed files with 132 additions and 32 deletions

View File

@ -1,12 +1,17 @@
import { TextDocument } from 'vscode-languageserver/node' import { TextDocument } from 'vscode-languageserver/node'
import { State } from 'tailwindcss-language-service/src/util/state' import { State } from 'tailwindcss-language-service/src/util/state'
import { doValidate } from 'tailwindcss-language-service/src/diagnostics/diagnosticsProvider' import { doValidate } from 'tailwindcss-language-service/src/diagnostics/diagnosticsProvider'
import isExcluded from '../util/isExcluded'
export async function provideDiagnostics(state: State, document: TextDocument) { export async function provideDiagnostics(state: State, document: TextDocument) {
state.editor?.connection.sendDiagnostics({ if (await isExcluded(state, document)) {
uri: document.uri, clearDiagnostics(state, document)
diagnostics: await doValidate(state, document), } else {
}) state.editor?.connection.sendDiagnostics({
uri: document.uri,
diagnostics: await doValidate(state, document),
})
}
} }
export function clearDiagnostics(state: State, document: TextDocument): void { export function clearDiagnostics(state: State, document: TextDocument): void {

View File

@ -78,6 +78,9 @@ import * as culori from 'culori'
import namedColors from 'color-name' import namedColors from 'color-name'
import preflight from './lib/preflight' import preflight from './lib/preflight'
import tailwindPlugins from './lib/plugins' import tailwindPlugins from './lib/plugins'
import isExcluded from './util/isExcluded'
import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri'
import { equal } from 'tailwindcss-language-service/src/util/array'
let oldReadFileSync = fs.readFileSync let oldReadFileSync = fs.readFileSync
// @ts-ignore // @ts-ignore
@ -121,14 +124,6 @@ process.on('unhandledRejection', (e: any) => {
connection.console.error(formatError(`Unhandled exception`, e)) connection.console.error(formatError(`Unhandled exception`, e))
}) })
function normalizeFileNameToFsPath(fileName: string) {
return URI.file(fileName).fsPath
}
function getFileFsPath(documentUri: string): string {
return URI.parse(documentUri).fsPath
}
function deletePropertyPath(obj: any, path: string | string[]): void { function deletePropertyPath(obj: any, path: string | string[]): void {
if (typeof path === 'string') { if (typeof path === 'string') {
path = path.split('.') path = path.split('.')
@ -220,6 +215,7 @@ async function createProjectService(
enabled: false, enabled: false,
editor: { editor: {
connection, connection,
folder,
globalSettings: params.initializationOptions.configuration as Settings, globalSettings: params.initializationOptions.configuration as Settings,
userLanguages: params.initializationOptions.userLanguages userLanguages: params.initializationOptions.userLanguages
? params.initializationOptions.userLanguages ? params.initializationOptions.userLanguages
@ -258,12 +254,7 @@ async function createProjectService(
let registrations: Promise<BulkUnregistration> let registrations: Promise<BulkUnregistration>
let chokidarWatcher: chokidar.FSWatcher let chokidarWatcher: chokidar.FSWatcher
let ignore = [ let ignore = state.editor.globalSettings.tailwindCSS.files.exclude
'**/.git/objects/**',
'**/.git/subtree-cache/**',
'**/node_modules/**',
'**/.hg/store/**',
]
function onFileEvents(changes: Array<{ file: string; type: FileChangeType }>): void { function onFileEvents(changes: Array<{ file: string; type: FileChangeType }>): void {
let needsInit = false let needsInit = false
@ -456,7 +447,7 @@ async function createProjectService(
let [configPath] = ( let [configPath] = (
await glob([`**/${CONFIG_FILE_GLOB}`], { await glob([`**/${CONFIG_FILE_GLOB}`], {
cwd: folder, cwd: folder,
ignore: ['**/node_modules'], ignore: state.editor.globalSettings.tailwindCSS.files.exclude,
onlyFiles: true, onlyFiles: true,
absolute: true, absolute: true,
suppressErrors: true, suppressErrors: true,
@ -989,25 +980,33 @@ async function createProjectService(
}, },
onUpdateSettings(settings: any): void { onUpdateSettings(settings: any): void {
documentSettingsCache.clear() documentSettingsCache.clear()
if (state.enabled) { let previousExclude = state.editor.globalSettings.tailwindCSS.files.exclude
updateAllDiagnostics(state) state.editor.globalSettings = settings
} if (!equal(previousExclude, settings.tailwindCSS.files.exclude)) {
if (settings.editor.colorDecorators) { tryInit()
registerCapabilities(state.dependencies)
} else { } else {
connection.sendNotification('@/tailwindCSS/clearColors') if (state.enabled) {
updateAllDiagnostics(state)
}
if (settings.editor.colorDecorators) {
registerCapabilities(state.dependencies)
} else {
connection.sendNotification('@/tailwindCSS/clearColors')
}
} }
}, },
onHover(params: TextDocumentPositionParams): Promise<Hover> { async onHover(params: TextDocumentPositionParams): Promise<Hover> {
if (!state.enabled) return null if (!state.enabled) return null
let document = documentService.getDocument(params.textDocument.uri) let document = documentService.getDocument(params.textDocument.uri)
if (!document) return null if (!document) return null
if (await isExcluded(state, document)) return null
return doHover(state, document, params.position) return doHover(state, document, params.position)
}, },
onCompletion(params: CompletionParams): Promise<CompletionList> { async onCompletion(params: CompletionParams): Promise<CompletionList> {
if (!state.enabled) return null if (!state.enabled) return null
let document = documentService.getDocument(params.textDocument.uri) let document = documentService.getDocument(params.textDocument.uri)
if (!document) return null if (!document) return null
if (await isExcluded(state, document)) return null
return doComplete(state, document, params.position, params.context) return doComplete(state, document, params.position, params.context)
}, },
onCompletionResolve(item: CompletionItem): Promise<CompletionItem> { onCompletionResolve(item: CompletionItem): Promise<CompletionItem> {
@ -1026,6 +1025,7 @@ async function createProjectService(
if (!state.enabled) return [] if (!state.enabled) return []
let document = documentService.getDocument(params.textDocument.uri) let document = documentService.getDocument(params.textDocument.uri)
if (!document) return [] if (!document) return []
if (await isExcluded(state, document)) return null
return getDocumentColors(state, document) return getDocumentColors(state, document)
}, },
async onColorPresentation(params: ColorPresentationParams): Promise<ColorPresentation[]> { async onColorPresentation(params: ColorPresentationParams): Promise<ColorPresentation[]> {

View File

@ -0,0 +1,18 @@
import minimatch from 'minimatch'
import * as path from 'path'
import { State } from 'tailwindcss-language-service/src/util/state'
import { TextDocument } from 'vscode-languageserver-textdocument'
import { getFileFsPath } from './uri'
export default async function isExcluded(state: State, document: TextDocument): Promise<boolean> {
let settings = await state.editor.getConfiguration(document.uri)
let file = getFileFsPath(document.uri)
for (let pattern of settings.tailwindCSS.files.exclude) {
if (minimatch(file, path.join(state.editor.folder, pattern))) {
return true
}
}
return false
}

View File

@ -0,0 +1,9 @@
import { URI } from 'vscode-uri'
export function normalizeFileNameToFsPath(fileName: string) {
return URI.file(fileName).fsPath
}
export function getFileFsPath(documentUri: string): string {
return URI.parse(documentUri).fsPath
}

View File

@ -19,6 +19,7 @@ export type ClassNames = {
export type EditorState = { export type EditorState = {
connection: Connection connection: Connection
folder: string
documents: TextDocuments<TextDocument> documents: TextDocuments<TextDocument>
globalSettings: Settings globalSettings: Settings
userLanguages: Record<string, string> userLanguages: Record<string, string>
@ -56,6 +57,9 @@ export type Settings = {
experimental: { experimental: {
classRegex: string[] classRegex: string[]
} }
files: {
exclude: string[]
}
} }
} }

View File

@ -62,6 +62,10 @@ This setting allows you to add additional language support. The key of each entr
} }
``` ```
### `tailwindCSS.files.exclude`
Configure glob patterns to exclude from all IntelliSense features. Inherits all glob patterns from the `files.exclude` setting. **Default: ["\*\*/.git/\*\*", "\*\*/node_modules/\*\*", "\*\*/.hg/\*\*"]**
### `tailwindCSS.emmetCompletions` ### `tailwindCSS.emmetCompletions`
Enable completions when using [Emmet](https://emmet.io/)-style syntax, for example `div.bg-red-500.uppercase`. **Default: `false`** Enable completions when using [Emmet](https://emmet.io/)-style syntax, for example `div.bg-red-500.uppercase`. **Default: `false`**

View File

@ -119,6 +119,18 @@
"default": {}, "default": {},
"markdownDescription": "Enable features in languages that are not supported by default. Add a mapping here between the new language and an already supported language.\n E.g.: `{\"plaintext\": \"html\"}`" "markdownDescription": "Enable features in languages that are not supported by default. Add a mapping here between the new language and an already supported language.\n E.g.: `{\"plaintext\": \"html\"}`"
}, },
"tailwindCSS.files.exclude": {
"type": "array",
"items": {
"type": "string"
},
"default": [
"**/.git/**",
"**/node_modules/**",
"**/.hg/**"
],
"markdownDescription": "Configure glob patterns to exclude from all IntelliSense features. Inherits all glob patterns from the `#files.exclude#` setting."
},
"tailwindCSS.classAttributes": { "tailwindCSS.classAttributes": {
"type": "array", "type": "array",
"items": { "items": {

View File

@ -31,6 +31,7 @@ import { languages as defaultLanguages } from 'tailwindcss-language-service/src/
import isObject from 'tailwindcss-language-service/src/util/isObject' import isObject from 'tailwindcss-language-service/src/util/isObject'
import { dedupe, equal } from 'tailwindcss-language-service/src/util/array' import { dedupe, equal } from 'tailwindcss-language-service/src/util/array'
import namedColors from 'color-name' import namedColors from 'color-name'
import minimatch from 'minimatch'
const colorNames = Object.keys(namedColors) const colorNames = Object.keys(namedColors)
@ -82,6 +83,45 @@ function getUserLanguages(folder?: WorkspaceFolder): Record<string, string> {
return isObject(langs) ? langs : {} return isObject(langs) ? langs : {}
} }
function getExcludePatterns(folder: WorkspaceFolder): string[] {
let globalExclude = Workspace.getConfiguration('files', folder).get('exclude')
let exclude = Object.entries(globalExclude)
.filter(([, value]) => value)
.map(([key]) => key)
return [
...exclude,
...(<string[]>Workspace.getConfiguration('tailwindCSS', folder).get('files.exclude')),
]
}
function isExcluded(file: string, folder: WorkspaceFolder): boolean {
let exclude = getExcludePatterns(folder)
for (let pattern of exclude) {
if (minimatch(file, path.join(folder.uri.fsPath, pattern))) {
return true
}
}
return false
}
function mergeExcludes(settings, scope) {
// merge `files.exclude` into `tailwindCSS.files.exclude`
let globalExclude = Object.entries(Workspace.getConfiguration('files', scope).get('exclude'))
.filter(([, value]) => value)
.map(([key]) => key)
return {
...settings,
files: {
...settings.files,
exclude: [...globalExclude, ...settings.files.exclude],
},
}
}
export async function activate(context: ExtensionContext) { export async function activate(context: ExtensionContext) {
let module = context.asAbsolutePath(path.join('dist', 'server', 'index.js')) let module = context.asAbsolutePath(path.join('dist', 'server', 'index.js'))
let prod = path.join('dist', 'server', 'tailwindServer.js') let prod = path.join('dist', 'server', 'tailwindServer.js')
@ -108,8 +148,10 @@ export async function activate(context: ExtensionContext) {
if (!folder) { if (!folder) {
return return
} }
folder = getOuterMostWorkspaceFolder(folder) if (!isExcluded(uri.fsPath, folder)) {
bootWorkspaceClient(folder) folder = getOuterMostWorkspaceFolder(folder)
bootWorkspaceClient(folder)
}
}) })
context.subscriptions.push(watcher) context.subscriptions.push(watcher)
@ -180,7 +222,7 @@ export async function activate(context: ExtensionContext) {
let configuration = { let configuration = {
editor: Workspace.getConfiguration('editor', folder), editor: Workspace.getConfiguration('editor', folder),
tailwindCSS: Workspace.getConfiguration('tailwindCSS', folder), tailwindCSS: mergeExcludes(Workspace.getConfiguration('tailwindCSS', folder), folder),
} }
let inspectPort = configuration.tailwindCSS.get('inspectPort') let inspectPort = configuration.tailwindCSS.get('inspectPort')
@ -309,7 +351,13 @@ export async function activate(context: ExtensionContext) {
} }
} }
} }
return Workspace.getConfiguration(section, scope) let settings = Workspace.getConfiguration(section, scope)
if (section === 'tailwindCSS') {
return mergeExcludes(settings, scope)
}
return settings
}) })
}, },
}, },
@ -375,7 +423,7 @@ export async function activate(context: ExtensionContext) {
let [configFile] = await Workspace.findFiles( let [configFile] = await Workspace.findFiles(
new RelativePattern(folder, `**/${CONFIG_FILE_GLOB}`), new RelativePattern(folder, `**/${CONFIG_FILE_GLOB}`),
'**/node_modules/**', `{${getExcludePatterns(folder).join(',')}}`,
1 1
) )