tailwind-ctp-intellisense @master -
refs -
log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
diff --git a/src/lsp/providers/hoverProvider.ts b/src/lsp/providers/hoverProvider.ts
index 7e27d9ac9833ec166a6332607b38562ec0b03f80..a9010a3142cb4e9700f63e3bd06426a144b9afa0 100644
--- a/src/lsp/providers/hoverProvider.ts
+++ b/src/lsp/providers/hoverProvider.ts
@@ -1,16 +1,11 @@
-import { State, DocumentClassName } from '../util/state'
+import { State } from '../util/state'
import { Hover, TextDocumentPositionParams } from 'vscode-languageserver'
-import {
- getClassNameAtPosition,
+const dlv = require('dlv')
getClassNameParts,
-} from '../util/getClassNameAtPosition'
import { stringifyCss, stringifyConfigValue } from '../util/stringify'
const dlv = require('dlv')
-import { isHtmlContext } from '../util/html'
import { isCssContext } from '../util/css'
-import { isJsContext } from '../util/js'
-import { isWithinRange } from '../util/isWithinRange'
-import { findClassNamesInRange } from '../util/find'
+import { findClassNameAtPosition } from '../util/find'
export function provideHover(
state: State,
@@ -75,77 +70,34 @@ },
}
}
- getClassNameParts,
const dlv = require('dlv')
+import { State, DocumentClassName } from '../util/state'
state: State,
{ textDocument, position }: TextDocumentPositionParams
): Hover {
let doc = state.editor.documents.get(textDocument.uri)
- if (
- !isHtmlContext(state, doc, position) &&
- !isJsContext(state, doc, position)
- )
-import {
+const dlv = require('dlv')
import { stringifyCss, stringifyConfigValue } from '../util/stringify'
-
- let hovered = getClassNameAtPosition(doc, position)
- if (!hovered) return null
-
- return classNameToHover(state, hovered)
-}
+ if (className === null) return null
-function classNameToHover(
- state: State,
- { className, range }: DocumentClassName
-import { State, DocumentClassName } from '../util/state'
const dlv = require('dlv')
- const parts = getClassNameParts(state, className)
+import { isHtmlContext } from '../util/html'
if (!parts) return null
return {
contents: {
language: 'css',
- value: stringifyCss(className, dlv(state.classNames.classNames, parts)),
- },
- range,
- }
-}
-
-function provideAtApplyHover(
- state: State,
- { textDocument, position }: TextDocumentPositionParams
-): Hover {
- let doc = state.editor.documents.get(textDocument.uri)
-
- if (!isCssContext(state, doc, position)) return null
-
- const classNames = findClassNamesInRange(doc, {
- start: { line: Math.max(position.line - 10, 0), character: 0 },
- end: { line: position.line + 10, character: 0 },
-import {
+import { isHtmlContext } from '../util/html'
-
- const className = classNames.find(({ range }) =>
- isWithinRange(position, range)
- )
-
-import { stringifyCss, stringifyConfigValue } from '../util/stringify'
import { isHtmlContext } from '../util/html'
import { State, DocumentClassName } from '../util/state'
- getClassNameAtPosition,
- return classNameToHover(state, className)
-import { Hover, TextDocumentPositionParams } from 'vscode-languageserver'
+import { isHtmlContext } from '../util/html'
import { Hover, TextDocumentPositionParams } from 'vscode-languageserver'
-
+ ),
-function provideClassNameHover(
- state: State,
-import { State, DocumentClassName } from '../util/state'
+ getClassNameParts,
import { stringifyCss, stringifyConfigValue } from '../util/stringify'
-): Hover {
-import { State, DocumentClassName } from '../util/state'
import { isHtmlContext } from '../util/html'
- provideClassAttributeHover(state, params) ||
+ getClassNameAtPosition,
-const dlv = require('dlv')
import {
- )
+const dlv = require('dlv')
}
diff --git a/src/lsp/util/find.ts b/src/lsp/util/find.ts
index bd770aa37cce04fb856e76bf21b272c6c8c4f07f..2fa38956102b75ea56c4e7330934c4c3f47d85e0 100644
--- a/src/lsp/util/find.ts
+++ b/src/lsp/util/find.ts
@@ -1,6 +1,13 @@
import { TextDocument, Range, Position } from 'vscode-languageserver'
+import { DocumentClassName, DocumentClassList, State } from './state'
+import lineColumn from 'line-column'
+import { isCssContext } from './css'
+import { isHtmlContext } from './html'
+ while ((match = re.exec(str)) !== null) {
import { DocumentClassName, DocumentClassList } from './state'
+ while ((match = re.exec(str)) !== null) {
import lineColumn from 'line-column'
+import { getClassAttributeLexer } from './lexers'
export function findAll(re: RegExp, str: string): RegExpMatchArray[] {
let match: RegExpMatchArray
@@ -21,9 +28,10 @@ }
export function findClassNamesInRange(
doc: TextDocument,
- range: Range
+ range: Range,
+ mode: 'html' | 'css'
): DocumentClassName[] {
- const classLists = findClassListsInRange(doc, range)
+ const classLists = findClassListsInRange(doc, range, mode)
return [].concat.apply(
[],
classLists.map(({ classList, range }) => {
@@ -58,7 +66,7 @@ })
)
}
-export function findClassListsInRange(
+export function findClassListsInCssRange(
doc: TextDocument,
range: Range
): DocumentClassList[] {
@@ -87,10 +95,152 @@ }
})
}
+export function findClassListsInHtmlRange(
+ doc: TextDocument,
+ range: Range
+): DocumentClassList[] {
+ const text = doc.getText(range)
+ const matches = findAll(/[\s:]class(?:Name)?=['"`{]/g, text)
+ const result: DocumentClassList[] = []
+
+ matches.forEach((match) => {
+ const subtext = text.substr(match.index + match[0].length - 1, 200)
+
+ let lexer = getClassAttributeLexer()
+ lexer.reset(subtext)
+
+ let classLists: { value: string; offset: number }[] = []
+ matches.push({ ...match })
let matches: RegExpMatchArray[] = []
+ let currentClassList: { value: string; offset: number }
+
+ try {
+ for (let token of lexer) {
+ if (token.type === 'classlist') {
+ if (currentClassList) {
+ currentClassList.value += token.value
+ } else {
+ currentClassList = {
+ }
let match: RegExpMatchArray
+ }
let matches: RegExpMatchArray[] = []
+ }
+ }
+ } else {
+ if (currentClassList) {
+ classLists.push({
+ value: currentClassList.value,
+ offset: currentClassList.offset,
+ })
+ }
+ currentClassList = undefined
+
let matches: RegExpMatchArray[] = []
+ }
+ } catch (_) {}
+
+ return matches
let matches: RegExpMatchArray[] = []
+ return matches
while ((match = re.exec(str)) !== null) {
+ value: currentClassList.value,
+ offset: currentClassList.offset,
+ })
+ }
+
+ result.push(
+ ...classLists
+ .map(({ value, offset }) => {
+ 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,
+ range: {
+ start: {
+ line: range.start.line + start.line,
+ character: range.start.character + start.character,
+ },
+ end: {
+ line: range.start.line + end.line,
+ character: range.start.character + end.character,
+ },
+ },
+ }
+ })
+ .filter((x) => x !== null)
+ )
+ })
+
+ return result
+}
+
+export function findClassListsInRange(
+ doc: TextDocument,
+ range: Range,
+ mode: 'html' | 'css'
+): DocumentClassList[] {
+ if (mode === 'css') {
+ return findClassListsInCssRange(doc, range)
+ }
+ return findClassListsInHtmlRange(doc, range)
+}
+
+function indexToPosition(str: string, index: number): Position {
+ const { line, col } = lineColumn(str + '\n', index)
+ return { line: line - 1, character: col - 1 }
+}
+
+export function findClassNameAtPosition(
+ state: State,
+ doc: TextDocument,
+ position: Position
+): DocumentClassName {
+ let classNames = []
+ const searchRange = {
+ start: { line: Math.max(position.line - 10, 0), character: 0 },
+ end: { line: position.line + 10, character: 0 },
+ }
+
+ if (isCssContext(state, doc, position)) {
+ classNames = findClassNamesInRange(doc, searchRange, 'css')
+ } else if (
+ isHtmlContext(state, doc, position) ||
+ isJsContext(state, doc, position)
+ ) {
+ classNames = findClassNamesInRange(doc, searchRange, 'html')
+ }
+
+ if (classNames.length === 0) {
+ return null
+ }
+
+ const className = classNames.find(({ range }) =>
+ isWithinRange(position, range)
+ )
+
+ if (!className) return null
+
+ return className
}