Browse Source

Do not load lib.d.ts files on the UI thread

Alex Dima 4 years ago
parent
commit
5577502c1c
2 changed files with 30 additions and 23 deletions
  1. 29 22
      src/languageFeatures.ts
  2. 1 1
      src/tsMode.ts

+ 29 - 22
src/languageFeatures.ts

@@ -7,7 +7,6 @@
 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;
@@ -24,16 +23,6 @@ enum IndentStyle {
 	Smart = 2
 }
 
-function getOrCreateLibFile(uri: Uri): monaco.editor.ITextModel | null {
-	let model = monaco.editor.getModel(uri)
-	if (!model) {
-		if (uri.path.indexOf("/lib.") === 0) {
-			return monaco.editor.createModel(libFileMap[uri.path.slice(1)], "javascript", uri)
-		}
-	}
-	return model
-}
-
 export function flattenDiagnosticMessageText(diag: string | ts.DiagnosticMessageChain | undefined, newLine: string, indent = 0): string {
 	if (typeof diag === "string") {
 		return diag;
@@ -106,7 +95,10 @@ export class LibFiles {
 		this._fetchLibFilesPromise = null;
 	}
 
-	public isLibFile(uri: Uri): boolean {
+	public isLibFile(uri: Uri | null): boolean {
+		if (!uri) {
+			return false;
+		}
 		if (uri.path.indexOf("/lib.") === 0) {
 			return !!libFileSet[uri.path.slice(1)];
 		}
@@ -124,7 +116,7 @@ export class LibFiles {
 		return null;
 	}
 
-	private _containsLibFile(uris: Uri[]): boolean {
+	private _containsLibFile(uris: (Uri | null)[]): boolean {
 		for (let uri of uris) {
 			if (this.isLibFile(uri)) {
 				return true;
@@ -133,7 +125,7 @@ export class LibFiles {
 		return false;
 	}
 
-	public async fetchLibFilesIfNecessary(uris: Uri[]): Promise<void> {
+	public async fetchLibFilesIfNecessary(uris: (Uri | null)[]): Promise<void> {
 		if (!this._containsLibFile(uris)) {
 			// no lib files necessary
 			return;
@@ -170,7 +162,10 @@ export class DiagnosticsAdapter extends Adapter {
 	private _disposables: IDisposable[] = [];
 	private _listener: { [uri: string]: IDisposable } = Object.create(null);
 
-	constructor(private _defaults: LanguageServiceDefaultsImpl, private _selector: string,
+	constructor(
+		private readonly _libFiles: LibFiles,
+		private _defaults: LanguageServiceDefaultsImpl,
+		private _selector: string,
 		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
 	) {
 		super(worker);
@@ -258,19 +253,31 @@ export class DiagnosticsAdapter extends Adapter {
 			promises.push(worker.getSuggestionDiagnostics(model.uri.toString()));
 		}
 
-		const diagnostics = await Promise.all(promises);
+		const allDiagnostics = await Promise.all(promises);
 
-		if (!diagnostics || model.isDisposed()) {
+		if (!allDiagnostics || model.isDisposed()) {
 			// model was disposed in the meantime
 			return;
 		}
 
-		const markers = diagnostics
+		const diagnostics = allDiagnostics
 			.reduce((p, c) => c.concat(p), [])
-			.filter(d => (this._defaults.getDiagnosticsOptions().diagnosticCodesToIgnore || []).indexOf(d.code) === -1)
-			.map(d => this._convertDiagnostics(model, d));
+			.filter(d => (this._defaults.getDiagnosticsOptions().diagnosticCodesToIgnore || []).indexOf(d.code) === -1);
+
+		// Fetch lib files if necessary
+		const relatedUris = diagnostics
+			.map(d => d.relatedInformation || [])
+			.reduce((p, c) => c.concat(p), [])
+			.map(relatedInformation => relatedInformation.file ? monaco.Uri.parse(relatedInformation.file.fileName) : null);
+
+		await this._libFiles.fetchLibFilesIfNecessary(relatedUris);
+
+		if (model.isDisposed()) {
+			// model was disposed in the meantime
+			return;
+		}
 
-		monaco.editor.setModelMarkers(model, this._selector, markers);
+		monaco.editor.setModelMarkers(model, this._selector, diagnostics.map(d => this._convertDiagnostics(model, d)));
 	}
 
 	private _convertDiagnostics(model: monaco.editor.ITextModel, diag: ts.Diagnostic): monaco.editor.IMarkerData {
@@ -302,7 +309,7 @@ export class DiagnosticsAdapter extends Adapter {
 			let relatedResource: monaco.editor.ITextModel | null = model;
 			if (info.file) {
 				const relatedResourceUri = monaco.Uri.parse(info.file.fileName);
-				relatedResource = getOrCreateLibFile(relatedResourceUri);
+				relatedResource = this._libFiles.getOrCreateModel(relatedResourceUri);
 			}
 
 			if (!relatedResource) {

+ 1 - 1
src/tsMode.ts

@@ -68,7 +68,7 @@ function setupMode(defaults: LanguageServiceDefaultsImpl, modeId: string): (...u
 	monaco.languages.registerOnTypeFormattingEditProvider(modeId, new languageFeatures.FormatOnTypeAdapter(worker));
 	monaco.languages.registerCodeActionProvider(modeId, new languageFeatures.CodeActionAdaptor(worker));
 	monaco.languages.registerRenameProvider(modeId, new languageFeatures.RenameAdapter(worker));
-	new languageFeatures.DiagnosticsAdapter(defaults, modeId, worker);
+	new languageFeatures.DiagnosticsAdapter(libFiles, defaults, modeId, worker);
 
 	return worker;
 }