mirror of
https://github.com/microsoft/monaco-editor.git
synced 2025-12-22 15:05:39 +01:00
Merge pull request #30 from stefan-lacatus/extraLibOptimizations
Optimize how external libs are handled and allow for custom languages
This commit is contained in:
commit
f39458d794
4 changed files with 94 additions and 25 deletions
|
|
@ -135,13 +135,15 @@ export class DiagnostcsAdapter extends Adapter {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this._disposables.push(this._defaults.onDidChange(() => {
|
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(recomputeDiagostics));
|
||||||
|
this._disposables.push(this._defaults.onDidExtraLibsChange(recomputeDiagostics));
|
||||||
|
|
||||||
monaco.editor.getModels().forEach(onModelAdd);
|
monaco.editor.getModels().forEach(onModelAdd);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,32 +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 _extraLibs: { [path: string]: string };
|
private _onDidExtraLibsChange = new Emitter<void>();
|
||||||
|
|
||||||
|
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 _onDidExtraLibsChangeTimeout: number;
|
||||||
|
|
||||||
constructor(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._onDidExtraLibsChangeTimeout = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
get onDidChange(): IEvent<monaco.languages.typescript.LanguageServiceDefaults> {
|
get onDidChange(): IEvent<void> {
|
||||||
return this._onDidChange.event;
|
return this._onDidChange.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
getExtraLibs(): { [path: string]: string; } {
|
get onDidExtraLibsChange(): IEvent<void> {
|
||||||
const result = Object.create(null);
|
return this._onDidExtraLibsChange.event;
|
||||||
for (var key in this._extraLibs) {
|
}
|
||||||
result[key] = this._extraLibs[key];
|
|
||||||
}
|
getExtraLibs(): IExtraLibs {
|
||||||
return Object.freeze(result);
|
return this._extraLibs;
|
||||||
}
|
}
|
||||||
|
|
||||||
addExtraLib(content: string, filePath?: string): IDisposable {
|
addExtraLib(content: string, filePath?: string): IDisposable {
|
||||||
|
|
@ -45,29 +58,58 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
|
||||||
filePath = `ts:extralib-${Math.random().toString(36).substring(2, 15)}`;
|
filePath = `ts:extralib-${Math.random().toString(36).substring(2, 15)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._extraLibs[filePath]) {
|
if (this._extraLibs[filePath] && this._extraLibs[filePath].content === content) {
|
||||||
throw new Error(`${filePath} already a extra lib`);
|
// no-op, there already exists an extra lib with this content
|
||||||
|
return {
|
||||||
|
dispose: () => { }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
this._extraLibs[filePath] = content;
|
let myVersion = 1;
|
||||||
this._onDidChange.fire(this);
|
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]) {
|
let extraLib = this._extraLibs[filePath];
|
||||||
this._onDidChange.fire(this);
|
if (!extraLib) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (extraLib.version !== myVersion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete this._extraLibs[filePath];
|
||||||
|
this._fireOnDidExtraLibsChangeSoon();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
getCompilerOptions(): monaco.languages.typescript.CompilerOptions {
|
||||||
return this._compilerOptions;
|
return this._compilerOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
|
@ -76,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 {
|
||||||
|
|
|
||||||
|
|
@ -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: { [fileName: string]: string } = 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;
|
||||||
|
|
||||||
|
|
@ -59,9 +60,11 @@ export class TypeScriptWorker implements ts.LanguageServiceHost {
|
||||||
let model = this._getModel(fileName);
|
let model = this._getModel(fileName);
|
||||||
if (model) {
|
if (model) {
|
||||||
return model.version.toString();
|
return model.version.toString();
|
||||||
} else if (this.isDefaultLibFileName(fileName) || fileName in this._extraLibs) {
|
} else if (this.isDefaultLibFileName(fileName)) {
|
||||||
// extra lib and default lib are static
|
// default lib is static
|
||||||
return '1';
|
return '1';
|
||||||
|
} else if (fileName in this._extraLibs) {
|
||||||
|
return String(this._extraLibs[fileName].version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,8 +76,8 @@ 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];
|
text = this._extraLibs[fileName].content;
|
||||||
|
|
||||||
} else if (fileName === DEFAULT_LIB.NAME) {
|
} else if (fileName === DEFAULT_LIB.NAME) {
|
||||||
text = DEFAULT_LIB.CONTENTS;
|
text = DEFAULT_LIB.CONTENTS;
|
||||||
|
|
@ -196,11 +199,15 @@ export class TypeScriptWorker implements ts.LanguageServiceHost {
|
||||||
getEmitOutput(fileName: string): Promise<ts.EmitOutput> {
|
getEmitOutput(fileName: string): Promise<ts.EmitOutput> {
|
||||||
return Promise.resolve(this._languageService.getEmitOutput(fileName));
|
return Promise.resolve(this._languageService.getEmitOutput(fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateExtraLibs(extraLibs: IExtraLibs) {
|
||||||
|
this._extraLibs = extraLibs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreateData {
|
export interface ICreateData {
|
||||||
compilerOptions: ts.CompilerOptions;
|
compilerOptions: ts.CompilerOptions;
|
||||||
extraLibs: { [path: string]: string };
|
extraLibs: IExtraLibs;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function create(ctx: IWorkerContext, createData: ICreateData): TypeScriptWorker {
|
export function create(ctx: IWorkerContext, createData: ICreateData): TypeScriptWorker {
|
||||||
|
|
|
||||||
|
|
@ -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…
Add table
Add a link
Reference in a new issue