[Monaco] Refactor the way XJSON grammar checker gets registered (#75160)

* Refactor the way XJSON grammar checker gets registered

- avoid registering multiple model add listeners
- remove regsiterGrammarChecker from public API!
- fix getWorker handler to register XJSON only for XJSON models

* remove unused import

* updateAnnos -> updateAnnotations
This commit is contained in:
Jean-Louis Leysens 2020-08-18 15:13:15 +02:00 committed by GitHub
parent 2a212cbad8
commit 36f0c75088
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 56 additions and 45 deletions

View file

@ -22,6 +22,19 @@ export enum AnnoTypes {
warning = 'warning',
}
export type Parser = ReturnType<typeof createParser>;
export interface Annotation {
name?: string;
type: AnnoTypes;
text: string;
at: number;
}
export interface ParseResult {
annotations: Annotation[];
}
/* eslint-disable */
export const createParser = () => {

View file

@ -17,8 +17,10 @@
* under the License.
*/
import { registerGrammarChecker } from './language';
/**
* This import registers the XJSON monaco language contribution
*/
import './language';
import { ID } from './constants';
export const XJsonLang = { registerGrammarChecker, ID };
export const XJsonLang = { ID };

View file

@ -32,13 +32,16 @@ const wps = new WorkerProxyService();
registerLexerRules(monaco);
// In future we will need to make this map languages to workers using "id" and/or "label" values
// that get passed in.
// that get passed in. Also this should not live inside the "xjson" dir directly. We can update this
// once we have another worker.
// @ts-ignore
window.MonacoEnvironment = {
getWorker: (id: any, label: any) => {
// In kibana we will probably build this once and then load with raw-loader
const blob = new Blob([workerSrc], { type: 'application/javascript' });
return new Worker(URL.createObjectURL(blob));
getWorker: (module: string, languageId: string) => {
if (languageId === ID) {
// In kibana we will probably build this once and then load with raw-loader
const blob = new Blob([workerSrc], { type: 'application/javascript' });
return new Worker(URL.createObjectURL(blob));
}
},
};
@ -47,15 +50,19 @@ monaco.languages.onLanguage(ID, async () => {
});
const OWNER = 'XJSON_GRAMMAR_CHECKER';
export const registerGrammarChecker = (editor: monaco.editor.IEditor) => {
export const registerGrammarChecker = () => {
const allDisposables: monaco.IDisposable[] = [];
const updateAnnos = async () => {
const { annotations } = await wps.getAnnos();
const model = editor.getModel() as monaco.editor.ITextModel | null;
if (!model) {
const updateAnnotations = async (model: monaco.editor.IModel): Promise<void> => {
if (model.isDisposed()) {
return;
}
const parseResult = await wps.getAnnos(model.uri);
if (!parseResult) {
return;
}
const { annotations } = parseResult;
monaco.editor.setModelMarkers(
model,
OWNER,
@ -74,19 +81,21 @@ export const registerGrammarChecker = (editor: monaco.editor.IEditor) => {
};
const onModelAdd = (model: monaco.editor.IModel) => {
allDisposables.push(
model.onDidChangeContent(async () => {
updateAnnos();
})
);
if (model.getModeId() === ID) {
allDisposables.push(
model.onDidChangeContent(async () => {
updateAnnotations(model);
})
);
updateAnnos();
updateAnnotations(model);
}
};
allDisposables.push(monaco.editor.onDidCreateModel(onModelAdd));
monaco.editor.getModels().forEach(onModelAdd);
return () => {
wps.stop();
allDisposables.forEach((d) => d.dispose());
};
};
registerGrammarChecker();

View file

@ -19,17 +19,19 @@
/* eslint-disable-next-line @kbn/eslint/module_migration */
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import { createParser } from '../grammar';
import { createParser, Parser, ParseResult } from '../grammar';
export class XJsonWorker {
constructor(private ctx: monaco.worker.IWorkerContext) {}
private parser: any;
private parser: Parser | undefined;
async parse() {
async parse(modelUri: string): Promise<ParseResult | undefined> {
if (!this.parser) {
this.parser = createParser();
}
const [model] = this.ctx.getMirrorModels();
return this.parser(model.getValue());
const model = this.ctx.getMirrorModels().find((m) => m.uri.toString() === modelUri);
if (model) {
return this.parser(model.getValue());
}
}
}

View file

@ -17,32 +17,21 @@
* under the License.
*/
import { AnnoTypes } from './grammar';
import { ParseResult } from './grammar';
import { monaco } from '../monaco';
import { XJsonWorker } from './worker';
import { ID } from './constants';
export interface Annotation {
name?: string;
type: AnnoTypes;
text: string;
at: number;
}
export interface AnnotationsResponse {
annotations: Annotation[];
}
export class WorkerProxyService {
private worker: monaco.editor.MonacoWebWorker<XJsonWorker> | undefined;
public async getAnnos(): Promise<AnnotationsResponse> {
public async getAnnos(modelUri: monaco.Uri): Promise<ParseResult | undefined> {
if (!this.worker) {
throw new Error('Worker Proxy Service has not been setup!');
}
await this.worker.withSyncedResources(monaco.editor.getModels().map(({ uri }) => uri));
await this.worker.withSyncedResources([modelUri]);
const proxy = await this.worker.getProxy();
return proxy.parse();
return proxy.parse(modelUri.toString());
}
public setup() {

View file

@ -3,7 +3,6 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { XJsonLang } from '@kbn/monaco';
import React, { FunctionComponent, useCallback } from 'react';
import { FieldHook, Monaco } from '../../../../../../shared_imports';
@ -33,9 +32,6 @@ export const XJsonEditor: FunctionComponent<Props> = ({ field, editorProps }) =>
value: xJson,
languageId: XJsonLang.ID,
options: { minimap: { enabled: false } },
editorDidMount: (m: any) => {
XJsonLang.registerGrammarChecker(m);
},
onChange,
...editorProps,
}}