add class list finder helper and fix ranges

master
Brad Cornes 2020-05-24 18:32:25 +01:00
parent d6b5a897ac
commit 02683ece85
2 changed files with 93 additions and 13 deletions

View File

@ -12,7 +12,7 @@ export const CSS_LANGUAGES = [
'sugarss', 'sugarss',
] ]
function isCssDoc(state: State, doc: TextDocument): boolean { export function isCssDoc(state: State, doc: TextDocument): boolean {
const userCssLanguages = Object.keys( const userCssLanguages = Object.keys(
state.editor.userLanguages state.editor.userLanguages
).filter((lang) => CSS_LANGUAGES.includes(state.editor.userLanguages[lang])) ).filter((lang) => CSS_LANGUAGES.includes(state.editor.userLanguages[lang]))

View File

@ -1,10 +1,10 @@
import { TextDocument, Range, Position } from 'vscode-languageserver' import { TextDocument, Range, Position } from 'vscode-languageserver'
import { DocumentClassName, DocumentClassList, State } from './state' import { DocumentClassName, DocumentClassList, State } from './state'
import lineColumn from 'line-column' import lineColumn from 'line-column'
import { isCssContext } from './css' import { isCssContext, isCssDoc } from './css'
import { isHtmlContext } from './html' import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
import { isWithinRange } from './isWithinRange' import { isWithinRange } from './isWithinRange'
import { isJsContext } from './js' import { isJsContext, isJsDoc } from './js'
import { getClassAttributeLexer } from './lexers' import { getClassAttributeLexer } from './lexers'
export function findAll(re: RegExp, str: string): RegExpMatchArray[] { export function findAll(re: RegExp, str: string): RegExpMatchArray[] {
@ -26,8 +26,8 @@ export function findLast(re: RegExp, str: string): RegExpMatchArray {
export function findClassNamesInRange( export function findClassNamesInRange(
doc: TextDocument, doc: TextDocument,
range: Range, range?: Range,
mode: 'html' | 'css' mode?: 'html' | 'css'
): DocumentClassName[] { ): DocumentClassName[] {
const classLists = findClassListsInRange(doc, range, mode) const classLists = findClassListsInRange(doc, range, mode)
return [].concat.apply( return [].concat.apply(
@ -66,10 +66,11 @@ export function findClassNamesInRange(
export function findClassListsInCssRange( export function findClassListsInCssRange(
doc: TextDocument, doc: TextDocument,
range: Range range?: Range
): DocumentClassList[] { ): DocumentClassList[] {
const text = doc.getText(range) const text = doc.getText(range)
const matches = findAll(/(@apply\s+)(?<classList>[^;}]+)[;}]/g, text) const matches = findAll(/(@apply\s+)(?<classList>[^;}]+)[;}]/g, text)
const globalStart: Position = range ? range.start : { line: 0, character: 0 }
return matches.map((match) => { return matches.map((match) => {
const start = indexToPosition(text, match.index + match[1].length) const start = indexToPosition(text, match.index + match[1].length)
@ -81,12 +82,14 @@ export function findClassListsInCssRange(
classList: match.groups.classList, classList: match.groups.classList,
range: { range: {
start: { start: {
line: range.start.line + start.line, line: globalStart.line + start.line,
character: range.start.character + start.character, character:
(end.line === 0 ? globalStart.character : 0) + start.character,
}, },
end: { end: {
line: range.start.line + end.line, line: globalStart.line + end.line,
character: range.start.character + end.character, character:
(end.line === 0 ? globalStart.character : 0) + end.character,
}, },
}, },
} }
@ -172,11 +175,14 @@ export function findClassListsInHtmlRange(
range: { range: {
start: { start: {
line: range.start.line + start.line, line: range.start.line + start.line,
character: range.start.character + start.character, character:
(end.line === 0 ? range.start.character : 0) +
start.character,
}, },
end: { end: {
line: range.start.line + end.line, line: range.start.line + end.line,
character: range.start.character + end.character, character:
(end.line === 0 ? range.start.character : 0) + end.character,
}, },
}, },
} }
@ -199,6 +205,80 @@ export function findClassListsInRange(
return findClassListsInHtmlRange(doc, range) return findClassListsInHtmlRange(doc, range)
} }
export function findClassListsInDocument(
state: State,
doc: TextDocument
): DocumentClassList[] {
if (isCssDoc(state, doc)) {
return findClassListsInCssRange(doc)
}
if (isVueDoc(doc)) {
let text = doc.getText()
let blocks = findAll(
/<(?<type>template|style|script)\b[^>]*>.*?(<\/\k<type>>|$)/gis,
text
)
let htmlRanges: Range[] = []
let cssRanges: Range[] = []
for (let i = 0; i < blocks.length; i++) {
let range = {
start: indexToPosition(text, blocks[i].index),
end: indexToPosition(text, blocks[i].index + blocks[i][0].length),
}
if (blocks[i].groups.type === 'style') {
cssRanges.push(range)
} else {
htmlRanges.push(range)
}
}
return [].concat.apply(
[],
[
...htmlRanges.map((range) => findClassListsInHtmlRange(doc, range)),
...cssRanges.map((range) => findClassListsInCssRange(doc, range)),
]
)
}
if (isHtmlDoc(state, doc) || isJsDoc(state, doc) || isSvelteDoc(doc)) {
let text = doc.getText()
let styleBlocks = findAll(/<style(?:\s[^>]*>|>).*?(<\/style>|$)/gis, text)
let htmlRanges: Range[] = []
let cssRanges: Range[] = []
let currentIndex = 0
for (let i = 0; i < styleBlocks.length; i++) {
htmlRanges.push({
start: indexToPosition(text, currentIndex),
end: indexToPosition(text, styleBlocks[i].index),
})
cssRanges.push({
start: indexToPosition(text, styleBlocks[i].index),
end: indexToPosition(
text,
styleBlocks[i].index + styleBlocks[i][0].length
),
})
currentIndex = styleBlocks[i].index + styleBlocks[i][0].length
}
htmlRanges.push({
start: indexToPosition(text, currentIndex),
end: indexToPosition(text, text.length),
})
return [].concat.apply(
[],
[
...htmlRanges.map((range) => findClassListsInHtmlRange(doc, range)),
...cssRanges.map((range) => findClassListsInCssRange(doc, range)),
]
)
}
return []
}
function indexToPosition(str: string, index: number): Position { function indexToPosition(str: string, index: number): Position {
const { line, col } = lineColumn(str + '\n', index) const { line, col } = lineColumn(str + '\n', index)
return { line: line - 1, character: col - 1 } return { line: line - 1, character: col - 1 }