Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User/morgilad/dispose disposables when disposing model #482

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ Every PR should come with a test that checks it.

## Changelog

### 12.0.8

- fix: dispose all monaco models when disposing the worker to prevent memory leaks.

### 12.0.7

- revert: KQL color contrast for query operators change.
Expand Down
2 changes: 1 addition & 1 deletion package/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kusto/monaco-kusto",
"version": "12.0.7",
"version": "12.0.8",
"description": "CSL, KQL plugin for the Monaco Editor",
"author": {
"name": "Microsoft"
Expand Down
65 changes: 37 additions & 28 deletions package/src/kustoMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { IKustoWorkerImpl } from './kustoWorker';
import { kustoLanguageDefinition } from './syntaxHighlighting/kustoMonarchLanguageDefinition';
import { LANGUAGE_ID } from './globals';
import { semanticTokensProviderRegistrarCreator } from './syntaxHighlighting/semanticTokensProviderRegistrar';
import { IDisposable } from 'monaco-editor';
morgilad marked this conversation as resolved.
Show resolved Hide resolved

export interface AugmentedWorker
extends KustoWorker,
Expand All @@ -29,13 +30,10 @@ let workerPromise: Promise<AugmentedWorkerAccessor> = new Promise((resolve, reje
* Called when Kusto language is first needed (a model has the language set)
* @param defaults
*/
export function setupMode(
defaults: LanguageServiceDefaults,
monacoInstance: typeof globalThis.monaco
): AugmentedWorkerAccessor {
let onSchemaChange = new monaco.Emitter<Schema>();
export function setupMode(defaults: LanguageServiceDefaults, monacoInstance: typeof globalThis.monaco): IDisposable {
const onSchemaChange = new monaco.Emitter<Schema>();
// TODO: when should we dispose of these? seems like monaco-css and monaco-typescript don't dispose of these.
let disposables: monaco.IDisposable[] = [];
const disposables: monaco.IDisposable[] = [];
const semanticTokensProviderRegistrar = semanticTokensProviderRegistrarCreator();

const client = new WorkerManager(monacoInstance, defaults);
Expand Down Expand Up @@ -80,10 +78,7 @@ export function setupMode(
)
);

const monarchTokensProvider = monacoInstance.languages.setMonarchTokensProvider(
LANGUAGE_ID,
kustoLanguageDefinition
);
disposables.push(monacoInstance.languages.setMonarchTokensProvider(LANGUAGE_ID, kustoLanguageDefinition));

disposables.push(
new languageFeatures.DiagnosticsAdapter(
Expand Down Expand Up @@ -143,27 +138,41 @@ export function setupMode(
kustoWorker = workerAccessor;
resolveWorker(workerAccessor);

monacoInstance.languages.setLanguageConfiguration(LANGUAGE_ID, {
folding: {
offSide: false,
markers: { start: /^\s*[\r\n]/gm, end: /^\s*[\r\n]/gm },
},
comments: {
lineComment: '//',
blockComment: null,
disposables.push(monacoInstance.languages.setLanguageConfiguration(LANGUAGE_ID, kanguageConfiguration));

return asDisposable(disposables);
}

function asDisposable(disposables: IDisposable[]): IDisposable {
return {
dispose: () => {
return disposeAll(disposables);
},
autoClosingPairs: [
{ open: '{', close: '}' },
{ open: '[', close: ']' },
{ open: '(', close: ')' },
{ open: "'", close: "'", notIn: ['string', 'comment'] },
{ open: '"', close: '"', notIn: ['string', 'comment'] },
],
});

return kustoWorker;
};
}

function disposeAll(disposables: IDisposable[]) {
disposables.forEach((d) => d.dispose());
}

export function getKustoWorker(): Promise<AugmentedWorkerAccessor> {
return workerPromise.then(() => kustoWorker);
}

const kanguageConfiguration = {
folding: {
offSide: false,
markers: { start: /^\s*[\r\n]/gm, end: /^\s*[\r\n]/gm },
},
comments: {
lineComment: '//',
blockComment: null,
},
autoClosingPairs: [
{ open: '{', close: '}' },
{ open: '[', close: ']' },
{ open: '(', close: ')' },
{ open: "'", close: "'", notIn: ['string', 'comment'] },
{ open: '"', close: '"', notIn: ['string', 'comment'] },
],
};
13 changes: 9 additions & 4 deletions package/src/monaco.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,19 @@ export function getKustoWorker(): Promise<WorkerAccessor> {
});
}

function withMode(callback: (module: typeof mode) => void): void {
import('./kustoMode').then(callback);
function withMode<T>(callback: (module: typeof mode) => T): Promise<T> {
return import('./kustoMode').then(callback);
}

export const kustoDefaults = new LanguageServiceDefaultsImpl(defaultLanguageSettings);

monaco.languages.onLanguage('kusto', () => {
withMode((mode) => mode.setupMode(kustoDefaults, monaco as typeof globalThis.monaco));
let disposable: monaco.IDisposable;
monaco.languages.onLanguage('kusto', async () => {
disposable = await withMode((mode) => mode.setupMode(kustoDefaults, monaco as typeof globalThis.monaco));
});

monaco.editor.onWillDisposeModel((model) => {
disposable.dispose();
});

monaco.languages.register({
Expand Down
Loading