Skip to content

Commit ab47016

Browse files
committed
add documentation link to hovers
1 parent 033c71c commit ab47016

File tree

5 files changed

+140
-2
lines changed

5 files changed

+140
-2
lines changed

package-lock.json

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/tailwindcss-language-service/package-lock.json

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/tailwindcss-language-service/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"dependencies": {
1717
"@ctrl/tinycolor": "^3.1.4",
1818
"@types/moo": "^0.5.3",
19+
"abort-controller": "^3.0.0",
1920
"css.escape": "^1.5.1",
2021
"detect-indent": "^6.0.0",
2122
"dlv": "^1.1.3",

packages/tailwindcss-language-service/src/hoverProvider.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { findClassNameAtPosition } from './util/find'
77
import { validateApply } from './util/validateApply'
88
import { getClassNameParts } from './util/getClassNameAtPosition'
99
import { getDocumentSettings } from './util/getDocumentSettings'
10+
import { getDocsForClassName } from './util/docs'
1011

1112
export async function doHover(
1213
state: State,
@@ -103,10 +104,19 @@ async function provideClassNameHover(
103104

104105
if (!css) return null
105106

107+
const docs = await getDocsForClassName(parts[parts.length - 1], 200)
108+
106109
return {
107110
contents: {
108-
language: 'css',
109-
value: css,
111+
kind: 'markdown',
112+
value: [
113+
'```css',
114+
css,
115+
'```',
116+
...(docs
117+
? ['', '---', '', `[Tailwind CSS Documentation](${docs.url})`]
118+
: []),
119+
].join('\n'),
110120
},
111121
range: className.range,
112122
}

packages/tailwindcss-language-service/src/util/docs.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import fetch from 'isomorphic-unfetch'
22
import Cache from 'tmp-cache'
3+
import AbortController from 'abort-controller'
4+
5+
interface Doc {
6+
title: string
7+
url: string
8+
}
39

410
const cache = new Cache(30)
511

@@ -52,3 +58,57 @@ export async function searchDocs(
5258
: {}),
5359
}))
5460
}
61+
62+
const classNameCache = {}
63+
64+
export async function getDocsForClassName(
65+
className: string,
66+
timeoutMs?: number
67+
): Promise<Doc | undefined> {
68+
if (classNameCache[className]) return classNameCache[className]
69+
70+
let hit
71+
const controller = new AbortController()
72+
const timeout = timeoutMs
73+
? setTimeout(() => controller.abort(), timeoutMs)
74+
: undefined
75+
76+
try {
77+
const hits = await searchDocs(
78+
className,
79+
{
80+
hitsPerPage: 20,
81+
attributesToRetrieve: [
82+
'hierarchy.lvl1',
83+
'hierarchy.lvl4',
84+
'type',
85+
'url',
86+
],
87+
attributesToSnippet: [],
88+
facetFilters: 'version:v2',
89+
distinct: 1,
90+
},
91+
{ signal: controller.signal }
92+
)
93+
94+
hit = hits.find((hit) => {
95+
return (
96+
hit.type === 'lvl4' &&
97+
hit.url.endsWith('#class-reference') &&
98+
hit.hierarchy.lvl4 === className
99+
)
100+
})
101+
} finally {
102+
clearTimeout(timeout)
103+
}
104+
105+
if (hit) {
106+
classNameCache[className] = {
107+
title: hit.hierarchy.lvl1,
108+
url: hit.url.replace(/\/?#class-reference$/, ''),
109+
}
110+
return classNameCache[className]
111+
}
112+
113+
return undefined
114+
}

0 commit comments

Comments
 (0)