Changes for PR #30

pull/2748/head
Alex Dima 6 years ago
parent 6c73d7f708
commit 6b2271c1c1

@ -29,8 +29,6 @@ bundleOne('monaco.contribution');
bundleOne('tsMode'); bundleOne('tsMode');
bundleOne('tsWorker'); bundleOne('tsWorker');
updateImports('monaco.contribution');
function bundleOne(moduleId, exclude) { function bundleOne(moduleId, exclude) {
requirejs.optimize({ requirejs.optimize({
baseUrl: 'release/dev/', baseUrl: 'release/dev/',
@ -38,8 +36,7 @@ function bundleOne(moduleId, exclude) {
out: 'release/min/' + moduleId + '.js', out: 'release/min/' + moduleId + '.js',
exclude: exclude, exclude: exclude,
paths: { paths: {
'vs/language/typescript': REPO_ROOT + '/release/dev', 'vs/language/typescript': REPO_ROOT + '/release/dev'
'vs/basic-languages': REPO_ROOT + '/node_modules/monaco-languages/release/dev'
}, },
optimize: 'none' optimize: 'none'
}, function(buildResponse) { }, function(buildResponse) {
@ -56,10 +53,3 @@ function bundleOne(moduleId, exclude) {
fs.writeFileSync(filePath, BUNDLED_FILE_HEADER + result.code); 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);
}

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

@ -5,8 +5,6 @@
'use strict'; 'use strict';
import * as mode from './tsMode'; 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 Emitter = monaco.Emitter;
import IEvent = monaco.IEvent; import IEvent = monaco.IEvent;
@ -14,41 +12,45 @@ import IDisposable = monaco.IDisposable;
// --- TypeScript configuration and defaults --------- // --- 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 { export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.LanguageServiceDefaults {
private _onDidChange = new Emitter<monaco.languages.typescript.LanguageServiceDefaults>(); private _onDidChange = new Emitter<void>();
private _onDidExtraLibsChange = new Emitter<monaco.languages.typescript.LanguageServiceDefaults>(); private _onDidExtraLibsChange = new Emitter<void>();
private _extraLibs: { [path: string]: { content: string, version: number } }; private _extraLibs: IExtraLibs;
private _workerMaxIdleTime: number; private _workerMaxIdleTime: number;
private _eagerModelSync: boolean; private _eagerModelSync: boolean;
private _compilerOptions: monaco.languages.typescript.CompilerOptions; private _compilerOptions: monaco.languages.typescript.CompilerOptions;
private _diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions; private _diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions;
private _languageId: string; private _onDidExtraLibsChangeTimeout: number;
private _eagerExtraLibSync: boolean = true;
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._extraLibs = Object.create(null);
this._workerMaxIdleTime = 2 * 60 * 1000; this._workerMaxIdleTime = 2 * 60 * 1000;
this.setCompilerOptions(compilerOptions); this.setCompilerOptions(compilerOptions);
this.setDiagnosticsOptions(diagnosticsOptions); this.setDiagnosticsOptions(diagnosticsOptions);
this._languageId = languageId; this._onDidExtraLibsChangeTimeout = -1;
} }
get onDidChange(): IEvent<monaco.languages.typescript.LanguageServiceDefaults> { get onDidChange(): IEvent<void> {
return this._onDidChange.event; return this._onDidChange.event;
} }
get onDidExtraLibsChange(): IEvent<monaco.languages.typescript.LanguageServiceDefaults> { get onDidExtraLibsChange(): IEvent<void> {
return this._onDidExtraLibsChange.event; return this._onDidExtraLibsChange.event;
} }
getExtraLibs(): { [path: string]: string; } { getExtraLibs(): IExtraLibs {
const result = Object.create(null); return this._extraLibs;
for (var key in this._extraLibs) {
result[key] = this._extraLibs[key];
}
return Object.freeze(result);
} }
addExtraLib(content: string, filePath?: string): IDisposable { addExtraLib(content: string, filePath?: string): IDisposable {
@ -56,49 +58,49 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
filePath = `ts:extralib-${Date.now()}`; filePath = `ts:extralib-${Date.now()}`;
} }
if (this._extraLibs[filePath]) { if (this._extraLibs[filePath] && this._extraLibs[filePath].content === content) {
if(this._extraLibs[filePath].content !== content) { // no-op, there already exists an extra lib with this content
this._extraLibs[filePath].version++; return {
this._extraLibs[filePath].content = content; dispose: () => { }
}
} else {
this._extraLibs[filePath] = {
content: content,
version: 1,
}; };
} }
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 { return {
dispose: () => { dispose: () => {
if (delete this._extraLibs[filePath] && this._eagerExtraLibSync) { let extraLib = this._extraLibs[filePath];
this.syncExtraLibs(); if (!extraLib) {
return;
}
if (extraLib.version !== myVersion) {
return;
} }
delete this._extraLibs[filePath];
this._fireOnDidExtraLibsChangeSoon();
} }
}; };
} }
async syncExtraLibs(): Promise<void> { private _fireOnDidExtraLibsChangeSoon(): void {
try { if (this._onDidExtraLibsChangeTimeout !== -1) {
let worker; // already scheduled
try { return;
// 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);
} }
this._onDidExtraLibsChangeTimeout = setTimeout(() => {
this._onDidExtraLibsChangeTimeout = -1;
this._onDidExtraLibsChange.fire(undefined);
}, 0);
} }
getCompilerOptions(): monaco.languages.typescript.CompilerOptions { getCompilerOptions(): monaco.languages.typescript.CompilerOptions {
@ -107,7 +109,7 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
setCompilerOptions(options: monaco.languages.typescript.CompilerOptions): void { setCompilerOptions(options: monaco.languages.typescript.CompilerOptions): void {
this._compilerOptions = options || Object.create(null); this._compilerOptions = options || Object.create(null);
this._onDidChange.fire(this); this._onDidChange.fire(undefined);
} }
getDiagnosticsOptions(): monaco.languages.typescript.DiagnosticsOptions { getDiagnosticsOptions(): monaco.languages.typescript.DiagnosticsOptions {
@ -116,7 +118,7 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
setDiagnosticsOptions(options: monaco.languages.typescript.DiagnosticsOptions): void { setDiagnosticsOptions(options: monaco.languages.typescript.DiagnosticsOptions): void {
this._diagnosticsOptions = options || Object.create(null); this._diagnosticsOptions = options || Object.create(null);
this._onDidChange.fire(this); this._onDidChange.fire(undefined);
} }
setMaximumWorkerIdleTime(value: number): void { setMaximumWorkerIdleTime(value: number): void {
@ -138,10 +140,6 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
getEagerModelSync() { getEagerModelSync() {
return this._eagerModelSync; return this._eagerModelSync;
} }
setEagerExtraLibSync(value: boolean) {
this._eagerExtraLibSync = value;
}
} }
//#region enums copied from typescript to prevent loading the entire typescriptServices --- //#region enums copied from typescript to prevent loading the entire typescriptServices ---
@ -182,75 +180,20 @@ enum ModuleResolutionKind {
} }
//#endregion //#endregion
const languageDefaultOptions = { const typescriptDefaults = new LanguageServiceDefaultsImpl(
javascript: { { allowNonTsExtensions: true, target: ScriptTarget.Latest },
compilerOptions: { allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest }, { noSemanticValidation: false, noSyntaxValidation: false });
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);
}
setupNamedLanguage({ const javascriptDefaults = new LanguageServiceDefaultsImpl(
id: 'typescript', { allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest },
extensions: ['.ts', '.tsx'], { noSemanticValidation: true, noSyntaxValidation: false });
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);
function getTypeScriptWorker(): Promise<any> { function getTypeScriptWorker(): Promise<any> {
return getLanguageWorker("typescript"); return getMode().then(mode => mode.getTypeScriptWorker());
} }
function getJavaScriptWorker(): Promise<any> { function getJavaScriptWorker(): Promise<any> {
return getLanguageWorker("javascript"); return getMode().then(mode => mode.getJavaScriptWorker());
}
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]));
});
} }
// Export API // Export API
@ -261,13 +204,10 @@ function createAPI(): typeof monaco.languages.typescript {
NewLineKind: NewLineKind, NewLineKind: NewLineKind,
ScriptTarget: ScriptTarget, ScriptTarget: ScriptTarget,
ModuleResolutionKind: ModuleResolutionKind, ModuleResolutionKind: ModuleResolutionKind,
typescriptDefaults: getLanguageDefaults("typescript"), typescriptDefaults: typescriptDefaults,
javascriptDefaults: getLanguageDefaults("javascript"), javascriptDefaults: javascriptDefaults,
getLanguageDefaults: getLanguageDefaults,
getTypeScriptWorker: getTypeScriptWorker, getTypeScriptWorker: getTypeScriptWorker,
getJavaScriptWorker: getJavaScriptWorker, getJavaScriptWorker: getJavaScriptWorker
getLanguageWorker: getLanguageWorker,
setupNamedLanguage: setupNamedLanguage
} }
} }
monaco.languages.typescript = createAPI(); monaco.languages.typescript = createAPI();
@ -277,3 +217,10 @@ monaco.languages.typescript = createAPI();
function getMode(): Promise<typeof mode> { function getMode(): Promise<typeof mode> {
return import('./tsMode'); 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));
});

15
src/monaco.d.ts vendored

@ -164,17 +164,6 @@ declare module monaco.languages.typescript {
* to the worker on start or restart. * to the worker on start or restart.
*/ */
setEagerModelSync(value: boolean): void; 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; export var typescriptDefaults: LanguageServiceDefaults;
@ -182,8 +171,4 @@ declare module monaco.languages.typescript {
export var getTypeScriptWorker: () => Promise<any>; export var getTypeScriptWorker: () => Promise<any>;
export var getJavaScriptWorker: () => 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;
} }

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

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

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

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

@ -17,6 +17,8 @@ export class WorkerManager {
private _idleCheckInterval: number; private _idleCheckInterval: number;
private _lastUsedTime: number; private _lastUsedTime: number;
private _configChangeListener: IDisposable; private _configChangeListener: IDisposable;
private _updateExtraLibsToken: number;
private _extraLibsChangeListener: IDisposable;
private _worker: monaco.editor.MonacoWebWorker<TypeScriptWorker>; private _worker: monaco.editor.MonacoWebWorker<TypeScriptWorker>;
private _client: Promise<TypeScriptWorker>; private _client: Promise<TypeScriptWorker>;
@ -28,6 +30,8 @@ export class WorkerManager {
this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000); this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000);
this._lastUsedTime = 0; this._lastUsedTime = 0;
this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker()); this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker());
this._updateExtraLibsToken = 0;
this._extraLibsChangeListener = this._defaults.onDidExtraLibsChange(() => this._updateExtraLibs());
} }
private _stopWorker(): void { private _stopWorker(): void {
@ -41,9 +45,23 @@ export class WorkerManager {
dispose(): void { dispose(): void {
clearInterval(this._idleCheckInterval); clearInterval(this._idleCheckInterval);
this._configChangeListener.dispose(); this._configChangeListener.dispose();
this._extraLibsChangeListener.dispose();
this._stopWorker(); 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 { private _checkIfIdle(): void {
if (!this._worker) { if (!this._worker) {
return; return;

Loading…
Cancel
Save