tailwind-ctp-intellisense/packages/tailwindcss-language-service/src/hoverProvider.ts

107 lines
2.6 KiB
TypeScript
Raw Normal View History

import { State } from './util/state'
import type { Hover, TextDocument, Position } from 'vscode-languageserver'
import { stringifyCss, stringifyConfigValue } from './util/stringify'
2020-04-12 14:48:38 +00:00
const dlv = require('dlv')
import { isCssContext } from './util/css'
import { findClassNameAtPosition } from './util/find'
import { validateApply } from './util/validateApply'
import { getClassNameParts } from './util/getClassNameAtPosition'
2020-04-12 14:48:38 +00:00
export function doHover(
2020-04-12 14:48:38 +00:00
state: State,
document: TextDocument,
position: Position
2020-04-12 14:48:38 +00:00
): Hover {
2020-04-12 16:53:22 +00:00
return (
provideClassNameHover(state, document, position) ||
provideCssHelperHover(state, document, position)
2020-04-12 16:53:22 +00:00
)
}
function provideCssHelperHover(
state: State,
document: TextDocument,
position: Position
2020-04-12 16:53:22 +00:00
): Hover {
if (!isCssContext(state, document, position)) return null
2020-04-12 16:53:22 +00:00
const line = document.getText({
2020-04-12 16:53:22 +00:00
start: { line: position.line, character: 0 },
end: { line: position.line + 1, character: 0 },
})
const match = line.match(
/(?<helper>theme|config)\((?<quote>['"])(?<key>[^)]+)\k<quote>\)/
)
if (match === null) return null
2020-04-28 20:19:28 +00:00
const startChar = match.index + match.groups.helper.length + 2
2020-04-12 16:53:22 +00:00
const endChar = startChar + match.groups.key.length
2020-04-12 14:48:38 +00:00
2020-04-12 16:53:22 +00:00
if (position.character < startChar || position.character >= endChar) {
return null
2020-04-12 14:48:38 +00:00
}
2020-04-12 16:53:22 +00:00
let key = match.groups.key
.split(/(\[[^\]]+\]|\.)/)
.filter(Boolean)
.filter((x) => x !== '.')
.map((x) => x.replace(/^\[([^\]]+)\]$/, '$1'))
if (key.length === 0) return null
if (match.groups.helper === 'theme') {
key = ['theme', ...key]
}
const value = stringifyConfigValue(dlv(state.config, key))
if (value === null) return null
return {
contents: { kind: 'plaintext', value },
range: {
start: { line: position.line, character: startChar },
end: {
line: position.line,
character: endChar,
},
},
}
2020-04-12 14:48:38 +00:00
}
function provideClassNameHover(
2020-04-12 14:48:38 +00:00
state: State,
document: TextDocument,
position: Position
2020-04-12 14:48:38 +00:00
): Hover {
let className = findClassNameAtPosition(state, document, position)
if (className === null) return null
2020-04-12 14:48:38 +00:00
const parts = getClassNameParts(state, className.className)
if (!parts) return null
2020-04-12 14:48:38 +00:00
if (isCssContext(state, document, position)) {
let validated = validateApply(state, parts)
if (validated === null || validated.isApplyable === false) {
return null
}
}
2020-11-19 17:34:59 +00:00
const css = stringifyCss(
className.className,
dlv(state.classNames.classNames, [...parts, '__info'])
)
if (!css) return null
2020-04-12 14:48:38 +00:00
return {
contents: {
language: 'css',
2020-11-19 17:34:59 +00:00
value: css,
2020-04-12 14:48:38 +00:00
},
range: className.range,
2020-04-12 14:48:38 +00:00
}
}