update settings schema

master
Brad Cornes 2021-05-04 12:40:50 +01:00
parent e0ef982fd5
commit a72226c141
16 changed files with 103 additions and 172 deletions

View File

@ -313,7 +313,7 @@ async function provideCustomClassNameCompletions(
position: Position
): Promise<CompletionList> {
const settings = await state.editor.getConfiguration(document.uri)
const regexes = dlv(settings, 'experimental.classRegex', [])
const regexes = dlv(settings, 'tailwindCSS.experimental.classRegex', [])
if (regexes.length === 0) return null
const positionOffset = document.offsetAt(position)
@ -853,7 +853,7 @@ async function provideEmmetCompletions(
position: Position
): Promise<CompletionList> {
let settings = await state.editor.getConfiguration(document.uri)
if (settings.emmetCompletions !== true) return null
if (settings.tailwindCSS.emmetCompletions !== true) return null
const isHtml = isHtmlContext(state, document, position)
const isJs = !isHtml && isJsContext(state, document, position)
@ -980,9 +980,9 @@ export async function resolveCompletionItem(
if (!item.documentation) {
const settings = await state.editor.getConfiguration()
const css = stringifyCss(item.data.join(':'), className, {
tabSize: dlv(settings, 'tabSize', 2),
showPixelEquivalents: dlv(settings, 'showPixelEquivalents', true),
rootFontSize: dlv(settings, 'rootFontSize', 16),
tabSize: dlv(settings, 'editor.tabSize', 2),
showPixelEquivalents: dlv(settings, 'tailwindCSS.showPixelEquivalents', true),
rootFontSize: dlv(settings, 'tailwindCSS.rootFontSize', 16),
})
if (css) {
item.documentation = {
@ -1044,8 +1044,8 @@ async function getCssDetail(state: State, className: any): Promise<string> {
if (className.__rule === true) {
const settings = await state.editor.getConfiguration()
return stringifyDecls(removeMeta(className), {
showPixelEquivalents: dlv(settings, 'showPixelEquivalents', true),
rootFontSize: dlv(settings, 'rootFontSize', 16),
showPixelEquivalents: dlv(settings, 'tailwindCSS.showPixelEquivalents', true),
rootFontSize: dlv(settings, 'tailwindCSS.rootFontSize', 16),
})
}
return null

View File

@ -24,7 +24,7 @@ export async function doValidate(
): Promise<AugmentedDiagnostic[]> {
const settings = await state.editor.getConfiguration(document.uri)
return settings.validate
return settings.tailwindCSS.validate
? [
...(only.includes(DiagnosticKind.CssConflict)
? await getCssConflictDiagnostics(state, document, settings)

View File

@ -13,7 +13,7 @@ export async function getCssConflictDiagnostics(
document: TextDocument,
settings: Settings
): Promise<CssConflictDiagnostic[]> {
let severity = settings.lint.cssConflict
let severity = settings.tailwindCSS.lint.cssConflict
if (severity === 'ignore') return []
let diagnostics: CssConflictDiagnostic[] = []

View File

@ -13,7 +13,7 @@ export async function getIncorrectVariantOrderDiagnostics(
): Promise<IncorrectVariantOrderDiagnostic[]> {
if (!state.jit) return []
let severity = settings.lint.incorrectVariantOrder
let severity = settings.tailwindCSS.lint.incorrectVariantOrder
if (severity === 'ignore') return []
let diagnostics: IncorrectVariantOrderDiagnostic[] = []

View File

@ -9,16 +9,10 @@ export async function getInvalidApplyDiagnostics(
document: TextDocument,
settings: Settings
): Promise<InvalidApplyDiagnostic[]> {
let severity = settings.lint.invalidApply
let severity = settings.tailwindCSS.lint.invalidApply
if (severity === 'ignore') return []
const classNames = await findClassNamesInRange(
state,
document,
undefined,
'css',
false
)
const classNames = await findClassNamesInRange(state, document, undefined, 'css', false)
let diagnostics: InvalidApplyDiagnostic[] = classNames.map((className) => {
let result = validateApply(state, className.className)

View File

@ -24,9 +24,7 @@ function validateConfigPath(
state: State,
path: string | string[],
base: string[] = []
):
| { isValid: true; value: any }
| { isValid: false; reason: string; suggestions: string[] } {
): { isValid: true; value: any } | { isValid: false; reason: string; suggestions: string[] } {
let keys = Array.isArray(path) ? path : stringToPath(path)
let value = dlv(state.config, [...base, ...keys])
let suggestions: string[] = []
@ -49,9 +47,7 @@ function validateConfigPath(
})
.slice(1) // skip original path
return possibilities.find(
(possibility) => validateConfigPath(state, possibility, base).isValid
)
return possibilities.find((possibility) => validateConfigPath(state, possibility, base).isValid)
}
if (typeof value === 'undefined') {
@ -67,9 +63,7 @@ function validateConfigPath(
)
)
if (closestValidKey) {
suggestions.push(
pathToString([...keys.slice(0, keys.length - 1), closestValidKey])
)
suggestions.push(pathToString([...keys.slice(0, keys.length - 1), closestValidKey]))
reason += ` Did you mean '${suggestions[0]}'?`
}
} else {
@ -99,18 +93,14 @@ function validateConfigPath(
Array.isArray(value)
)
) {
let reason = `'${pathToString(
path
)}' was found but does not resolve to a string.`
let reason = `'${pathToString(path)}' was found but does not resolve to a string.`
if (isObject(value)) {
let validKeys = Object.keys(value).filter(
(key) => validateConfigPath(state, [...keys, key], base).isValid
)
if (validKeys.length) {
suggestions.push(
...validKeys.map((validKey) => pathToString([...keys, validKey]))
)
suggestions.push(...validKeys.map((validKey) => pathToString([...keys, validKey])))
reason += ` Did you mean something like '${suggestions[0]}'?`
}
}
@ -171,7 +161,7 @@ export function getInvalidConfigPathDiagnostics(
document: TextDocument,
settings: Settings
): InvalidConfigPathDiagnostic[] {
let severity = settings.lint.invalidConfigPath
let severity = settings.tailwindCSS.lint.invalidConfigPath
if (severity === 'ignore') return []
let diagnostics: InvalidConfigPathDiagnostic[] = []

View File

@ -13,7 +13,7 @@ export function getInvalidScreenDiagnostics(
document: TextDocument,
settings: Settings
): InvalidScreenDiagnostic[] {
let severity = settings.lint.invalidScreen
let severity = settings.tailwindCSS.lint.invalidScreen
if (severity === 'ignore') return []
let diagnostics: InvalidScreenDiagnostic[] = []
@ -31,9 +31,7 @@ export function getInvalidScreenDiagnostics(
let text = document.getText(range)
let matches = findAll(/(?:\s|^)@screen\s+(?<screen>[^\s{]+)/g, text)
let screens = Object.keys(
dlv(state.config, 'theme.screens', dlv(state.config, 'screens', {}))
)
let screens = Object.keys(dlv(state.config, 'theme.screens', dlv(state.config, 'screens', {})))
matches.forEach((match) => {
if (screens.includes(match.groups.screen)) {

View File

@ -13,7 +13,7 @@ export function getInvalidTailwindDirectiveDiagnostics(
document: TextDocument,
settings: Settings
): InvalidTailwindDirectiveDiagnostic[] {
let severity = settings.lint.invalidTailwindDirective
let severity = settings.tailwindCSS.lint.invalidTailwindDirective
if (severity === 'ignore') return []
let diagnostics: InvalidTailwindDirectiveDiagnostic[] = []

View File

@ -12,7 +12,7 @@ export function getInvalidVariantDiagnostics(
document: TextDocument,
settings: Settings
): InvalidVariantDiagnostic[] {
let severity = settings.lint.invalidVariant
let severity = settings.tailwindCSS.lint.invalidVariant
if (severity === 'ignore') return []
let diagnostics: InvalidVariantDiagnostic[] = []
@ -32,8 +32,7 @@ export function getInvalidVariantDiagnostics(
matches.forEach((match) => {
let variants = match.groups.variants.split(/(\s*,\s*)/)
let listStartIndex =
match.index + match[0].length - match.groups.variants.length
let listStartIndex = match.index + match[0].length - match.groups.variants.length
for (let i = 0; i < variants.length; i += 2) {
let variant = variants[i].trim()
@ -50,8 +49,7 @@ export function getInvalidVariantDiagnostics(
message += ` Did you mean '${suggestion}'?`
}
let variantStartIndex =
listStartIndex + variants.slice(0, i).join('').length
let variantStartIndex = listStartIndex + variants.slice(0, i).join('').length
diagnostics.push({
code: DiagnosticKind.InvalidVariant,

View File

@ -18,7 +18,7 @@ export async function getDocumentColors(
if (!state.enabled) return colors
let settings = await state.editor.getConfiguration(document.uri)
if (settings.colorDecorators === false) return colors
if (settings.tailwindCSS.colorDecorators === false) return colors
let classLists = await findClassListsInDocument(state, document)
classLists.forEach((classList) => {

View File

@ -106,9 +106,9 @@ async function provideClassNameHover(
className.className,
dlv(state.classNames.classNames, [...parts, '__info']),
{
tabSize: dlv(settings, 'tabSize', 2),
showPixelEquivalents: dlv(settings, 'showPixelEquivalents', true),
rootFontSize: dlv(settings, 'rootFontSize', 16),
tabSize: dlv(settings, 'editor.tabSize', 2),
showPixelEquivalents: dlv(settings, 'tailwindCSS.showPixelEquivalents', true),
rootFontSize: dlv(settings, 'tailwindCSS.rootFontSize', 16),
}
)

View File

@ -1,20 +1,12 @@
import type { TextDocument, Range, Position } from 'vscode-languageserver'
import {
DocumentClassName,
DocumentClassList,
State,
DocumentHelperFunction,
} from './state'
import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
import lineColumn from 'line-column'
import { isCssContext, isCssDoc } from './css'
import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
import { isWithinRange } from './isWithinRange'
import { isJsContext, isJsDoc } from './js'
import { flatten } from './array'
import {
getClassAttributeLexer,
getComputedClassAttributeLexer,
} from './lexers'
import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
import { getLanguageBoundaries } from './getLanguageBoundaries'
import { resolveRange } from './resolveRange'
const dlv = require('dlv')
@ -63,13 +55,11 @@ export function getClassNamesInClassList({
range: {
start: {
line: range.start.line + start.line,
character:
(end.line === 0 ? range.start.character : 0) + start.character,
character: (end.line === 0 ? range.start.character : 0) + start.character,
},
end: {
line: range.start.line + end.line,
character:
(end.line === 0 ? range.start.character : 0) + end.character,
character: (end.line === 0 ? range.start.character : 0) + end.character,
},
},
})
@ -86,13 +76,7 @@ export async function findClassNamesInRange(
mode?: 'html' | 'css',
includeCustom: boolean = true
): Promise<DocumentClassName[]> {
const classLists = await findClassListsInRange(
state,
doc,
range,
mode,
includeCustom
)
const classLists = await findClassListsInRange(state, doc, range, mode, includeCustom)
return flatten(classLists.map(getClassNamesInClassList))
}
@ -104,10 +88,7 @@ export async function findClassNamesInDocument(
return flatten(classLists.map(getClassNamesInClassList))
}
export function findClassListsInCssRange(
doc: TextDocument,
range?: Range
): DocumentClassList[] {
export function findClassListsInCssRange(doc: TextDocument, range?: Range): DocumentClassList[] {
const text = doc.getText(range)
const matches = findAll(
/(@apply\s+)(?<classList>[^;}]+?)(?<important>\s*!important)?\s*[;}]/g,
@ -117,23 +98,18 @@ export function findClassListsInCssRange(
return matches.map((match) => {
const start = indexToPosition(text, match.index + match[1].length)
const end = indexToPosition(
text,
match.index + match[1].length + match.groups.classList.length
)
const end = indexToPosition(text, match.index + match[1].length + match.groups.classList.length)
return {
classList: match.groups.classList,
important: Boolean(match.groups.important),
range: {
start: {
line: globalStart.line + start.line,
character:
(end.line === 0 ? globalStart.character : 0) + start.character,
character: (end.line === 0 ? globalStart.character : 0) + start.character,
},
end: {
line: globalStart.line + end.line,
character:
(end.line === 0 ? globalStart.character : 0) + end.character,
character: (end.line === 0 ? globalStart.character : 0) + end.character,
},
},
}
@ -146,7 +122,7 @@ async function findCustomClassLists(
range?: Range
): Promise<DocumentClassList[]> {
const settings = await state.editor.getConfiguration(doc.uri)
const regexes = dlv(settings, 'experimental.classRegex', [])
const regexes = dlv(settings, 'tailwindCSS.experimental.classRegex', [])
if (!Array.isArray(regexes) || regexes.length === 0) return []
@ -155,17 +131,13 @@ async function findCustomClassLists(
for (let i = 0; i < regexes.length; i++) {
try {
let [containerRegex, classRegex] = Array.isArray(regexes[i])
? regexes[i]
: [regexes[i]]
let [containerRegex, classRegex] = Array.isArray(regexes[i]) ? regexes[i] : [regexes[i]]
containerRegex = createMultiRegexp(containerRegex)
let containerMatch
while ((containerMatch = containerRegex.exec(text)) !== null) {
const searchStart = doc.offsetAt(
range?.start || { line: 0, character: 0 }
)
const searchStart = doc.offsetAt(range?.start || { line: 0, character: 0 })
const matchStart = searchStart + containerMatch.start
const matchEnd = searchStart + containerMatch.end
@ -173,9 +145,7 @@ async function findCustomClassLists(
classRegex = createMultiRegexp(classRegex)
let classMatch
while (
(classMatch = classRegex.exec(containerMatch.match)) !== null
) {
while ((classMatch = classRegex.exec(containerMatch.match)) !== null) {
const classMatchStart = matchStart + classMatch.start
const classMatchEnd = matchStart + classMatch.end
result.push({
@ -202,15 +172,9 @@ async function findCustomClassLists(
return result
}
export function findClassListsInHtmlRange(
doc: TextDocument,
range?: Range
): DocumentClassList[] {
export function findClassListsInHtmlRange(doc: TextDocument, range?: Range): DocumentClassList[] {
const text = doc.getText(range)
const matches = findAll(
/(?:\s|:|\()(?:class(?:Name)?|\[ngClass\])=['"`{]/g,
text
)
const matches = findAll(/(?:\s|:|\()(?:class(?:Name)?|\[ngClass\])=['"`{]/g, text)
const result: DocumentClassList[] = []
matches.forEach((match) => {
@ -274,12 +238,7 @@ export function findClassListsInHtmlRange(
)
const end = indexToPosition(
text,
match.index +
match[0].length -
1 +
offset +
value.length +
afterOffset
match.index + match[0].length - 1 + offset + value.length + afterOffset
)
return {
@ -287,15 +246,11 @@ export function findClassListsInHtmlRange(
range: {
start: {
line: (range?.start.line || 0) + start.line,
character:
(end.line === 0 ? range?.start.character || 0 : 0) +
start.character,
character: (end.line === 0 ? range?.start.character || 0 : 0) + start.character,
},
end: {
line: (range?.start.line || 0) + end.line,
character:
(end.line === 0 ? range?.start.character || 0 : 0) +
end.character,
character: (end.line === 0 ? range?.start.character || 0 : 0) + end.character,
},
},
}
@ -320,10 +275,7 @@ export async function findClassListsInRange(
} else {
classLists = findClassListsInHtmlRange(doc, range)
}
return [
...classLists,
...(includeCustom ? await findCustomClassLists(state, doc, range) : []),
]
return [...classLists, ...(includeCustom ? await findCustomClassLists(state, doc, range) : [])]
}
export async function findClassListsInDocument(
@ -355,9 +307,7 @@ export function findHelperFunctionsInDocument(
let boundaries = getLanguageBoundaries(state, doc)
if (!boundaries) return []
return flatten(
boundaries.css.map((range) => findHelperFunctionsInRange(doc, range))
)
return flatten(boundaries.css.map((range) => findHelperFunctionsInRange(doc, range)))
}
export function findHelperFunctionsInRange(
@ -387,10 +337,7 @@ export function findHelperFunctionsInRange(
),
valueRange: resolveRange(
{
start: indexToPosition(
text,
startIndex + match.groups.helper.length + 1
),
start: indexToPosition(text, startIndex + match.groups.helper.length + 1),
end: indexToPosition(
text,
startIndex + match.groups.helper.length + 1 + 1 + value.length + 1
@ -420,10 +367,7 @@ export async function findClassNameAtPosition(
if (isCssContext(state, doc, position)) {
classNames = await findClassNamesInRange(state, doc, searchRange, 'css')
} else if (
isHtmlContext(state, doc, position) ||
isJsContext(state, doc, position)
) {
} else if (isHtmlContext(state, doc, position) || isJsContext(state, doc, position)) {
classNames = await findClassNamesInRange(state, doc, searchRange, 'html')
}
@ -431,9 +375,7 @@ export async function findClassNameAtPosition(
return null
}
const className = classNames.find(({ range }) =>
isWithinRange(position, range)
)
const className = classNames.find(({ range }) => isWithinRange(position, range))
if (!className) return null

View File

@ -33,9 +33,9 @@ export function generateRules(state: State, classNames: string[]): { root: Root;
export async function stringifyRoot(state: State, root: Root, uri?: string): Promise<string> {
let settings = await state.editor.getConfiguration(uri)
let tabSize = dlv(settings, 'tabSize', 2)
let showPixelEquivalents = dlv(settings, 'showPixelEquivalents', true)
let rootFontSize = dlv(settings, 'rootFontSize', 16)
let tabSize = dlv(settings, 'editor.tabSize', 2)
let showPixelEquivalents = dlv(settings, 'tailwindCSS.showPixelEquivalents', true)
let rootFontSize = dlv(settings, 'tailwindCSS.rootFontSize', 16)
let clone = root

View File

@ -31,7 +31,10 @@ export type EditorState = {
type DiagnosticSeveritySetting = 'ignore' | 'warning' | 'error'
export type Settings = {
editor: {
tabSize: number
}
tailwindCSS: {
emmetCompletions: boolean
includeLanguages: Record<string, string>
validate: boolean
@ -50,6 +53,7 @@ export type Settings = {
experimental: {
classRegex: string[]
}
}
}
export interface FeatureFlags {

View File

@ -17,6 +17,7 @@ import {
Range,
TextEditorDecorationType,
RelativePattern,
ConfigurationScope,
} from 'vscode'
import { LanguageClient, LanguageClientOptions, TransportKind } from 'vscode-languageclient/node'
import { DEFAULT_LANGUAGES } from './lib/languages'
@ -249,31 +250,28 @@ export function activate(context: ExtensionContext) {
return editableColors
},
workspace: {
configuration: (params, token, next) => {
try {
configuration: (params) => {
return params.items.map(({ section, scopeUri }) => {
if (section === 'tailwindCSS') {
let scope = scopeUri
? {
languageId: Workspace.textDocuments.find(
(doc) => doc.uri.toString() === scopeUri
).languageId,
let scope: ConfigurationScope = folder
if (scopeUri) {
let doc = Workspace.textDocuments.find((doc) => doc.uri.toString() === scopeUri)
if (doc) {
scope = {
languageId: doc.languageId,
}
: folder
let tabSize = Workspace.getConfiguration('editor', scope).get('tabSize') || 2
return { tabSize, ...Workspace.getConfiguration(section, scope) }
}
throw Error()
}
return Workspace.getConfiguration(section, scope)
})
} catch (_error) {
return next(params, token)
}
},
},
},
initializationOptions: {
userLanguages: getUserLanguages(folder),
configuration: Workspace.getConfiguration('tailwindCSS', folder),
configuration: {
editor: Workspace.getConfiguration('editor', folder),
tailwindCSS: Workspace.getConfiguration('tailwindCSS', folder),
},
},
synchronize: {
configurationSection: ['editor', 'tailwindCSS'],

View File

@ -158,10 +158,17 @@ async function createProjectService(
if (documentSettingsCache.has(uri)) {
return documentSettingsCache.get(uri)
}
let config = await connection.workspace.getConfiguration({
let [editor, tailwindCSS] = await Promise.all([
connection.workspace.getConfiguration({
section: 'editor',
scopeUri: uri,
}),
connection.workspace.getConfiguration({
section: 'tailwindCSS',
scopeUri: uri,
})
}),
])
let config: Settings = { editor, tailwindCSS }
documentSettingsCache.set(uri, config)
return config
},