Improve conflict diagnostics (#503)

master
Brad Cornes 2022-03-04 15:41:44 +00:00 committed by GitHub
parent 86497bb380
commit ddfaea21cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 51 deletions

View File

@ -20,7 +20,9 @@ export async function getCssConflictDiagnostics(
const classLists = await findClassListsInDocument(state, document) const classLists = await findClassListsInDocument(state, document)
classLists.forEach((classList) => { classLists.forEach((classList) => {
const classNames = getClassNamesInClassList(classList) const classNames = Array.isArray(classList)
? classList.flatMap(getClassNamesInClassList)
: getClassNamesInClassList(classList)
classNames.forEach((className, index) => { classNames.forEach((className, index) => {
if (state.jit) { if (state.jit) {

View File

@ -22,7 +22,7 @@ export async function getRecommendedVariantOrderDiagnostics(
let diagnostics: RecommendedVariantOrderDiagnostic[] = [] let diagnostics: RecommendedVariantOrderDiagnostic[] = []
const classLists = await findClassListsInDocument(state, document) const classLists = await findClassListsInDocument(state, document)
classLists.forEach((classList) => { classLists.flat().forEach((classList) => {
const classNames = getClassNamesInClassList(classList) const classNames = getClassNamesInClassList(classList)
classNames.forEach((className) => { classNames.forEach((className) => {
let { rules } = jit.generateRules(state, [className.className]) let { rules } = jit.generateRules(state, [className.className])

View File

@ -20,7 +20,7 @@ export async function getDocumentColors(
if (settings.tailwindCSS.colorDecorators === false) return colors if (settings.tailwindCSS.colorDecorators === false) return colors
let classLists = await findClassListsInDocument(state, document) let classLists = await findClassListsInDocument(state, document)
classLists.forEach((classList) => { classLists.flat().forEach((classList) => {
let classNames = getClassNamesInClassList(classList) let classNames = getClassNamesInClassList(classList)
classNames.forEach((className) => { classNames.forEach((className) => {
let color = getColor(state, className.className) let color = getColor(state, className.className)

View File

@ -77,7 +77,15 @@ export async function findClassNamesInRange(
includeCustom: boolean = true includeCustom: boolean = true
): Promise<DocumentClassName[]> { ): 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)) return flatten(
classLists.flatMap((classList) => {
if (Array.isArray(classList)) {
return classList.map(getClassNamesInClassList)
} else {
return [getClassNamesInClassList(classList)]
}
})
)
} }
export async function findClassNamesInDocument( export async function findClassNamesInDocument(
@ -85,7 +93,15 @@ export async function findClassNamesInDocument(
doc: TextDocument doc: TextDocument
): Promise<DocumentClassName[]> { ): Promise<DocumentClassName[]> {
const classLists = await findClassListsInDocument(state, doc) const classLists = await findClassListsInDocument(state, doc)
return flatten(classLists.map(getClassNamesInClassList)) return flatten(
classLists.flatMap((classList) => {
if (Array.isArray(classList)) {
return classList.map(getClassNamesInClassList)
} else {
return [getClassNamesInClassList(classList)]
}
})
)
} }
export function findClassListsInCssRange(doc: TextDocument, range?: Range): DocumentClassList[] { export function findClassListsInCssRange(doc: TextDocument, range?: Range): DocumentClassList[] {
@ -182,7 +198,7 @@ export async function findClassListsInHtmlRange(
state: State, state: State,
doc: TextDocument, doc: TextDocument,
range?: Range range?: Range
): Promise<DocumentClassList[]> { ): Promise<Array<DocumentClassList | DocumentClassList[]>> {
const text = doc.getText(range) const text = doc.getText(range)
const matches = matchClassAttributes( const matches = matchClassAttributes(
@ -190,7 +206,7 @@ export async function findClassListsInHtmlRange(
(await state.editor.getConfiguration(doc.uri)).tailwindCSS.classAttributes (await state.editor.getConfiguration(doc.uri)).tailwindCSS.classAttributes
) )
const result: DocumentClassList[] = [] const result: Array<DocumentClassList | DocumentClassList[]> = []
matches.forEach((match) => { matches.forEach((match) => {
const subtext = text.substr(match.index + match[0].length - 1) const subtext = text.substr(match.index + match[0].length - 1)
@ -201,9 +217,11 @@ export async function findClassListsInHtmlRange(
: getClassAttributeLexer() : getClassAttributeLexer()
lexer.reset(subtext) lexer.reset(subtext)
let classLists: { value: string; offset: number }[] = [] let classLists: Array<{ value: string; offset: number } | { value: string; offset: number }[]> =
let token: moo.Token []
let rootClassList: { value: string; offset: number }[] = []
let currentClassList: { value: string; offset: number } let currentClassList: { value: string; offset: number }
let depth = 0
try { try {
for (let token of lexer) { for (let token of lexer) {
@ -218,56 +236,53 @@ export async function findClassListsInHtmlRange(
} }
} else { } else {
if (currentClassList) { if (currentClassList) {
classLists.push({ if (depth === 0) {
value: currentClassList.value, rootClassList.push({
offset: currentClassList.offset, value: currentClassList.value,
}) offset: currentClassList.offset,
})
} else {
classLists.push({
value: currentClassList.value,
offset: currentClassList.offset,
})
}
} }
currentClassList = undefined currentClassList = undefined
} }
if (token.type === 'lbrace') {
depth += 1
} else if (token.type === 'rbrace') {
depth -= 1
}
} }
} catch (_) {} } catch (_) {}
if (currentClassList) { if (currentClassList) {
classLists.push({ if (depth === 0) {
value: currentClassList.value, rootClassList.push({
offset: currentClassList.offset, value: currentClassList.value,
}) offset: currentClassList.offset,
})
} else {
classLists.push({
value: currentClassList.value,
offset: currentClassList.offset,
})
}
} }
classLists.push(rootClassList)
result.push( result.push(
...classLists ...classLists
.map(({ value, offset }) => { .map((classList) => {
if (value.trim() === '') { if (Array.isArray(classList)) {
return null return classList
} .map((classList) => resolveClassList(classList, text, match, range))
.filter((x) => x !== null)
const before = value.match(/^\s*/) } else {
const beforeOffset = before === null ? 0 : before[0].length return resolveClassList(classList, text, match, range)
const after = value.match(/\s*$/)
const afterOffset = after === null ? 0 : -after[0].length
const start = indexToPosition(
text,
match.index + match[0].length - 1 + offset + beforeOffset
)
const end = indexToPosition(
text,
match.index + match[0].length - 1 + offset + value.length + afterOffset
)
return {
classList: value.substr(beforeOffset, value.length + afterOffset),
range: {
start: {
line: (range?.start.line || 0) + start.line,
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,
},
},
} }
}) })
.filter((x) => x !== null) .filter((x) => x !== null)
@ -277,14 +292,51 @@ export async function findClassListsInHtmlRange(
return result return result
} }
function resolveClassList(
classList: { value: string; offset: number },
text: string,
match: RegExpMatchArray,
range?: Range
): DocumentClassList {
let { value, offset } = classList
if (value.trim() === '') {
return null
}
const before = value.match(/^\s*/)
const beforeOffset = before === null ? 0 : before[0].length
const after = value.match(/\s*$/)
const afterOffset = after === null ? 0 : -after[0].length
const start = indexToPosition(text, match.index + match[0].length - 1 + offset + beforeOffset)
const end = indexToPosition(
text,
match.index + match[0].length - 1 + offset + value.length + afterOffset
)
return {
classList: value.substr(beforeOffset, value.length + afterOffset),
range: {
start: {
line: (range?.start.line || 0) + start.line,
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,
},
},
}
}
export async function findClassListsInRange( export async function findClassListsInRange(
state: State, state: State,
doc: TextDocument, doc: TextDocument,
range?: Range, range?: Range,
mode?: 'html' | 'css', mode?: 'html' | 'css',
includeCustom: boolean = true includeCustom: boolean = true
): Promise<DocumentClassList[]> { ): Promise<Array<DocumentClassList | DocumentClassList[]>> {
let classLists: DocumentClassList[] let classLists: Array<DocumentClassList | DocumentClassList[]>
if (mode === 'css') { if (mode === 'css') {
classLists = findClassListsInCssRange(doc, range) classLists = findClassListsInCssRange(doc, range)
} else { } else {
@ -296,7 +348,7 @@ export async function findClassListsInRange(
export async function findClassListsInDocument( export async function findClassListsInDocument(
state: State, state: State,
doc: TextDocument doc: TextDocument
): Promise<DocumentClassList[]> { ): Promise<Array<DocumentClassList | DocumentClassList[]>> {
if (isCssDoc(state, doc)) { if (isCssDoc(state, doc)) {
return findClassListsInCssRange(doc) return findClassListsInCssRange(doc)
} }