Skip to content

Commit 8ab4c5a

Browse files
committed
wip
1 parent 32cac12 commit 8ab4c5a

File tree

6 files changed

+119
-13
lines changed

6 files changed

+119
-13
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Position } from 'vscode-languageserver'
22
import type { TextDocument } from 'vscode-languageserver-textdocument'
3-
import { isVueDoc, isSvelteDoc, isHtmlDoc } from './html'
3+
import { isVueDoc, isSvelteDoc, isHtmlDoc, isAstroDoc } from './html'
44
import { isJsDoc } from './js'
55
import type { State } from './state'
66
import { cssLanguages } from './languages'
@@ -27,7 +27,13 @@ export function isCssContext(state: State, doc: TextDocument, position: Position
2727
return true
2828
}
2929

30-
if (isHtmlDoc(state, doc) || isVueDoc(doc) || isSvelteDoc(doc) || isJsDoc(state, doc)) {
30+
if (
31+
isHtmlDoc(state, doc) ||
32+
isVueDoc(doc) ||
33+
isSvelteDoc(doc) ||
34+
isJsDoc(state, doc) ||
35+
isAstroDoc(doc)
36+
) {
3137
let str = doc.getText({
3238
start: { line: 0, character: 0 },
3339
end: position,

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { TextDocument } from 'vscode-languageserver-textdocument'
33
import type { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
44
import lineColumn from 'line-column'
55
import { isCssContext, isCssDoc } from './css'
6-
import { isHtmlContext, isVueDoc } from './html'
6+
import { isAstroDoc, isHtmlContext, isVueDoc } from './html'
77
import { isWithinRange } from './isWithinRange'
88
import { isJsContext } from './js'
99
import { dedupeByRange, flatten } from './array'
@@ -617,6 +617,26 @@ export async function findClassNameAtPosition(
617617
}),
618618
)
619619

620+
classNames = dedupeByRange(flatten(groups)).flatMap((classList) =>
621+
getClassNamesInClassList(classList, state.blocklist),
622+
)
623+
} else if (isAstroDoc(doc)) {
624+
let boundaries = getLanguageBoundaries(state, doc)
625+
626+
let groups = await Promise.all(
627+
boundaries.map(async ({ type, range }) => {
628+
if (type === 'html') {
629+
return await findClassListsInRange(state, doc, range, 'html')
630+
}
631+
632+
if (type === 'js' || type === 'jsx') {
633+
return await findClassListsInRange(state, doc, range, 'jsx')
634+
}
635+
636+
return []
637+
}),
638+
)
639+
620640
classNames = dedupeByRange(flatten(groups)).flatMap((classList) =>
621641
getClassNamesInClassList(classList, state.blocklist),
622642
)

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

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Range } from 'vscode-languageserver'
22
import type { TextDocument } from 'vscode-languageserver-textdocument'
3-
import { isVueDoc, isHtmlDoc, isSvelteDoc } from './html'
3+
import { isVueDoc, isHtmlDoc, isSvelteDoc, isAstroDoc } from './html'
44
import type { State } from './state'
55
import { indexToPosition } from './find'
66
import { isJsDoc } from './js'
@@ -134,8 +134,25 @@ let vueStates = {
134134
},
135135
}
136136

137+
let astroStates = {
138+
...states,
139+
main: {
140+
htmlBlockStart: { push: 'htmlBlock' },
141+
...states.main,
142+
jsBlockStart: { match: '---', push: 'script' },
143+
},
144+
script: {
145+
htmlBlockStart: { match: '---', push: 'html' },
146+
...text,
147+
},
148+
html: {
149+
...text,
150+
},
151+
}
152+
137153
let defaultLexer = moo.states(states)
138154
let vueLexer = moo.states(vueStates)
155+
let astroLexer = moo.states(astroStates)
139156

140157
let cache = new Cache<string, LanguageBoundary[] | null>({ max: 25, maxAge: 1000 })
141158

@@ -157,13 +174,15 @@ export function getLanguageBoundaries(
157174

158175
let isJs = isJsDoc(state, doc)
159176

160-
let defaultType = isVueDoc(doc)
161-
? 'none'
162-
: isHtmlDoc(state, doc) || isSvelteDoc(doc)
163-
? 'html'
164-
: isJs
165-
? 'jsx'
166-
: null
177+
let defaultType: string | null = null
178+
179+
if (isVueDoc(doc) || isAstroDoc(doc)) {
180+
defaultType = 'none'
181+
} else if (isHtmlDoc(state, doc) || isSvelteDoc(doc)) {
182+
defaultType = 'html'
183+
} else if (isJs) {
184+
defaultType = 'jsx'
185+
}
167186

168187
if (defaultType === null) {
169188
cache.set(cacheKey, null)
@@ -172,17 +191,28 @@ export function getLanguageBoundaries(
172191

173192
text = getTextWithoutComments(text, isJs ? 'js' : 'html')
174193

175-
let lexer = defaultType === 'none' ? vueLexer : defaultLexer
194+
let lexer = defaultLexer
195+
196+
if (defaultType === 'none') {
197+
if (isVueDoc(doc)) {
198+
lexer = vueLexer
199+
} else if (isAstroDoc(doc)) {
200+
lexer = astroLexer
201+
}
202+
}
203+
176204
lexer.reset(text)
177205

178206
let type = defaultType
179207
let boundaries: LanguageBoundary[] = [
180208
{ type: defaultType, range: { start: { line: 0, character: 0 }, end: undefined } },
181209
]
210+
182211
let offset = 0
183212

184213
try {
185214
for (let token of lexer) {
215+
console.log({ token })
186216
if (!token.type.startsWith('nested')) {
187217
if (token.type.endsWith('BlockStart')) {
188218
let position = indexToPosition(text, offset)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ export function isSvelteDoc(doc: TextDocument): boolean {
2020
return doc.languageId === 'svelte'
2121
}
2222

23+
export function isAstroDoc(doc: TextDocument): boolean {
24+
return doc.languageId === 'astro'
25+
}
26+
2327
export function isHtmlContext(state: State, doc: TextDocument, position: Position): boolean {
2428
let str = doc.getText({
2529
start: { line: 0, character: 0 },

packages/tailwindcss-language-service/src/util/language-boundaries.test.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test } from 'vitest'
22
import { getLanguageBoundaries } from './getLanguageBoundaries'
3-
import { jsx, createDocument, html } from './test-utils'
3+
import { jsx, createDocument, html, astro } from './test-utils'
44

55
test('regex literals are ignored when determining language boundaries', ({ expect }) => {
66
let file = createDocument({
@@ -189,3 +189,48 @@ test('Vue files detect <template>, <script>, and <style> as separate boundaries'
189189
},
190190
])
191191
})
192+
193+
test('Astro files default to HTML', ({ expect }) => {
194+
let file = createDocument({
195+
name: 'file.astro',
196+
lang: 'astro',
197+
content: html`<div class="border-gray-200"></div>`,
198+
})
199+
200+
let boundaries = getLanguageBoundaries(file.state, file.doc)
201+
202+
expect(boundaries).toEqual([
203+
{
204+
type: 'none',
205+
range: {
206+
start: { line: 0, character: 0 },
207+
end: { line: 0, character: 35 },
208+
},
209+
},
210+
])
211+
})
212+
213+
test.only('Astro files front matter is pared as JS', ({ expect }) => {
214+
let file = createDocument({
215+
name: 'file.astro',
216+
lang: 'astro',
217+
content: astro`
218+
---
219+
console.log('test')
220+
---
221+
<div class="border-gray-200"></div>
222+
`,
223+
})
224+
225+
let boundaries = getLanguageBoundaries(file.state, file.doc)
226+
227+
expect(boundaries).toEqual([
228+
{
229+
type: 'none',
230+
range: {
231+
start: { line: 0, character: 0 },
232+
end: { line: 3, character: 35 },
233+
},
234+
},
235+
])
236+
})

packages/tailwindcss-language-service/src/util/test-utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export const ts: Dedent = dedent
99
export const tsx: Dedent = dedent
1010
export const css: Dedent = dedent
1111
export const html: Dedent = dedent
12+
export const astro: Dedent = dedent
1213
export const pug: Dedent = dedent
1314

1415
export function createDocument({

0 commit comments

Comments
 (0)