From 28b56e0a6c7bb120af018b1a9e36c5f0337759cb Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 5 Sep 2022 03:48:25 +0800 Subject: [PATCH] fix: document features stop working for script block close #1813 --- .../src/documentFeatures/format.ts | 12 ++--- .../src/documentService.ts | 4 +- .../src/utils/sharedLs.ts | 45 ----------------- .../src/utils/singleFileTypeScriptService.ts | 48 +++++++++++++++++++ 4 files changed, 56 insertions(+), 53 deletions(-) delete mode 100644 packages/vue-language-service/src/utils/sharedLs.ts create mode 100644 packages/vue-language-service/src/utils/singleFileTypeScriptService.ts diff --git a/packages/vue-language-service/src/documentFeatures/format.ts b/packages/vue-language-service/src/documentFeatures/format.ts index b8dce4e74..0d71d73dc 100644 --- a/packages/vue-language-service/src/documentFeatures/format.ts +++ b/packages/vue-language-service/src/documentFeatures/format.ts @@ -79,16 +79,16 @@ export function register(context: DocumentServiceRuntimeContext) { let end = sourceMap.getMappedRange(range.end)?.[0].end; if (!start) { - const minSourceStart = Math.min(...sourceMap.base.mappings.map(m => m.sourceRange.start)); - if (document.offsetAt(range.start) <= minSourceStart) { - start = range.start; + const firstMapping = sourceMap.base.mappings.sort((a, b) => a.sourceRange.start - b.sourceRange.start)[0]; + if (document.offsetAt(range.start) < firstMapping.sourceRange.start) { + start = sourceMap.mappedDocument.positionAt(firstMapping.mappedRange.start); } } if (!end) { - const maxSourceEnd = Math.max(...sourceMap.base.mappings.map(m => m.sourceRange.end)); - if (document.offsetAt(range.end) >= maxSourceEnd) { - end = range.end; + const lastMapping = sourceMap.base.mappings.sort((a, b) => b.sourceRange.start - a.sourceRange.start)[0]; + if (document.offsetAt(range.end) > lastMapping.sourceRange.end) { + end = sourceMap.mappedDocument.positionAt(lastMapping.mappedRange.end); } } diff --git a/packages/vue-language-service/src/documentService.ts b/packages/vue-language-service/src/documentService.ts index 811a5d27a..f5327bfde 100644 --- a/packages/vue-language-service/src/documentService.ts +++ b/packages/vue-language-service/src/documentService.ts @@ -20,7 +20,7 @@ import * as linkedEditingRanges from './documentFeatures/linkedEditingRanges'; import * as selectionRanges from './documentFeatures/selectionRanges'; import { getTsSettings } from './tsConfigs'; import { DocumentServiceRuntimeContext } from './types'; -import * as sharedServices from './utils/sharedLs'; +import { getSingleFileTypeScriptService } from './utils/singleFileTypeScriptService'; import { parseVueDocument, VueDocument } from './vueDocuments'; import useAutoWrapParenthesesPlugin from './plugins/vue-autoinsert-parentheses'; import useVuePlugin from './plugins/vue'; @@ -102,7 +102,7 @@ export function getDocumentService( }, updateTsLs(document) { if (isTsDocument(document)) { - tsLs = sharedServices.getDummyTsLs(context.typescript, ts2, document, tsSettings); + tsLs = getSingleFileTypeScriptService(context.typescript, ts2, document, tsSettings); } }, }; diff --git a/packages/vue-language-service/src/utils/sharedLs.ts b/packages/vue-language-service/src/utils/sharedLs.ts deleted file mode 100644 index 95ad51a5d..000000000 --- a/packages/vue-language-service/src/utils/sharedLs.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { TextDocument } from 'vscode-languageserver-textdocument'; -import type * as ts2 from '@volar/typescript-language-service'; -import { URI } from 'vscode-uri'; - -// Fast dummy TS language service, only has one script. -let dummyProjectVersion = 0; -let dummyTsLs: ts2.LanguageService | undefined; -let doc: TextDocument; -let dummyFileName: string; - -export function getDummyTsLs( - ts: typeof import('typescript/lib/tsserverlibrary'), - ts2: typeof import('@volar/typescript-language-service'), - _doc: TextDocument, - settings: ts2.Settings, -): ts2.LanguageService { - if (!dummyTsLs) { - const host: ts.LanguageServiceHost = { - readFile: () => undefined, - fileExists: fileName => fileName === dummyFileName, - getProjectVersion: () => dummyProjectVersion.toString(), - getScriptVersion: () => dummyProjectVersion.toString(), - getCompilationSettings: () => ({ allowJs: true, jsx: ts.JsxEmit.Preserve }), - getScriptFileNames: () => [dummyFileName], - getScriptSnapshot: fileName => { - if (fileName === dummyFileName) { - return ts.ScriptSnapshot.fromString(doc.getText()); - } - }, - getCurrentDirectory: () => '', - getDefaultLibFileName: () => '', - }; - dummyTsLs = ts2.createLanguageService( - ts, - host, - ts.createLanguageService(host), - settings, - URI.file('/'), - ); - } - dummyProjectVersion++; - doc = _doc; - dummyFileName = '/dummy' + _doc.uri.substring(_doc.uri.lastIndexOf('.')); - return dummyTsLs; -} diff --git a/packages/vue-language-service/src/utils/singleFileTypeScriptService.ts b/packages/vue-language-service/src/utils/singleFileTypeScriptService.ts new file mode 100644 index 000000000..497bb5dc5 --- /dev/null +++ b/packages/vue-language-service/src/utils/singleFileTypeScriptService.ts @@ -0,0 +1,48 @@ +import type { TextDocument } from 'vscode-languageserver-textdocument'; +import type * as ts2 from '@volar/typescript-language-service'; +import { URI } from 'vscode-uri'; +import * as shared from '@volar/shared'; + +let projectVersion = 0; +let doc: TextDocument; +let fileName: string; +let scriptSnapshot: ts.IScriptSnapshot; +let service: ts2.LanguageService | undefined; + +const host: ts.LanguageServiceHost = { + readFile: () => undefined, + fileExists: fileName => fileName === fileName, + getProjectVersion: () => projectVersion.toString(), + getScriptVersion: () => projectVersion.toString(), + getCompilationSettings: () => ({ allowJs: true, jsx: 1 }), + getScriptFileNames: () => [fileName], + getScriptSnapshot: fileName => { + if (fileName === fileName) { + return scriptSnapshot; + } + }, + getCurrentDirectory: () => '', + getDefaultLibFileName: () => '', +}; + +export function getSingleFileTypeScriptService( + ts: typeof import('typescript/lib/tsserverlibrary'), + ts2: typeof import('@volar/typescript-language-service'), + _doc: TextDocument, + settings: ts2.Settings, +): ts2.LanguageService { + if (!service) { + service = ts2.createLanguageService( + ts, + host, + ts.createLanguageService(host), + settings, + URI.file('/'), + ); + } + projectVersion++; + doc = _doc; + fileName = shared.getPathOfUri(_doc.uri); + scriptSnapshot = ts.ScriptSnapshot.fromString(doc.getText()); + return service; +}