Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: annotation support to highlight valid's className #1142

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions packages/tailwindcss-language-server/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function getDefaultSettings(): Settings {
classAttributes: ['class', 'className', 'ngClass', 'class:list'],
codeActions: true,
hovers: true,
annotations: false,
suggestions: true,
validate: true,
colorDecorators: true,
Expand Down
27 changes: 26 additions & 1 deletion packages/tailwindcss-language-server/src/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
DocumentLink,
} from 'vscode-languageserver/node'
import { FileChangeType } from 'vscode-languageserver/node'
import type { TextDocument } from 'vscode-languageserver-textdocument'
import type { Range, TextDocument } from 'vscode-languageserver-textdocument'
import { URI } from 'vscode-uri'
import { showError, showWarning, SilentError } from './util/error'
import * as path from 'node:path'
Expand All @@ -35,6 +35,7 @@ import stackTrace from 'stack-trace'
import extractClassNames from './lib/extractClassNames'
import { klona } from 'klona/full'
import { doHover } from '@tailwindcss/language-service/src/hoverProvider'
import { updateAnnotation } from '@tailwindcss/language-service/src/annotation'
import { Resolver } from './resolver'
import {
doComplete,
Expand Down Expand Up @@ -106,6 +107,7 @@ export interface ProjectService {
onCompletionResolve(item: CompletionItem): Promise<CompletionItem>
provideDiagnostics(document: TextDocument): void
provideDiagnosticsForce(document: TextDocument): void
provideAnnotations(document: TextDocument): Promise<Range[]>
onDocumentColor(params: DocumentColorParams): Promise<ColorInformation[]>
onColorPresentation(params: ColorPresentationParams): Promise<ColorPresentation[]>
onCodeAction(params: CodeActionParams): Promise<CodeAction[]>
Expand Down Expand Up @@ -480,6 +482,9 @@ export async function createProjectService(
postcss: { version: null, module: null },
resolveConfig: { module: null },
loadConfig: { module: null },
defaultExtractor: {
module: require('tailwindcss/lib/lib/defaultExtractor').defaultExtractor,
},
}

return tryRebuild()
Expand Down Expand Up @@ -693,6 +698,9 @@ export async function createProjectService(
postcss: { version: null, module: null },
resolveConfig: { module: null },
loadConfig: { module: null },
defaultExtractor: {
module: require('tailwindcss/lib/lib/defaultExtractor').defaultExtractor,
},
}

return tryRebuild()
Expand Down Expand Up @@ -733,6 +741,9 @@ export async function createProjectService(
loadConfig: { module: loadConfigFn },
transformThemeValue: { module: transformThemeValueFn },
jit: jitModules,
defaultExtractor: {
module: require('tailwindcss/lib/lib/defaultExtractor').defaultExtractor,
},
}
state.browserslist = browserslist
state.featureFlags = featureFlags
Expand Down Expand Up @@ -1231,6 +1242,20 @@ export async function createProjectService(
if (!state.enabled) return
provideDiagnostics(state, document)
},
provideAnnotations: async (params) => {
try {
if (!state.enabled) return []
let document = documentService.getDocument(params.uri)
if (!document) return []
let settings = await state.editor.getConfiguration(document.uri)
if (!settings.tailwindCSS.annotations) return []
if (await isExcluded(state, document)) return []
return updateAnnotation(state, params)
} catch (error) {
console.error(error)
return []
}
},
async onDocumentColor(params: DocumentColorParams): Promise<ColorInformation[]> {
return withFallback(async () => {
if (!state.enabled) return []
Expand Down
31 changes: 31 additions & 0 deletions packages/tailwindcss-language-server/src/tw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,16 @@ export class TW {
this.disposables.push(
this.documentService.onDidChangeContent((change) => {
this.getProject(change.document)?.provideDiagnostics(change.document)

const { document } = change
this.getProject(document)
?.provideAnnotations(document)
.then((annotations) => {
this.connection.sendRequest('@/tailwindCSS/annotations', {
uri: document.uri,
annotations,
})
})
}),
)

Expand All @@ -644,9 +654,30 @@ export class TW {
await this.connection.sendNotification('@/tailwindCSS/documentReady', {
uri: event.document.uri,
})

const { document } = event
this.getProject(document)
?.provideAnnotations(document)
.then((annotations) => {
this.connection.sendRequest('@/tailwindCSS/annotations', {
uri: document.uri,
annotations,
})
})
}),
)

this.documentService.getAllDocuments().forEach((document) => {
this.getProject(document)
?.provideAnnotations(document)
.then((annotations) => {
this.connection.sendRequest('@/tailwindCSS/annotations', {
uri: document.uri,
annotations,
})
})
})

if (this.initializeParams.capabilities.workspace.workspaceFolders) {
this.disposables.push(
this.connection.workspace.onDidChangeWorkspaceFolders(async (evt) => {
Expand Down
51 changes: 51 additions & 0 deletions packages/tailwindcss-language-service/src/annotation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { Range, TextDocument } from 'vscode-languageserver-textdocument'
import type { State } from './util/state'

export async function updateAnnotation(state: State, document: TextDocument): Promise<Range[]> {
const text = document.getText()

const extractorContext = {
tailwindConfig: {
separator: '-',
prefix: '',
},
}
if (state.jitContext?.tailwindConfig?.separator) {
extractorContext.tailwindConfig.separator = state.jitContext.tailwindConfig.separator
}
if (state.jitContext?.tailwindConfig?.prefix) {
extractorContext.tailwindConfig.prefix = state.jitContext.tailwindConfig.prefix
}

const classNames = state.modules.defaultExtractor.module(extractorContext)(text) as string[]

const result: Range[] = []

if (state.v4) {
const rules = state.designSystem.compile(classNames)

let index = 0
classNames.forEach((className, i) => {
const start = text.indexOf(className, index)
const end = start + className.length
if (rules.at(i).nodes.length > 0 && start !== -1) {
result.push({ start: document.positionAt(start), end: document.positionAt(end) })
}
index = end
})
} else if (state.jit) {
const rules = state.modules.jit.generateRules.module(classNames, state.jitContext)

let index = 0
classNames.forEach((className) => {
const start = text.indexOf(className, index)
const end = start + className.length
if (rules?.find(([, i]) => (i.raws.tailwind as any)?.candidate === className)) {
result.push({ start: document.positionAt(start), end: document.positionAt(end) })
}
index = end
})
}

return result
}
2 changes: 2 additions & 0 deletions packages/tailwindcss-language-service/src/util/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type TailwindCssSettings = {
classAttributes: string[]
suggestions: boolean
hovers: boolean
annotations: boolean
codeActions: boolean
validate: boolean
showPixelEquivalents: boolean
Expand Down Expand Up @@ -124,6 +125,7 @@ export interface State {
expandApplyAtRules: { module: any }
evaluateTailwindFunctions?: { module: any }
}
defaultExtractor: { module: any }
}

v4?: boolean
Expand Down
6 changes: 6 additions & 0 deletions packages/vscode-tailwindcss/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@
"markdownDescription": "Enable hovers.",
"scope": "language-overridable"
},
"tailwindCSS.annotations": {
"type": "boolean",
"default": false,
"markdownDescription": "Enable annotations.",
"scope": "language-overridable"
},
"tailwindCSS.codeActions": {
"type": "boolean",
"default": true,
Expand Down
13 changes: 13 additions & 0 deletions packages/vscode-tailwindcss/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
Position,
Range,
RelativePattern,
DecorationRangeBehavior,
} from 'vscode'
import type {
DocumentFilter,
Expand Down Expand Up @@ -356,6 +357,13 @@ export async function activate(context: ExtensionContext) {

context.subscriptions.push(colorDecorationType)

let underlineDecorationType = Window.createTextEditorDecorationType({
textDecoration: 'none; border-bottom: 1px dashed currentColor',
rangeBehavior: DecorationRangeBehavior.ClosedClosed,
})

context.subscriptions.push(underlineDecorationType)

/**
* Clear all decorated colors from all visible text editors
*/
Expand Down Expand Up @@ -537,6 +545,11 @@ export async function activate(context: ExtensionContext) {
client.onNotification('@/tailwindCSS/projectInitialized', updateActiveTextEditorContext)
client.onNotification('@/tailwindCSS/projectReset', updateActiveTextEditorContext)
client.onNotification('@/tailwindCSS/projectsDestroyed', resetActiveTextEditorContext)
client.onRequest('@/tailwindCSS/annotations', ({ uri, annotations }) => {
Window.visibleTextEditors
.find((editor) => editor.document.uri.toString() === uri)
?.setDecorations(underlineDecorationType, annotations)
})
client.onRequest('@/tailwindCSS/getDocumentSymbols', showSymbols)

interface ErrorNotification {
Expand Down