From f8c70cb50bc4c36d2e9def005852a3b3da64bab1 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Wed, 21 Aug 2024 19:07:55 +0200 Subject: [PATCH 1/2] Revert "fix: undo loop in scanner" This reverts commit 8dbab73d5253283e60496eebbbbfcbb68cf21a21. --- .../language-server/src/workspace-scanner.ts | 24 ++++++++----------- .../src/language-model-cache.ts | 4 ++++ .../src/language-services-types.ts | 2 +- .../src/language-services.ts | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/language-server/src/workspace-scanner.ts b/packages/language-server/src/workspace-scanner.ts index 9003a90d..bec56201 100644 --- a/packages/language-server/src/workspace-scanner.ts +++ b/packages/language-server/src/workspace-scanner.ts @@ -53,22 +53,18 @@ export default class WorkspaceScanner { uri = URI.parse(file.toString().replace("/static/extensions/fs", "")); } - const alreadyParsed = this.#ls.hasCached(uri); - if (alreadyParsed) { - // The same file may be referenced by multiple other files, - // so skip doing the parsing work if it's already been done. - // Changes to the file are handled by the `update` method. - return; - } - try { - // TODO: figure out what caused the loop - const content = await this.#fs.readFile(uri); + let document: TextDocument | null | undefined = + this.#ls.getCachedTextDocument(uri); + if (!document) { + const content = await this.#fs.readFile(uri); - const document = getSCSSRegionsDocument( - TextDocument.create(uri.toString(), "scss", 1, content), - ); - if (!document) return; + document = getSCSSRegionsDocument( + TextDocument.create(uri.toString(), "scss", 1, content), + ); + if (!document) return; + this.#ls.parseStylesheet(document); + } const links = await this.#ls.findDocumentLinks(document); for (const link of links) { diff --git a/packages/language-services/src/language-model-cache.ts b/packages/language-services/src/language-model-cache.ts index 587ed201..23052e5c 100644 --- a/packages/language-services/src/language-model-cache.ts +++ b/packages/language-services/src/language-model-cache.ts @@ -128,6 +128,10 @@ export class LanguageModelCache { return Object.values(this.#languageModels).map((cached) => cached.document); } + getCachedTextDocument(uri: string): TextDocument | undefined { + return this.#languageModels[uri]?.document; + } + has(uri: string) { return typeof this.#languageModels[uri] !== "undefined"; } diff --git a/packages/language-services/src/language-services-types.ts b/packages/language-services/src/language-services-types.ts index c5f4b621..23ead6ba 100644 --- a/packages/language-services/src/language-services-types.ts +++ b/packages/language-services/src/language-services-types.ts @@ -133,7 +133,7 @@ export interface LanguageService { range: Range, context?: CodeActionContext, ): Promise; - hasCached(uri: URI): boolean; + getCachedTextDocument(uri: URI): TextDocument | undefined; /** * Utility function to reparse an updated document. * Like {@link LanguageService.parseStylesheet}, but returns nothing. diff --git a/packages/language-services/src/language-services.ts b/packages/language-services/src/language-services.ts index 8ed28261..c5731c26 100644 --- a/packages/language-services/src/language-services.ts +++ b/packages/language-services/src/language-services.ts @@ -160,8 +160,8 @@ class LanguageServiceImpl implements LanguageService { return this.#findSymbols.findWorkspaceSymbols(query); } - hasCached(uri: URI): boolean { - return this.#cache.has(uri.toString()); + getCachedTextDocument(uri: URI): TextDocument | undefined { + return this.#cache.getCachedTextDocument(uri.toString()); } getColorPresentations(document: TextDocument, color: Color, range: Range) { From eaaa96d1f5d3923ce56ce7e7ca8a5a203e233603 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Sat, 24 Aug 2024 14:09:34 +0200 Subject: [PATCH 2/2] fix: race condition in workspace scanner This time without the infinite loop for workspaces with circular references. --- packages/language-server/src/workspace-scanner.ts | 15 +++++++++++++-- .../language-services/src/language-model-cache.ts | 4 ---- .../language-services/src/language-services.ts | 2 +- vscode-extension/package.json | 4 ++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/language-server/src/workspace-scanner.ts b/packages/language-server/src/workspace-scanner.ts index bec56201..fedfe15f 100644 --- a/packages/language-server/src/workspace-scanner.ts +++ b/packages/language-server/src/workspace-scanner.ts @@ -56,6 +56,7 @@ export default class WorkspaceScanner { try { let document: TextDocument | null | undefined = this.#ls.getCachedTextDocument(uri); + if (!document) { const content = await this.#fs.readFile(uri); @@ -63,10 +64,11 @@ export default class WorkspaceScanner { TextDocument.create(uri.toString(), "scss", 1, content), ); if (!document) return; - this.#ls.parseStylesheet(document); } + this.#ls.parseStylesheet(document); const links = await this.#ls.findDocumentLinks(document); + for (const link of links) { if ( !link.target || @@ -77,8 +79,17 @@ export default class WorkspaceScanner { continue; } + let uri = URI.parse(link.target); + let visited: TextDocument | null | undefined = + this.#ls.getCachedTextDocument(uri); + + if (visited) { + // avoid infinite loop if circular references + continue; + } + try { - await this.parse(URI.parse(link.target), depth + 1); + await this.parse(uri, depth + 1); } catch { // do nothing } diff --git a/packages/language-services/src/language-model-cache.ts b/packages/language-services/src/language-model-cache.ts index 23052e5c..587ed201 100644 --- a/packages/language-services/src/language-model-cache.ts +++ b/packages/language-services/src/language-model-cache.ts @@ -128,10 +128,6 @@ export class LanguageModelCache { return Object.values(this.#languageModels).map((cached) => cached.document); } - getCachedTextDocument(uri: string): TextDocument | undefined { - return this.#languageModels[uri]?.document; - } - has(uri: string) { return typeof this.#languageModels[uri] !== "undefined"; } diff --git a/packages/language-services/src/language-services.ts b/packages/language-services/src/language-services.ts index c5731c26..c9c64839 100644 --- a/packages/language-services/src/language-services.ts +++ b/packages/language-services/src/language-services.ts @@ -161,7 +161,7 @@ class LanguageServiceImpl implements LanguageService { } getCachedTextDocument(uri: URI): TextDocument | undefined { - return this.#cache.getCachedTextDocument(uri.toString()); + return this.#cache.getDocument(uri.toString()); } getColorPresentations(document: TextDocument, color: Color, range: Range) { diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 61e40774..9689e340 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -131,7 +131,7 @@ "build": "webpack --mode development", "start:web": "vscode-test-web --browserType=chromium --extensionDevelopmentPath=.", "lint": "eslint \"**/*.ts\" --cache", - "test:e2e": "node ./test/e2e/runTest.js", + "test:e2e": "node ./test/e2e/runTest.js && node ./test/new-e2e/runTest.js", "pretest:web": "webpack --config ./webpack.test-web.config.js ", "test:web": "node ./test/web/runTest.js" }, @@ -141,4 +141,4 @@ "publisherId": "02638283-c13a-4acf-9f26-24bdcfdfce24", "isPreReleaseVersion": false } -} \ No newline at end of file +}