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 { State } from 'tailwindcss-language-service/src/util/state'
import { doValidate } from 'tailwindcss-language-service/src/diagnostics/diagnosticsProvider'
import isExcluded from '../util/isExcluded'
export async function provideDiagnostics(state: State, document: TextDocument) {
if (await isExcluded(state, document)) {
clearDiagnostics(state, document)
} else {
state.editor?.connection.sendDiagnostics({
uri: document.uri,
diagnostics: await doValidate(state, document),
})
}
}
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 preflight from './lib/preflight'
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
// @ts-ignore
@ -121,14 +124,6 @@ process.on('unhandledRejection', (e: any) => {
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 {
if (typeof path === 'string') {
path = path.split('.')
@ -220,6 +215,7 @@ async function createProjectService(
enabled: false,
editor: {
connection,
folder,
globalSettings: params.initializationOptions.configuration as Settings,
userLanguages: params.initializationOptions.userLanguages
? params.initializationOptions.userLanguages
@ -258,12 +254,7 @@ async function createProjectService(
let registrations: Promise<BulkUnregistration>
let chokidarWatcher: chokidar.FSWatcher
let ignore = [
'**/.git/objects/**',
'**/.git/subtree-cache/**',
'**/node_modules/**',
'**/.hg/store/**',
]
let ignore = state.editor.globalSettings.tailwindCSS.files.exclude
function onFileEvents(changes: Array<{ file: string; type: FileChangeType }>): void {
let needsInit = false
@ -456,7 +447,7 @@ async function createProjectService(
let [configPath] = (
await glob([`**/${CONFIG_FILE_GLOB}`], {
cwd: folder,
ignore: ['**/node_modules'],
ignore: state.editor.globalSettings.tailwindCSS.files.exclude,
onlyFiles: true,
absolute: true,
suppressErrors: true,
@ -989,6 +980,11 @@ async function createProjectService(
},
onUpdateSettings(settings: any): void {
documentSettingsCache.clear()
let previousExclude = state.editor.globalSettings.tailwindCSS.files.exclude
state.editor.globalSettings = settings
if (!equal(previousExclude, settings.tailwindCSS.files.exclude)) {
tryInit()
} else {
if (state.enabled) {
updateAllDiagnostics(state)
}
@ -997,17 +993,20 @@ async function createProjectService(
} else {
connection.sendNotification('@/tailwindCSS/clearColors')
}
}
},
onHover(params: TextDocumentPositionParams): Promise<Hover> {
async onHover(params: TextDocumentPositionParams): Promise<Hover> {
if (!state.enabled) return null
let document = documentService.getDocument(params.textDocument.uri)
if (!document) return null
if (await isExcluded(state, document)) return null
return doHover(state, document, params.position)
},
onCompletion(params: CompletionParams): Promise<CompletionList> {
async onCompletion(params: CompletionParams): Promise<CompletionList> {
if (!state.enabled) return null
let document = documentService.getDocument(params.textDocument.uri)
if (!document) return null
if (await isExcluded(state, document)) return null
return doComplete(state, document, params.position, params.context)
},
onCompletionResolve(item: CompletionItem): Promise<CompletionItem> {
@ -1026,6 +1025,7 @@ async function createProjectService(
if (!state.enabled) return []
let document = documentService.getDocument(params.textDocument.uri)
if (!document) return []
if (await isExcluded(state, document)) return null
return getDocumentColors(state, document)
},
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 = {
connection: Connection
folder: string
documents: TextDocuments<TextDocument>
globalSettings: Settings
userLanguages: Record<string, string>
@ -56,6 +57,9 @@ export type Settings = {
experimental: {
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`
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": {},
"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": {
"type": "array",
"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 { dedupe, equal } from 'tailwindcss-language-service/src/util/array'
import namedColors from 'color-name'
import minimatch from 'minimatch'
const colorNames = Object.keys(namedColors)
@ -82,6 +83,45 @@ function getUserLanguages(folder?: WorkspaceFolder): Record<string, string> {
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) {
let module = context.asAbsolutePath(path.join('dist', 'server', 'index.js'))
let prod = path.join('dist', 'server', 'tailwindServer.js')
@ -108,8 +148,10 @@ export async function activate(context: ExtensionContext) {
if (!folder) {
return
}
if (!isExcluded(uri.fsPath, folder)) {
folder = getOuterMostWorkspaceFolder(folder)
bootWorkspaceClient(folder)
}
})
context.subscriptions.push(watcher)
@ -180,7 +222,7 @@ export async function activate(context: ExtensionContext) {
let configuration = {
editor: Workspace.getConfiguration('editor', folder),
tailwindCSS: Workspace.getConfiguration('tailwindCSS', folder),
tailwindCSS: mergeExcludes(Workspace.getConfiguration('tailwindCSS', folder), folder),
}
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(
new RelativePattern(folder, `**/${CONFIG_FILE_GLOB}`),
'**/node_modules/**',
`{${getExcludePatterns(folder).join(',')}}`,
1
)