From 6a18fe651799475a6b0c46ee96c33e5b38d2b624 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 28 Aug 2020 09:58:22 +0200 Subject: [PATCH] Introduce LibFiles and adopt in DefinitionAdapter --- scripts/importTypescript.js | 20 +++++++-- src/languageFeatures.ts | 89 +++++++++++++++++++++++++++++++++++-- src/lib/lib.index.ts | 65 +++++++++++++++++++++++++++ src/tsMode.ts | 4 +- src/tsWorker.ts | 4 ++ 5 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 src/lib/lib.index.ts diff --git a/scripts/importTypescript.js b/scripts/importTypescript.js index fd5302a1..2063e4ac 100644 --- a/scripts/importTypescript.js +++ b/scripts/importTypescript.js @@ -106,7 +106,7 @@ function importLibs() { return fs.readFileSync(srcPath).toString(); } - var strResult = `/*--------------------------------------------------------------------------------------------- + var strLibResult = `/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -115,17 +115,29 @@ ${generatedNote} /** Contains all the lib files */ export const libFileMap: Record = {} ` +; + + var strIndexResult = `/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +${generatedNote} + +/** Contains all the lib files */ +export const libFileSet: Record = {} +` ; var dtsFiles = fs.readdirSync(TYPESCRIPT_LIB_SOURCE).filter(f => f.includes("lib.")); while (dtsFiles.length > 0) { var name = dtsFiles.shift(); var output = readLibFile(name); - strResult += `libFileMap['${name}'] = "${escapeText(output)}";\n`; + strLibResult += `libFileMap['${name}'] = "${escapeText(output)}";\n`; + strIndexResult += `libFileSet['${name}'] = true;\n`; } - var dstPath = path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.ts'); - fs.writeFileSync(dstPath, strResult); + fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.ts'), strLibResult); + fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.index.ts'), strIndexResult); } /** diff --git a/src/languageFeatures.ts b/src/languageFeatures.ts index 342a0329..a2e44807 100644 --- a/src/languageFeatures.ts +++ b/src/languageFeatures.ts @@ -8,6 +8,7 @@ import { LanguageServiceDefaultsImpl } from './monaco.contribution'; import * as ts from './lib/typescriptServices'; import { TypeScriptWorker } from './tsWorker'; import { libFileMap } from "./lib/lib" +import { libFileSet } from "./lib/lib.index" import Uri = monaco.Uri; import Position = monaco.Position; @@ -69,7 +70,7 @@ function displayPartsToString(displayParts: ts.SymbolDisplayPart[] | undefined): export abstract class Adapter { - constructor(protected _worker: (first: Uri, ...more: Uri[]) => Promise) { + constructor(protected _worker: (...uris: Uri[]) => Promise) { } // protected _positionToOffset(model: monaco.editor.ITextModel, position: monaco.IPosition): number { @@ -89,6 +90,72 @@ export abstract class Adapter { } } +// --- lib files + +export class LibFiles { + + private _libFiles: Record; + private _hasFetchedLibFiles: boolean; + private _fetchLibFilesPromise: Promise | null; + + constructor( + private readonly _worker: (...uris: Uri[]) => Promise + ) { + this._libFiles = {}; + this._hasFetchedLibFiles = false; + this._fetchLibFilesPromise = null; + } + + public isLibFile(uri: Uri): boolean { + if (uri.path.indexOf("/lib.") === 0) { + return !!libFileSet[uri.path.slice(1)]; + } + return false; + } + + public getOrCreateModel(uri: Uri): monaco.editor.ITextModel | null { + const model = monaco.editor.getModel(uri); + if (model) { + return model; + } + if (this.isLibFile(uri) && this._hasFetchedLibFiles) { + return monaco.editor.createModel(this._libFiles[uri.path.slice(1)], "javascript", uri); + } + return null; + } + + private _containsLibFile(uris: Uri[]): boolean { + for (let uri of uris) { + if (this.isLibFile(uri)) { + return true; + } + } + return false; + } + + public async fetchLibFilesIfNecessary(uris: Uri[]): Promise { + if (!this._containsLibFile(uris)) { + // no lib files necessary + return; + } + await this._fetchLibFiles(); + } + + private _fetchLibFiles(): Promise { + if (!this._fetchLibFilesPromise) { + this._fetchLibFilesPromise = ( + this._worker() + .then(w => w.getLibFiles()) + .then((libFiles) => { + this._hasFetchedLibFiles = true; + this._libFiles = libFiles; + }) + ); + } + return this._fetchLibFilesPromise; + } +} + // --- diagnostics --- --- enum DiagnosticCategory { @@ -104,7 +171,7 @@ export class DiagnosticsAdapter extends Adapter { private _listener: { [uri: string]: IDisposable } = Object.create(null); constructor(private _defaults: LanguageServiceDefaultsImpl, private _selector: string, - worker: (first: Uri, ...more: Uri[]) => Promise + worker: (...uris: Uri[]) => Promise ) { super(worker); @@ -490,6 +557,13 @@ export class OccurrencesAdapter extends Adapter implements monaco.languages.Docu export class DefinitionAdapter extends Adapter { + constructor( + private readonly _libFiles: LibFiles, + worker: (...uris: Uri[]) => Promise + ) { + super(worker); + } + public async provideDefinition(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise { const resource = model.uri; const offset = model.getOffsetAt(position); @@ -500,10 +574,17 @@ export class DefinitionAdapter extends Adapter { return; } + // Fetch lib files if necessary + await this._libFiles.fetchLibFilesIfNecessary(entries.map(entry => Uri.parse(entry.fileName))); + + if (model.isDisposed()) { + return; + } + const result: monaco.languages.Location[] = []; for (let entry of entries) { const uri = Uri.parse(entry.fileName); - const refModel = getOrCreateLibFile(uri); + const refModel = this._libFiles.getOrCreateModel(uri); if (refModel) { result.push({ uri: uri, @@ -712,7 +793,7 @@ export class CodeActionAdaptor extends FormatHelper implements monaco.languages. const codeFixes = await worker.getCodeFixesAtPosition(resource.toString(), start, end, errorCodes, formatOptions); if (!codeFixes || model.isDisposed()) { - return { actions: [], dispose:() => {} }; + return { actions: [], dispose: () => { } }; } const actions = codeFixes.filter(fix => { diff --git a/src/lib/lib.index.ts b/src/lib/lib.index.ts new file mode 100644 index 00000000..d3566b74 --- /dev/null +++ b/src/lib/lib.index.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// +// **NOTE**: Do not edit directly! This file is generated using `npm run import-typescript` +// + + +/** Contains all the lib files */ +export const libFileSet: Record = {} +libFileSet['lib.d.ts'] = true; +libFileSet['lib.dom.d.ts'] = true; +libFileSet['lib.dom.iterable.d.ts'] = true; +libFileSet['lib.es2015.collection.d.ts'] = true; +libFileSet['lib.es2015.core.d.ts'] = true; +libFileSet['lib.es2015.d.ts'] = true; +libFileSet['lib.es2015.generator.d.ts'] = true; +libFileSet['lib.es2015.iterable.d.ts'] = true; +libFileSet['lib.es2015.promise.d.ts'] = true; +libFileSet['lib.es2015.proxy.d.ts'] = true; +libFileSet['lib.es2015.reflect.d.ts'] = true; +libFileSet['lib.es2015.symbol.d.ts'] = true; +libFileSet['lib.es2015.symbol.wellknown.d.ts'] = true; +libFileSet['lib.es2016.array.include.d.ts'] = true; +libFileSet['lib.es2016.d.ts'] = true; +libFileSet['lib.es2016.full.d.ts'] = true; +libFileSet['lib.es2017.d.ts'] = true; +libFileSet['lib.es2017.full.d.ts'] = true; +libFileSet['lib.es2017.intl.d.ts'] = true; +libFileSet['lib.es2017.object.d.ts'] = true; +libFileSet['lib.es2017.sharedmemory.d.ts'] = true; +libFileSet['lib.es2017.string.d.ts'] = true; +libFileSet['lib.es2017.typedarrays.d.ts'] = true; +libFileSet['lib.es2018.asyncgenerator.d.ts'] = true; +libFileSet['lib.es2018.asynciterable.d.ts'] = true; +libFileSet['lib.es2018.d.ts'] = true; +libFileSet['lib.es2018.full.d.ts'] = true; +libFileSet['lib.es2018.intl.d.ts'] = true; +libFileSet['lib.es2018.promise.d.ts'] = true; +libFileSet['lib.es2018.regexp.d.ts'] = true; +libFileSet['lib.es2019.array.d.ts'] = true; +libFileSet['lib.es2019.d.ts'] = true; +libFileSet['lib.es2019.full.d.ts'] = true; +libFileSet['lib.es2019.object.d.ts'] = true; +libFileSet['lib.es2019.string.d.ts'] = true; +libFileSet['lib.es2019.symbol.d.ts'] = true; +libFileSet['lib.es2020.bigint.d.ts'] = true; +libFileSet['lib.es2020.d.ts'] = true; +libFileSet['lib.es2020.full.d.ts'] = true; +libFileSet['lib.es2020.promise.d.ts'] = true; +libFileSet['lib.es2020.string.d.ts'] = true; +libFileSet['lib.es2020.symbol.wellknown.d.ts'] = true; +libFileSet['lib.es5.d.ts'] = true; +libFileSet['lib.es6.d.ts'] = true; +libFileSet['lib.esnext.array.d.ts'] = true; +libFileSet['lib.esnext.asynciterable.d.ts'] = true; +libFileSet['lib.esnext.bigint.d.ts'] = true; +libFileSet['lib.esnext.d.ts'] = true; +libFileSet['lib.esnext.full.d.ts'] = true; +libFileSet['lib.esnext.intl.d.ts'] = true; +libFileSet['lib.esnext.symbol.d.ts'] = true; +libFileSet['lib.scripthost.d.ts'] = true; +libFileSet['lib.webworker.d.ts'] = true; +libFileSet['lib.webworker.importscripts.d.ts'] = true; diff --git a/src/tsMode.ts b/src/tsMode.ts index efc95412..dc0e391b 100644 --- a/src/tsMode.ts +++ b/src/tsMode.ts @@ -55,11 +55,13 @@ function setupMode(defaults: LanguageServiceDefaultsImpl, modeId: string): (...u return client.getLanguageServiceWorker(...uris); }; + const libFiles = new languageFeatures.LibFiles(worker); + monaco.languages.registerCompletionItemProvider(modeId, new languageFeatures.SuggestAdapter(worker)); monaco.languages.registerSignatureHelpProvider(modeId, new languageFeatures.SignatureHelpAdapter(worker)); monaco.languages.registerHoverProvider(modeId, new languageFeatures.QuickInfoAdapter(worker)); monaco.languages.registerDocumentHighlightProvider(modeId, new languageFeatures.OccurrencesAdapter(worker)); - monaco.languages.registerDefinitionProvider(modeId, new languageFeatures.DefinitionAdapter(worker)); + monaco.languages.registerDefinitionProvider(modeId, new languageFeatures.DefinitionAdapter(libFiles, worker)); monaco.languages.registerReferenceProvider(modeId, new languageFeatures.ReferenceAdapter(worker)); monaco.languages.registerDocumentSymbolProvider(modeId, new languageFeatures.OutlineAdapter(worker)); monaco.languages.registerDocumentRangeFormattingEditProvider(modeId, new languageFeatures.FormatAdapter(worker)); diff --git a/src/tsWorker.ts b/src/tsWorker.ts index 8067bca0..e403e758 100644 --- a/src/tsWorker.ts +++ b/src/tsWorker.ts @@ -145,6 +145,10 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language return fileName === this.getDefaultLibFileName(this._compilerOptions); } + getLibFiles(): Promise> { + return Promise.resolve(libFileMap); + } + // --- language features private static clearFiles(diagnostics: ts.Diagnostic[]): monaco.languages.typescript.Diagnostic[] {