Home

tailwind-ctp-intellisense @7b8ee549de91d6110e638be064471be25b57845a - refs - log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
tailwind-ctp-intellisense / packages / tailwindcss-language-server / src / providers / hoverProvider.ts
- raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
import { State } from '../util/state'
import { Hover, TextDocumentPositionParams } from 'vscode-languageserver'
import {
  getClassNameAtPosition,
  getClassNameParts,
} from '../util/getClassNameAtPosition'
import { stringifyCss, stringifyConfigValue } from '../util/stringify'
const dlv = require('dlv')
import escapeClassName from 'css.escape'
import { isHtmlContext } from '../util/html'
import { isCssContext } from '../util/css'

export function provideHover(
  state: State,
  params: TextDocumentPositionParams
): Hover {
  return (
    provideClassNameHover(state, params) || provideCssHelperHover(state, params)
  )
}

function provideCssHelperHover(
  state: State,
  { textDocument, position }: TextDocumentPositionParams
): Hover {
  let doc = state.editor.documents.get(textDocument.uri)

  if (!isCssContext(doc, position)) return null

  const line = doc.getText({
    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

  const startChar = match.index + 7
  const endChar = startChar + match.groups.key.length

  if (position.character < startChar || position.character >= endChar) {
    return null
  }

  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,
      },
    },
  }
}

function provideClassNameHover(
  state: State,
  { textDocument, position }: TextDocumentPositionParams
): Hover {
  let doc = state.editor.documents.get(textDocument.uri)

  if (!isHtmlContext(doc, position)) return null

  let hovered = getClassNameAtPosition(doc, position)
  if (!hovered) return null

  const parts = getClassNameParts(state, hovered.className)
  if (parts === null) return null

  return {
    contents: {
      language: 'css',
      value: stringifyCss(dlv(state.classNames.classNames, parts), {
        selector: augmentClassName(parts, state),
      }),
    },
    range: hovered.range,
  }
}

// TODO
function augmentClassName(className: string | string[], state: State): string {
  const parts = Array.isArray(className)
    ? className
    : getClassNameParts(state, className)
  const obj = dlv(state.classNames.classNames, parts)
  const pseudo = obj.__pseudo ? obj.__pseudo.join('') : ''
  const scope = obj.__scope ? `${obj.__scope} ` : ''
  return `${scope}.${escapeClassName(parts.join(state.separator))}${pseudo}`
}