2020-10-08 15:20:54 +00:00
|
|
|
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')
|
2020-10-08 15:20:54 +00:00
|
|
|
import { isCssContext } from './util/css'
|
|
|
|
import { findClassNameAtPosition } from './util/find'
|
|
|
|
import { validateApply } from './util/validateApply'
|
|
|
|
import { getClassNameParts } from './util/getClassNameAtPosition'
|
2020-11-26 20:07:39 +00:00
|
|
|
import { getDocumentSettings } from './util/getDocumentSettings'
|
2020-04-12 14:48:38 +00:00
|
|
|
|
2020-11-26 20:07:39 +00:00
|
|
|
export async function doHover(
|
2020-04-12 14:48:38 +00:00
|
|
|
state: State,
|
2020-10-08 15:20:54 +00:00
|
|
|
document: TextDocument,
|
|
|
|
position: Position
|
2020-11-26 20:07:39 +00:00
|
|
|
): Promise<Hover> {
|
2020-04-12 16:53:22 +00:00
|
|
|
return (
|
2020-11-26 20:07:39 +00:00
|
|
|
(await provideClassNameHover(state, document, position)) ||
|
2020-10-08 15:20:54 +00:00
|
|
|
provideCssHelperHover(state, document, position)
|
2020-04-12 16:53:22 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function provideCssHelperHover(
|
|
|
|
state: State,
|
2020-10-08 15:20:54 +00:00
|
|
|
document: TextDocument,
|
|
|
|
position: Position
|
2020-04-12 16:53:22 +00:00
|
|
|
): Hover {
|
2020-10-08 15:20:54 +00:00
|
|
|
if (!isCssContext(state, document, position)) return null
|
2020-04-12 16:53:22 +00:00
|
|
|
|
2020-10-08 15:20:54 +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
|
|
|
}
|
|
|
|
|
2020-11-26 20:07:39 +00:00
|
|
|
async function provideClassNameHover(
|
2020-04-12 14:48:38 +00:00
|
|
|
state: State,
|
2020-10-08 15:20:54 +00:00
|
|
|
document: TextDocument,
|
|
|
|
position: Position
|
2020-11-26 20:07:39 +00:00
|
|
|
): Promise<Hover> {
|
2020-12-07 15:39:44 +00:00
|
|
|
let className = await findClassNameAtPosition(state, document, position)
|
2020-05-17 16:13:14 +00:00
|
|
|
if (className === null) return null
|
2020-04-12 14:48:38 +00:00
|
|
|
|
2020-05-17 16:13:14 +00:00
|
|
|
const parts = getClassNameParts(state, className.className)
|
2020-04-22 18:18:57 +00:00
|
|
|
if (!parts) return null
|
2020-04-12 14:48:38 +00:00
|
|
|
|
2020-10-08 15:20:54 +00:00
|
|
|
if (isCssContext(state, document, position)) {
|
2020-06-21 00:38:08 +00:00
|
|
|
let validated = validateApply(state, parts)
|
|
|
|
if (validated === null || validated.isApplyable === false) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-01 19:05:58 +00:00
|
|
|
const settings = await getDocumentSettings(state, document)
|
2020-11-26 20:07:39 +00:00
|
|
|
|
2020-11-19 17:34:59 +00:00
|
|
|
const css = stringifyCss(
|
|
|
|
className.className,
|
2020-11-26 20:07:39 +00:00
|
|
|
dlv(state.classNames.classNames, [...parts, '__info']),
|
2020-12-01 19:05:58 +00:00
|
|
|
{
|
2021-02-05 14:49:06 +00:00
|
|
|
tabSize: dlv(settings, 'tabSize', 2),
|
|
|
|
showPixelEquivalents: dlv(settings, 'showPixelEquivalents', true),
|
|
|
|
rootFontSize: dlv(settings, 'rootFontSize', 16),
|
2020-12-01 19:05:58 +00:00
|
|
|
}
|
2020-11-19 17:34:59 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
},
|
2020-05-17 16:13:14 +00:00
|
|
|
range: className.range,
|
2020-04-12 14:48:38 +00:00
|
|
|
}
|
|
|
|
}
|