Skip to content

Don't register ability to hover, request colors, etc… more than once #1378

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

Merged
merged 3 commits into from
May 20, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions packages/tailwindcss-language-server/src/tw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ export class TW {
}
}

if (results.some((result) => result.status === 'fulfilled')) {
await this.updateCommonCapabilities()
}

await this.listenForEvents()
}

Expand Down Expand Up @@ -628,8 +632,6 @@ export class TW {

console.log(`[Global] Initializing projects...`)

await this.updateCommonCapabilities()

// init projects for documents that are _already_ open
let readyDocuments: string[] = []
let enabledProjectCount = 0
Expand Down Expand Up @@ -896,6 +898,7 @@ export class TW {
capabilities.add(DidChangeConfigurationNotification.type, undefined)
}

this.commonRegistrations?.dispose()
this.commonRegistrations = await this.connection.client.register(capabilities)
}

Expand All @@ -907,7 +910,7 @@ export class TW {
}

private lastTriggerCharacters: Set<string> | undefined
private completionRegistration: Disposable | undefined
private completionRegistration: Promise<Disposable> | undefined
private async updateTriggerCharacters() {
// If the client does not suppory dynamic registration of completions then
// we cannot update the set of trigger characters
Expand Down Expand Up @@ -938,12 +941,27 @@ export class TW {

this.lastTriggerCharacters = chars

this.completionRegistration?.dispose()
this.completionRegistration = await this.connection.client.register(CompletionRequest.type, {
let current = this.completionRegistration
this.completionRegistration = this.connection.client.register(CompletionRequest.type, {
documentSelector: null,
resolveProvider: true,
triggerCharacters: Array.from(chars),
})

// NOTE:
// This weird setup works around a race condition where multiple projects
// with different separators update their capabilities at the same time. It
// is extremely unlikely but it could cause `CompletionRequest` to be
// registered more than once with the LSP client.
//
// We store the promises meaning everything up to this point is synchronous
// so it should be fine but really the proper fix here is to:
// - Refactor workspace folder initialization so discovery, initialization,
// file events, config watchers, etc… are all shared.
// - Remove the need for the "restart" concept in the server for as much as
// possible. Each project should be capable of reloading its modules.
await current?.then((r) => r.dispose())
await this.completionRegistration
}

private getProject(document: TextDocumentIdentifier): ProjectService {
Expand Down Expand Up @@ -1134,7 +1152,7 @@ export class TW {
this.commonRegistrations = undefined

this.lastTriggerCharacters.clear()
this.completionRegistration?.dispose()
this.completionRegistration?.then((r) => r.dispose())
this.completionRegistration = undefined

this.disposables.forEach((d) => d.dispose())
Expand Down