From 4a2457d64b311107fe2d70e2a88dba76088ea9c1 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 5 Mar 2024 14:03:33 -0500 Subject: [PATCH 1/2] Perform a soft reload of some project state when editing theme files --- .../src/projects.ts | 38 +++++++++++++++++++ .../tailwindcss-language-server/src/tw.ts | 36 ++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/packages/tailwindcss-language-server/src/projects.ts b/packages/tailwindcss-language-server/src/projects.ts index e0db5a89..67e4d173 100644 --- a/packages/tailwindcss-language-server/src/projects.ts +++ b/packages/tailwindcss-language-server/src/projects.ts @@ -108,6 +108,8 @@ export interface ProjectService { onCodeAction(params: CodeActionParams): Promise onDocumentLinks(params: DocumentLinkParams): DocumentLink[] sortClassLists(classLists: string[]): string[] + + reload(): Promise } export enum DocumentSelectorPriority { @@ -975,6 +977,42 @@ export async function createProjectService( enable() { enabled = true }, + + async reload() { + if (!state.v4) return + + console.log('---- RELOADING DESIGN SYSTEM ----') + let css = await readCssFile(state.configPath) + let designSystem = await loadDesignSystem( + state.modules.tailwindcss.module, + state.configPath, + css, + ) + + // TODO: This is weird and should be changed + // We use Object.create so no global state is mutated until necessary + let pseudoState = Object.create(state, { + designSystem: { + value: designSystem, + }, + }) + + let classList = designSystem.getClassList().map((className) => { + return [ + className[0], + { + ...className[1], + color: getColor(pseudoState, className[0]), + }, + ] + }) + + state.designSystem = designSystem + state.classList = classList as any + + console.log('---- RELOADED ----') + }, + state, documentSelector() { return documentSelector diff --git a/packages/tailwindcss-language-server/src/tw.ts b/packages/tailwindcss-language-server/src/tw.ts index 864455a3..122516ad 100644 --- a/packages/tailwindcss-language-server/src/tw.ts +++ b/packages/tailwindcss-language-server/src/tw.ts @@ -227,6 +227,7 @@ export class TW { changes: Array<{ file: string; type: FileChangeType }>, ): Promise => { let needsRestart = false + let needsSoftRestart = false changeLoop: for (let change of changes) { let normalizedFilename = normalizePath(change.file) @@ -259,6 +260,20 @@ export class TW { } } + for (let [, project] of this.projects) { + if (!project.state.v4) continue + + let reloadableFiles = [ + project.projectConfig.configPath, + ...project.projectConfig.config.entries.map((entry) => entry.path), + ] + + if (!changeAffectsFile(normalizedFilename, reloadableFiles)) continue + + needsSoftRestart = true + break changeLoop + } + let isCssFile = minimatch(normalizedFilename, `**/${CSS_GLOB}`, { dot: true, }) @@ -300,6 +315,15 @@ export class TW { return } + if (needsSoftRestart) { + try { + await this.softRestart() + } catch { + this.restart() + } + return + } + for (let [, project] of this.projects) { project.onFileEvents(changes) } @@ -776,6 +800,18 @@ export class TW { this.initPromise = undefined this.init() } + + async softRestart(): Promise { + // Tell each v4 project to reload it's design system' + for (let [, project] of this.projects) { + if (!project.state.v4) continue + + // "soft"-reload the project + try { + await project.reload() + } catch {} + } + } } function supportsDynamicRegistration(params: InitializeParams): boolean { From ba13c72fdc3103fca4b20d859e0eca2e16a75f29 Mon Sep 17 00:00:00 2001 From: Kris Braun Date: Tue, 5 Mar 2024 14:50:48 -0500 Subject: [PATCH 2/2] Format --- .../tailwindcss-language-server/src/tw.ts | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/packages/tailwindcss-language-server/src/tw.ts b/packages/tailwindcss-language-server/src/tw.ts index 122516ad..74f4bb22 100644 --- a/packages/tailwindcss-language-server/src/tw.ts +++ b/packages/tailwindcss-language-server/src/tw.ts @@ -177,7 +177,7 @@ export class TW { isDefaultVersion: false, }, } - }, + } ) } else { console.log("Searching for Tailwind CSS projects in the workspace's folders.") @@ -224,7 +224,7 @@ export class TW { console.log(`[Global] Creating projects: ${JSON.stringify(workspaceDescription)}`) const onDidChangeWatchedFiles = async ( - changes: Array<{ file: string; type: FileChangeType }>, + changes: Array<{ file: string; type: FileChangeType }> ): Promise => { let needsRestart = false let needsSoftRestart = false @@ -243,12 +243,10 @@ export class TW { for (let [, project] of this.projects) { let twVersion = require('tailwindcss/package.json').version try { - let v = require( - resolveFrom( - path.dirname(project.projectConfig.configPath), - 'tailwindcss/package.json', - ), - ).version + let v = require(resolveFrom( + path.dirname(project.projectConfig.configPath), + 'tailwindcss/package.json' + )).version if (typeof v === 'string') { twVersion = v } @@ -340,11 +338,11 @@ export class TW { .filter( (change, changeIndex, changes) => changes.findIndex((c) => c.file === change.file && c.type === change.type) === - changeIndex, + changeIndex ) await onDidChangeWatchedFiles(normalizedChanges) - }), + }) ) let disposable = await this.connection.client.register( @@ -355,7 +353,7 @@ export class TW { { globPattern: `**/${PACKAGE_LOCK_GLOB}` }, { globPattern: `**/${CSS_GLOB}` }, ], - }, + } ) this.disposables.push(disposable) @@ -384,14 +382,14 @@ export class TW { base, (err, events) => { onDidChangeWatchedFiles( - events.map((event) => ({ file: event.path, type: typeMap[event.type] })), + events.map((event) => ({ file: event.path, type: typeMap[event.type] })) ) }, { ignore: ignore.map((ignorePattern) => - path.resolve(base, ignorePattern.replace(/^[*/]+/, '').replace(/[*/]+$/, '')), + path.resolve(base, ignorePattern.replace(/^[*/]+/, '').replace(/[*/]+$/, '')) ), - }, + } ) this.disposables.push({ @@ -412,7 +410,7 @@ export class TW { stabilityThreshold: 100, pollInterval: 20, }, - }, + } ) await new Promise((resolve) => { @@ -423,17 +421,17 @@ export class TW { .on('add', (file) => onDidChangeWatchedFiles([ { file: path.resolve(base, file), type: FileChangeType.Created }, - ]), + ]) ) .on('change', (file) => onDidChangeWatchedFiles([ { file: path.resolve(base, file), type: FileChangeType.Changed }, - ]), + ]) ) .on('unlink', (file) => onDidChangeWatchedFiles([ { file: path.resolve(base, file), type: FileChangeType.Deleted }, - ]), + ]) ) this.disposables.push({ @@ -457,9 +455,9 @@ export class TW { projectConfig, this.initializeParams, this.watchPatterns, - configTailwindVersionMap.get(projectConfig.configPath), - ), - ), + configTailwindVersionMap.get(projectConfig.configPath) + ) + ) ) // init projects for documents that are _already_ open @@ -489,19 +487,19 @@ export class TW { for (let [, project] of this.projects) { project.onUpdateSettings(settings) } - }), + }) ) this.disposables.push( this.connection.onShutdown(() => { this.dispose() - }), + }) ) this.disposables.push( this.documentService.onDidChangeContent((change) => { this.getProject(change.document)?.provideDiagnostics(change.document) - }), + }) ) this.disposables.push( @@ -511,7 +509,7 @@ export class TW { project.enable() project.tryInit() } - }), + }) ) } @@ -525,7 +523,7 @@ export class TW { projectConfig: ProjectConfig, params: InitializeParams, watchPatterns: (patterns: string[]) => void, - tailwindVersion: string, + tailwindVersion: string ): Promise { let key = String(this.projectCounter++) const project = await createProjectService( @@ -548,7 +546,7 @@ export class TW { () => this.refreshDiagnostics(), (patterns: string[]) => watchPatterns(patterns), tailwindVersion, - this.settingsCache.get, + this.settingsCache.get ) this.projects.set(key, project) @@ -595,11 +593,11 @@ export class TW { private onRequest( method: '@/tailwindCSS/sortSelection', - params: { uri: string; classLists: string[] }, + params: { uri: string; classLists: string[] } ): { error: string } | { classLists: string[] } private onRequest( method: '@/tailwindCSS/getProject', - params: { uri: string }, + params: { uri: string } ): { version: string } | null private onRequest(method: string, params: any): any { if (method === '@/tailwindCSS/sortSelection') { @@ -802,7 +800,7 @@ export class TW { } async softRestart(): Promise { - // Tell each v4 project to reload it's design system' + // Tell each v4 project to reload it's design system for (let [, project] of this.projects) { if (!project.state.v4) continue