瀏覽代碼

Introduce LibFiles and adopt in DefinitionAdapter

Alex Dima 4 年之前
父節點
當前提交
6a18fe6517
共有 5 個文件被更改,包括 173 次插入9 次删除
  1. 16 4
      scripts/importTypescript.js
  2. 85 4
      src/languageFeatures.ts
  3. 65 0
      src/lib/lib.index.ts
  4. 3 1
      src/tsMode.ts
  5. 4 0
      src/tsWorker.ts

+ 16 - 4
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<string, string> = {}
 `
+;
+
+	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<string, boolean> = {}
+`
 ;
 
 	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);
 }
 
 /**

+ 85 - 4
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<TypeScriptWorker>) {
+	constructor(protected _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>) {
 	}
 
 	// 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<string, string>;
+	private _hasFetchedLibFiles: boolean;
+	private _fetchLibFilesPromise: Promise<void> | null;
+
+	constructor(
+		private readonly _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
+	) {
+		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<void> {
+		if (!this._containsLibFile(uris)) {
+			// no lib files necessary
+			return;
+		}
+		await this._fetchLibFiles();
+	}
+
+	private _fetchLibFiles(): Promise<void> {
+		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<TypeScriptWorker>
+		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
 	) {
 		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<TypeScriptWorker>
+	) {
+		super(worker);
+	}
+
 	public async provideDefinition(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.Definition | undefined> {
 		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 => {

+ 65 - 0
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<string, boolean> = {}
+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;

+ 3 - 1
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));

+ 4 - 0
src/tsWorker.ts

@@ -145,6 +145,10 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
 		return fileName === this.getDefaultLibFileName(this._compilerOptions);
 	}
 
+	getLibFiles(): Promise<Record<string, string>> {
+		return Promise.resolve(libFileMap);
+	}
+
 	// --- language features
 
 	private static clearFiles(diagnostics: ts.Diagnostic[]): monaco.languages.typescript.Diagnostic[] {