1
0
Alex Dima 6 жил өмнө
parent
commit
6b2271c1c1

+ 1 - 11
scripts/bundle.js

@@ -29,8 +29,6 @@ bundleOne('monaco.contribution');
 bundleOne('tsMode');
 bundleOne('tsWorker');
 
-updateImports('monaco.contribution');
-
 function bundleOne(moduleId, exclude) {
 	requirejs.optimize({
 		baseUrl: 'release/dev/',
@@ -38,8 +36,7 @@ function bundleOne(moduleId, exclude) {
 		out: 'release/min/' + moduleId + '.js',
 		exclude: exclude,
 		paths: {
-			'vs/language/typescript': REPO_ROOT + '/release/dev',
-			'vs/basic-languages': REPO_ROOT + '/node_modules/monaco-languages/release/dev'
+			'vs/language/typescript': REPO_ROOT + '/release/dev'
 		},
 		optimize: 'none'
 	}, function(buildResponse) {
@@ -56,10 +53,3 @@ function bundleOne(moduleId, exclude) {
 		fs.writeFileSync(filePath, BUNDLED_FILE_HEADER + result.code);
 	})
 }
-
-function updateImports(moduleId) {
-	const filePath = path.join(REPO_ROOT, 'release/esm/' + moduleId + '.js');
-	let fileContents = fs.readFileSync(filePath).toString();
-	fileContents = fileContents.replace(/vs\/basic-languages\//g, "../../basic-languages/");
-	fs.writeFileSync(filePath, fileContents);
-}

+ 4 - 3
src/languageFeatures.ts

@@ -134,15 +134,16 @@ export class DiagnostcsAdapter extends Adapter {
 				}
 			}
 		});
-		const redoDiagosticsCallback = () => {
+
+		const recomputeDiagostics = () => {
 			// redo diagnostics when options change
 			for (const model of monaco.editor.getModels()) {
 				onModelRemoved(model);
 				onModelAdd(model);
 			}
 		};
-		this._disposables.push(this._defaults.onDidChange(redoDiagosticsCallback));
-		this._disposables.push(this._defaults.onDidExtraLibsChange(redoDiagosticsCallback));
+		this._disposables.push(this._defaults.onDidChange(recomputeDiagostics));
+		this._disposables.push(this._defaults.onDidExtraLibsChange(recomputeDiagostics));
 
 		monaco.editor.getModels().forEach(onModelAdd);
 	}

+ 70 - 123
src/monaco.contribution.ts

@@ -5,8 +5,6 @@
 'use strict';
 
 import * as mode from './tsMode';
-import * as tsDefinitions from 'vs/basic-languages/typescript/typescript';
-import * as jsDefinitions from 'vs/basic-languages/javascript/javascript';
 
 import Emitter = monaco.Emitter;
 import IEvent = monaco.IEvent;
@@ -14,41 +12,45 @@ import IDisposable = monaco.IDisposable;
 
 // --- TypeScript configuration and defaults ---------
 
+export interface IExtraLib {
+	content: string;
+	version: number;
+}
+
+export interface IExtraLibs {
+	[path: string]: IExtraLib;
+}
+
 export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.LanguageServiceDefaults {
 
-	private _onDidChange = new Emitter<monaco.languages.typescript.LanguageServiceDefaults>();
-	private _onDidExtraLibsChange = new Emitter<monaco.languages.typescript.LanguageServiceDefaults>();
+	private _onDidChange = new Emitter<void>();
+	private _onDidExtraLibsChange = new Emitter<void>();
 
-	private _extraLibs: { [path: string]: { content: string, version: number } };
+	private _extraLibs: IExtraLibs;
 	private _workerMaxIdleTime: number;
 	private _eagerModelSync: boolean;
 	private _compilerOptions: monaco.languages.typescript.CompilerOptions;
 	private _diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions;
-	private _languageId: string;
-	private _eagerExtraLibSync: boolean = true;
+	private _onDidExtraLibsChangeTimeout: number;
 
-	constructor(languageId: string, compilerOptions: monaco.languages.typescript.CompilerOptions, diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions) {
+	constructor(compilerOptions: monaco.languages.typescript.CompilerOptions, diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions) {
 		this._extraLibs = Object.create(null);
 		this._workerMaxIdleTime = 2 * 60 * 1000;
 		this.setCompilerOptions(compilerOptions);
 		this.setDiagnosticsOptions(diagnosticsOptions);
-		this._languageId = languageId;
+		this._onDidExtraLibsChangeTimeout = -1;
 	}
 
-	get onDidChange(): IEvent<monaco.languages.typescript.LanguageServiceDefaults> {
+	get onDidChange(): IEvent<void> {
 		return this._onDidChange.event;
 	}
 
-	get onDidExtraLibsChange(): IEvent<monaco.languages.typescript.LanguageServiceDefaults> {
+	get onDidExtraLibsChange(): IEvent<void> {
 		return this._onDidExtraLibsChange.event;
 	}
 
-	getExtraLibs(): { [path: string]: string; } {
-		const result = Object.create(null);
-		for (var key in this._extraLibs) {
-			result[key] = this._extraLibs[key];
-		}
-		return Object.freeze(result);
+	getExtraLibs(): IExtraLibs {
+		return this._extraLibs;
 	}
 
 	addExtraLib(content: string, filePath?: string): IDisposable {
@@ -56,49 +58,49 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
 			filePath = `ts:extralib-${Date.now()}`;
 		}
 
-		if (this._extraLibs[filePath]) {
-			if(this._extraLibs[filePath].content !== content) {
-				this._extraLibs[filePath].version++;
-				this._extraLibs[filePath].content = content;
-			}
-		} else {
-			this._extraLibs[filePath] = {
-				content: content,
-				version: 1,
+		if (this._extraLibs[filePath] && this._extraLibs[filePath].content === content) {
+			// no-op, there already exists an extra lib with this content
+			return {
+				dispose: () => { }
 			};
 		}
-		if (this._eagerExtraLibSync) {
-			this.syncExtraLibs();
+
+		let myVersion = 1;
+		if (this._extraLibs[filePath]) {
+			myVersion = this._extraLibs[filePath].version + 1;
 		}
 
+		this._extraLibs[filePath] = {
+			content: content,
+			version: myVersion,
+		};
+		this._fireOnDidExtraLibsChangeSoon();
+
 		return {
 			dispose: () => {
-				if (delete this._extraLibs[filePath] && this._eagerExtraLibSync) {
-					this.syncExtraLibs();
+				let extraLib = this._extraLibs[filePath];
+				if (!extraLib) {
+					return;
+				}
+				if (extraLib.version !== myVersion) {
+					return;
 				}
+
+				delete this._extraLibs[filePath];
+				this._fireOnDidExtraLibsChangeSoon();
 			}
 		};
 	}
 
-	async syncExtraLibs(): Promise<void> {
-		try {
-			let worker;
-			try {
-				// we don't care if the get language worker fails.
-				// This happens if addExtraLib is called before the worker has initialized.
-				// however, when the worker has finished downloading and initializes,
-				// it does so with the latest extraLibs so no sync issue can appear
-				worker = await getLanguageWorker(this._languageId);
-			} catch (ignored) {
-				return;
-			}
-			const client = await worker("");
-			client.syncExtraLibs(this._extraLibs);
-			// let all listeners know that the extra libs have changed
-			this._onDidExtraLibsChange.fire(this);
-		} catch (error) {
-			console.error(error);
+	private _fireOnDidExtraLibsChangeSoon(): void {
+		if (this._onDidExtraLibsChangeTimeout !== -1) {
+			// already scheduled
+			return;
 		}
+		this._onDidExtraLibsChangeTimeout = setTimeout(() => {
+			this._onDidExtraLibsChangeTimeout = -1;
+			this._onDidExtraLibsChange.fire(undefined);
+		}, 0);
 	}
 
 	getCompilerOptions(): monaco.languages.typescript.CompilerOptions {
@@ -107,7 +109,7 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
 
 	setCompilerOptions(options: monaco.languages.typescript.CompilerOptions): void {
 		this._compilerOptions = options || Object.create(null);
-		this._onDidChange.fire(this);
+		this._onDidChange.fire(undefined);
 	}
 
 	getDiagnosticsOptions(): monaco.languages.typescript.DiagnosticsOptions {
@@ -116,7 +118,7 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
 
 	setDiagnosticsOptions(options: monaco.languages.typescript.DiagnosticsOptions): void {
 		this._diagnosticsOptions = options || Object.create(null);
-		this._onDidChange.fire(this);
+		this._onDidChange.fire(undefined);
 	}
 
 	setMaximumWorkerIdleTime(value: number): void {
@@ -138,10 +140,6 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
 	getEagerModelSync() {
 		return this._eagerModelSync;
 	}
-
-	setEagerExtraLibSync(value: boolean) {
-		this._eagerExtraLibSync = value;
-	}
 }
 
 //#region enums copied from typescript to prevent loading the entire typescriptServices ---
@@ -182,75 +180,20 @@ enum ModuleResolutionKind {
 }
 //#endregion
 
-const languageDefaultOptions = {
-	javascript: {
-		compilerOptions: { allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest },
-		diagnosticsOptions: { noSemanticValidation: true, noSyntaxValidation: false },
-	},
-	typescript: {
-		compilerOptions: { allowNonTsExtensions: true, target: ScriptTarget.Latest },
-		diagnosticsOptions: { noSemanticValidation: false, noSyntaxValidation: false }
-	}
-}
-
-const languageDefaults: { [name: string]: LanguageServiceDefaultsImpl } = {};
-
-/**
- * Generate the LanguageServiceDefaults for a new langauage with the given name
- * @param languageId Name of the language
- * @param isTypescriptBased Whether the language inherits from a typescript base or a javascript one
- */
-function setupLanguageServiceDefaults(languageId: string, isTypescriptBased: boolean) {
-	const languageOptions = isTypescriptBased ? languageDefaultOptions.typescript : languageDefaultOptions.javascript;
-	languageDefaults[languageId] = new LanguageServiceDefaultsImpl(languageId, languageOptions.compilerOptions, languageOptions.diagnosticsOptions);
-}
+const typescriptDefaults = new LanguageServiceDefaultsImpl(
+	{ allowNonTsExtensions: true, target: ScriptTarget.Latest },
+	{ noSemanticValidation: false, noSyntaxValidation: false });
 
-setupNamedLanguage({
-	id: 'typescript',
-	extensions: ['.ts', '.tsx'],
-	aliases: ['TypeScript', 'ts', 'typescript'],
-	mimetypes: ['text/typescript']
-}, true, true);
-
-setupNamedLanguage({
-	id: 'javascript',
-	extensions: ['.js', '.es6', '.jsx'],
-	firstLine: '^#!.*\\bnode',
-	filenames: ['jakefile'],
-	aliases: ['JavaScript', 'javascript', 'js'],
-	mimetypes: ['text/javascript'],
-}, false, true);
+const javascriptDefaults = new LanguageServiceDefaultsImpl(
+	{ allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest },
+	{ noSemanticValidation: true, noSyntaxValidation: false });
 
 function getTypeScriptWorker(): Promise<any> {
-	return getLanguageWorker("typescript");
+	return getMode().then(mode => mode.getTypeScriptWorker());
 }
 
 function getJavaScriptWorker(): Promise<any> {
-	return getLanguageWorker("javascript");
-}
-
-function getLanguageWorker(languageName: string): Promise<any> {
-	return getMode().then(mode => mode.getNamedLanguageWorker(languageName));
-}
-
-function getLanguageDefaults(languageName: string): LanguageServiceDefaultsImpl {
-	return languageDefaults[languageName];
-}
-
-function setupNamedLanguage(languageDefinition: monaco.languages.ILanguageExtensionPoint, isTypescript: boolean, registerLanguage?: boolean): void {
-	if (registerLanguage) {
-		monaco.languages.register(languageDefinition);
-
-		const langageConfig = isTypescript ? tsDefinitions : jsDefinitions;
-		monaco.languages.setMonarchTokensProvider(languageDefinition.id, langageConfig.language);
-		monaco.languages.setLanguageConfiguration(languageDefinition.id, langageConfig.conf);
-	}
-
-	setupLanguageServiceDefaults(languageDefinition.id, isTypescript);
-
-	monaco.languages.onLanguage(languageDefinition.id, () => {
-		return getMode().then(mode => mode.setupNamedLanguage(languageDefinition.id, isTypescript, languageDefaults[languageDefinition.id]));
-	});
+	return getMode().then(mode => mode.getJavaScriptWorker());
 }
 
 // Export API
@@ -261,13 +204,10 @@ function createAPI(): typeof monaco.languages.typescript {
 		NewLineKind: NewLineKind,
 		ScriptTarget: ScriptTarget,
 		ModuleResolutionKind: ModuleResolutionKind,
-		typescriptDefaults: getLanguageDefaults("typescript"),
-		javascriptDefaults: getLanguageDefaults("javascript"),
-		getLanguageDefaults: getLanguageDefaults,
+		typescriptDefaults: typescriptDefaults,
+		javascriptDefaults: javascriptDefaults,
 		getTypeScriptWorker: getTypeScriptWorker,
-		getJavaScriptWorker: getJavaScriptWorker,
-		getLanguageWorker: getLanguageWorker,
-		setupNamedLanguage: setupNamedLanguage
+		getJavaScriptWorker: getJavaScriptWorker
 	}
 }
 monaco.languages.typescript = createAPI();
@@ -277,3 +217,10 @@ monaco.languages.typescript = createAPI();
 function getMode(): Promise<typeof mode> {
 	return import('./tsMode');
 }
+
+monaco.languages.onLanguage('typescript', () => {
+	return getMode().then(mode => mode.setupTypeScript(typescriptDefaults));
+});
+monaco.languages.onLanguage('javascript', () => {
+	return getMode().then(mode => mode.setupJavaScript(javascriptDefaults));
+});

+ 0 - 15
src/monaco.d.ts

@@ -164,17 +164,6 @@ declare module monaco.languages.typescript {
          * to the worker on start or restart.
          */
         setEagerModelSync(value: boolean): void;
-
-        /**
-         * Configure if the extra libs should be eagerly synced after each addExtraLibCall.
-         * This is true by default
-         */
-        setEagerExtraLibSync(value: boolean): void;
-
-        /**
-         * If EagerExtraLibSync is disabled, call this to trigger the changes.
-         */
-        syncExtraLibs(): Promise<void>;
     }
 
     export var typescriptDefaults: LanguageServiceDefaults;
@@ -182,8 +171,4 @@ declare module monaco.languages.typescript {
 
     export var getTypeScriptWorker: () => Promise<any>;
     export var getJavaScriptWorker: () => Promise<any>;
-
-    export var getLanguageWorker: (langaugeName: string) => Promise<any>;
-    export var setupNamedLanguage: (languageDefinition: languages.ILanguageExtensionPoint, isTypescript: boolean, registerLanguage?: boolean) => void;
-    export var getLanguageDefaults: (languageName: string) => LanguageServiceDefaults;
 }

+ 26 - 9
src/tsMode.ts

@@ -11,23 +11,40 @@ import * as languageFeatures from './languageFeatures';
 
 import Uri = monaco.Uri;
 
-let scriptWorkerMap: { [name: string]: (first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker> } = {};
+let javaScriptWorker: (first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker>;
+let typeScriptWorker: (first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker>;
 
-export function setupNamedLanguage(languageName: string, isTypescript: boolean, defaults: LanguageServiceDefaultsImpl): void {
-	scriptWorkerMap[languageName + "Worker"] = setupMode(
+export function setupTypeScript(defaults: LanguageServiceDefaultsImpl): void {
+	typeScriptWorker = setupMode(
 		defaults,
-		languageName
+		'typescript'
 	);
 }
 
-export function getNamedLanguageWorker(languageName: string): Promise<(first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker>> {
-	let workerName = languageName + "Worker";
+export function setupJavaScript(defaults: LanguageServiceDefaultsImpl): void {
+	javaScriptWorker = setupMode(
+		defaults,
+		'javascript'
+	);
+}
+
+export function getJavaScriptWorker(): Promise<(first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker>> {
+	return new Promise((resolve, reject) => {
+		if (!javaScriptWorker) {
+			return reject("JavaScript not registered!");
+		}
+
+		resolve(javaScriptWorker);
+	});
+}
+
+export function getTypeScriptWorker(): Promise<(first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker>> {
 	return new Promise((resolve, reject) => {
-		if (!scriptWorkerMap[workerName]) {
-			return reject(languageName + " not registered!");
+		if (!typeScriptWorker) {
+			return reject("TypeScript not registered!");
 		}
 
-		resolve(scriptWorkerMap[workerName]);
+		resolve(typeScriptWorker);
 	});
 }
 

+ 7 - 6
src/tsWorker.ts

@@ -6,6 +6,7 @@
 
 import * as ts from './lib/typescriptServices';
 import { lib_dts, lib_es6_dts } from './lib/lib';
+import { IExtraLibs } from './monaco.contribution';
 
 import IWorkerContext = monaco.worker.IWorkerContext;
 
@@ -24,7 +25,7 @@ export class TypeScriptWorker implements ts.LanguageServiceHost {
 	// --- model sync -----------------------
 
 	private _ctx: IWorkerContext;
-	private _extraLibs: { [path: string]: { content: string, version: number } } = Object.create(null);
+	private _extraLibs: IExtraLibs = Object.create(null);
 	private _languageService = ts.createLanguageService(this);
 	private _compilerOptions: ts.CompilerOptions;
 
@@ -62,8 +63,8 @@ export class TypeScriptWorker implements ts.LanguageServiceHost {
 		} else if (this.isDefaultLibFileName(fileName)) {
 			// default lib is static
 			return '1';
-		} else if(fileName in this._extraLibs) {
-			return this._extraLibs[fileName].version.toString();
+		} else if (fileName in this._extraLibs) {
+			return String(this._extraLibs[fileName].version);
 		}
 	}
 
@@ -75,7 +76,7 @@ export class TypeScriptWorker implements ts.LanguageServiceHost {
 			text = model.getValue();
 
 		} else if (fileName in this._extraLibs) {
-			// static extra lib
+			// extra lib
 			text = this._extraLibs[fileName].content;
 
 		} else if (fileName === DEFAULT_LIB.NAME) {
@@ -199,14 +200,14 @@ export class TypeScriptWorker implements ts.LanguageServiceHost {
 		return Promise.resolve(this._languageService.getEmitOutput(fileName));
 	}
 
-	syncExtraLibs(extraLibs: { [path: string]: { content: string, version: number } }) {
+	updateExtraLibs(extraLibs: IExtraLibs) {
 		this._extraLibs = extraLibs;
 	}
 }
 
 export interface ICreateData {
 	compilerOptions: ts.CompilerOptions;
-	extraLibs: { [path: string]: { content: string, version: number } };
+	extraLibs: IExtraLibs;
 }
 
 export function create(ctx: IWorkerContext, createData: ICreateData): TypeScriptWorker {

+ 1 - 7
src/tsconfig.esm.json

@@ -9,13 +9,7 @@
       "es5",
       "es2015.collection",
       "es2015.promise"
-    ],
-    "baseUrl": "",
-    "paths": {
-      "vs/basic-languages/*": [
-        "../node_modules/monaco-languages/release/esm/*"
-      ]
-    },
+    ]
   },
   "include": [
     "**/*.ts"

+ 1 - 7
src/tsconfig.json

@@ -9,13 +9,7 @@
       "es5",
       "es2015.collection",
       "es2015.promise"
-    ],
-    "baseUrl": "",
-    "paths": {
-      "vs/basic-languages/*": [
-        "../node_modules/monaco-languages/release/dev/*"
-      ]
-    },
+    ]
   },
   "include": [
     "**/*.ts"

+ 18 - 0
src/workerManager.ts

@@ -17,6 +17,8 @@ export class WorkerManager {
 	private _idleCheckInterval: number;
 	private _lastUsedTime: number;
 	private _configChangeListener: IDisposable;
+	private _updateExtraLibsToken: number;
+	private _extraLibsChangeListener: IDisposable;
 
 	private _worker: monaco.editor.MonacoWebWorker<TypeScriptWorker>;
 	private _client: Promise<TypeScriptWorker>;
@@ -28,6 +30,8 @@ export class WorkerManager {
 		this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000);
 		this._lastUsedTime = 0;
 		this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker());
+		this._updateExtraLibsToken = 0;
+		this._extraLibsChangeListener = this._defaults.onDidExtraLibsChange(() => this._updateExtraLibs());
 	}
 
 	private _stopWorker(): void {
@@ -41,9 +45,23 @@ export class WorkerManager {
 	dispose(): void {
 		clearInterval(this._idleCheckInterval);
 		this._configChangeListener.dispose();
+		this._extraLibsChangeListener.dispose();
 		this._stopWorker();
 	}
 
+	private async _updateExtraLibs(): Promise<void> {
+		if (!this._worker) {
+			return;
+		}
+		const myToken = ++this._updateExtraLibsToken;
+		const proxy = await this._worker.getProxy();
+		if (this._updateExtraLibsToken !== myToken) {
+			// avoid multiple calls
+			return;
+		}
+		proxy.updateExtraLibs(this._defaults.getExtraLibs());
+	}
+
 	private _checkIfIdle(): void {
 		if (!this._worker) {
 			return;