mirror of
https://github.com/danbulant/monaco-yaml
synced 2026-05-19 04:08:48 +00:00
Convert classes to factory functions
TypeScript is better at inferring types when using simple functions and objects instead of classes. As a result many type annotations have now been removed without impacting type safety. Some other benefits are this can be minified better and private fields are now truly private variables.
This commit is contained in:
parent
bdfa1ef4e7
commit
8fa3ca4252
7 changed files with 355 additions and 345 deletions
1
index.d.ts
vendored
1
index.d.ts
vendored
|
|
@ -57,6 +57,7 @@ declare module 'monaco-editor/esm/vs/editor/editor.api' {
|
|||
|
||||
export interface LanguageServiceDefaults {
|
||||
readonly onDidChange: IEvent<LanguageServiceDefaults>;
|
||||
readonly languageId: string;
|
||||
readonly diagnosticsOptions: DiagnosticsOptions;
|
||||
setDiagnosticsOptions: (options: DiagnosticsOptions) => void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import {
|
|||
import * as ls from 'vscode-languageserver-types';
|
||||
import { CustomFormatterOptions } from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService';
|
||||
|
||||
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
|
||||
import { YAMLWorker } from './yamlWorker';
|
||||
|
||||
export type WorkerAccessor = (...more: Uri[]) => PromiseLike<YAMLWorker>;
|
||||
|
|
@ -48,85 +47,22 @@ function toDiagnostics(resource: Uri, diag: ls.Diagnostic): editor.IMarkerData {
|
|||
};
|
||||
}
|
||||
|
||||
export class DiagnosticsAdapter {
|
||||
private _disposables: IDisposable[] = [];
|
||||
private _listener: Record<string, IDisposable> = Object.create(null);
|
||||
export function createDiagnosticsAdapter(
|
||||
languageId: string,
|
||||
getWorker: WorkerAccessor,
|
||||
defaults: languages.yaml.LanguageServiceDefaults,
|
||||
): IDisposable {
|
||||
let disposables: IDisposable[] = [];
|
||||
const listeners: Record<string, IDisposable> = Object.create(null);
|
||||
|
||||
constructor(
|
||||
private _languageId: string,
|
||||
private _worker: WorkerAccessor,
|
||||
defaults: LanguageServiceDefaultsImpl,
|
||||
) {
|
||||
const onModelAdd = (model: editor.IModel): void => {
|
||||
const modeId = model.getModeId();
|
||||
if (modeId !== this._languageId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let handle: number;
|
||||
this._listener[String(toString)] = model.onDidChangeContent(() => {
|
||||
clearTimeout(handle);
|
||||
handle = setTimeout(() => this._doValidate(model.uri, modeId), 500);
|
||||
});
|
||||
|
||||
this._doValidate(model.uri, modeId);
|
||||
};
|
||||
|
||||
const onModelRemoved = (model: editor.IModel): void => {
|
||||
editor.setModelMarkers(model, this._languageId, []);
|
||||
const uriStr = String(model.uri);
|
||||
const listener = this._listener[uriStr];
|
||||
if (listener) {
|
||||
listener.dispose();
|
||||
delete this._listener[uriStr];
|
||||
}
|
||||
};
|
||||
|
||||
this._disposables.push(
|
||||
editor.onDidCreateModel(onModelAdd),
|
||||
editor.onWillDisposeModel((model) => {
|
||||
onModelRemoved(model);
|
||||
this._resetSchema(model.uri);
|
||||
}),
|
||||
editor.onDidChangeModelLanguage((event) => {
|
||||
onModelRemoved(event.model);
|
||||
onModelAdd(event.model);
|
||||
this._resetSchema(event.model.uri);
|
||||
}),
|
||||
defaults.onDidChange(() => {
|
||||
editor.getModels().forEach((model) => {
|
||||
if (model.getModeId() === this._languageId) {
|
||||
onModelRemoved(model);
|
||||
onModelAdd(model);
|
||||
}
|
||||
});
|
||||
}),
|
||||
{
|
||||
dispose: () => {
|
||||
editor.getModels().forEach(onModelRemoved);
|
||||
for (const disposable of Object.values(this._listener)) {
|
||||
disposable.dispose();
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
editor.getModels().forEach(onModelAdd);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._disposables.forEach((d) => d && d.dispose());
|
||||
this._disposables = [];
|
||||
}
|
||||
|
||||
private _resetSchema(resource: Uri): void {
|
||||
this._worker().then((worker) => {
|
||||
const resetSchema = (resource: Uri): void => {
|
||||
getWorker().then((worker) => {
|
||||
worker.resetSchema(String(resource));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private _doValidate(resource: Uri, languageId: string): void {
|
||||
this._worker(resource)
|
||||
const doValidate = (resource: Uri, languageId: string): void => {
|
||||
getWorker(resource)
|
||||
.then((worker) =>
|
||||
worker.doValidation(String(resource)).then((diagnostics) => {
|
||||
const markers = diagnostics.map((d) => toDiagnostics(resource, d));
|
||||
|
|
@ -139,7 +75,70 @@ export class DiagnosticsAdapter {
|
|||
.then(undefined, (err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onModelAdd = (model: editor.IModel): void => {
|
||||
const modeId = model.getModeId();
|
||||
if (modeId !== languageId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let handle: number;
|
||||
listeners[String(toString)] = model.onDidChangeContent(() => {
|
||||
clearTimeout(handle);
|
||||
handle = setTimeout(() => doValidate(model.uri, modeId), 500);
|
||||
});
|
||||
|
||||
doValidate(model.uri, modeId);
|
||||
};
|
||||
|
||||
const onModelRemoved = (model: editor.IModel): void => {
|
||||
editor.setModelMarkers(model, languageId, []);
|
||||
const uriStr = String(model.uri);
|
||||
const listener = listeners[uriStr];
|
||||
if (listener) {
|
||||
listener.dispose();
|
||||
delete listeners[uriStr];
|
||||
}
|
||||
};
|
||||
|
||||
disposables.push(
|
||||
editor.onDidCreateModel(onModelAdd),
|
||||
editor.onWillDisposeModel((model) => {
|
||||
onModelRemoved(model);
|
||||
resetSchema(model.uri);
|
||||
}),
|
||||
editor.onDidChangeModelLanguage((event) => {
|
||||
onModelRemoved(event.model);
|
||||
onModelAdd(event.model);
|
||||
resetSchema(event.model.uri);
|
||||
}),
|
||||
defaults.onDidChange(() => {
|
||||
editor.getModels().forEach((model) => {
|
||||
if (model.getModeId() === languageId) {
|
||||
onModelRemoved(model);
|
||||
onModelAdd(model);
|
||||
}
|
||||
});
|
||||
}),
|
||||
{
|
||||
dispose: () => {
|
||||
editor.getModels().forEach(onModelRemoved);
|
||||
for (const disposable of Object.values(listeners)) {
|
||||
disposable.dispose();
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
editor.getModels().forEach(onModelAdd);
|
||||
|
||||
return {
|
||||
dispose() {
|
||||
disposables.forEach((d) => d && d.dispose());
|
||||
disposables = [];
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// --- completion ------
|
||||
|
|
@ -218,64 +217,66 @@ function toTextEdit(textEdit: ls.TextEdit): editor.ISingleEditOperation {
|
|||
};
|
||||
}
|
||||
|
||||
export class CompletionAdapter implements languages.CompletionItemProvider {
|
||||
triggetCharacters = [' ', ':'];
|
||||
export function createCompletionItemProvider(
|
||||
getWorker: WorkerAccessor,
|
||||
): languages.CompletionItemProvider {
|
||||
return {
|
||||
triggerCharacters: [' ', ':'],
|
||||
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
provideCompletionItems(
|
||||
model: editor.IReadOnlyModel,
|
||||
position: Position,
|
||||
): PromiseLike<languages.CompletionList> {
|
||||
const resource = model.uri;
|
||||
|
||||
provideCompletionItems(
|
||||
model: editor.IReadOnlyModel,
|
||||
position: Position,
|
||||
): PromiseLike<languages.CompletionList> {
|
||||
const resource = model.uri;
|
||||
return getWorker(resource)
|
||||
.then((worker) => worker.doComplete(String(resource), fromPosition(position)))
|
||||
.then((info) => {
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this._worker(resource)
|
||||
.then((worker) => worker.doComplete(String(resource), fromPosition(position)))
|
||||
.then((info) => {
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
const wordInfo = model.getWordUntilPosition(position);
|
||||
const wordRange = new Range(
|
||||
position.lineNumber,
|
||||
wordInfo.startColumn,
|
||||
position.lineNumber,
|
||||
wordInfo.endColumn,
|
||||
);
|
||||
|
||||
const wordInfo = model.getWordUntilPosition(position);
|
||||
const wordRange = new Range(
|
||||
position.lineNumber,
|
||||
wordInfo.startColumn,
|
||||
position.lineNumber,
|
||||
wordInfo.endColumn,
|
||||
);
|
||||
const items = info.items.map((entry) => {
|
||||
const item: languages.CompletionItem = {
|
||||
label: entry.label,
|
||||
insertText: entry.insertText || entry.label,
|
||||
sortText: entry.sortText,
|
||||
filterText: entry.filterText,
|
||||
documentation: entry.documentation,
|
||||
detail: entry.detail,
|
||||
kind: toCompletionItemKind(entry.kind),
|
||||
range: wordRange,
|
||||
};
|
||||
if (entry.textEdit) {
|
||||
item.range = toRange(
|
||||
'range' in entry.textEdit ? entry.textEdit.range : entry.textEdit.replace,
|
||||
);
|
||||
item.insertText = entry.textEdit.newText;
|
||||
}
|
||||
if (entry.additionalTextEdits) {
|
||||
item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit);
|
||||
}
|
||||
if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) {
|
||||
item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
const items: languages.CompletionItem[] = info.items.map((entry) => {
|
||||
const item: languages.CompletionItem = {
|
||||
label: entry.label,
|
||||
insertText: entry.insertText || entry.label,
|
||||
sortText: entry.sortText,
|
||||
filterText: entry.filterText,
|
||||
documentation: entry.documentation,
|
||||
detail: entry.detail,
|
||||
kind: toCompletionItemKind(entry.kind),
|
||||
range: wordRange,
|
||||
return {
|
||||
isIncomplete: info.isIncomplete,
|
||||
suggestions: items,
|
||||
};
|
||||
if (entry.textEdit) {
|
||||
item.range = toRange(
|
||||
'range' in entry.textEdit ? entry.textEdit.range : entry.textEdit.replace,
|
||||
);
|
||||
item.insertText = entry.textEdit.newText;
|
||||
}
|
||||
if (entry.additionalTextEdits) {
|
||||
item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit);
|
||||
}
|
||||
if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) {
|
||||
item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
return {
|
||||
isIncomplete: info.isIncomplete,
|
||||
suggestions: items,
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function isMarkupContent(thing: unknown): thing is ls.MarkupContent {
|
||||
|
|
@ -316,24 +317,24 @@ function toMarkedStringArray(
|
|||
|
||||
// --- hover ------
|
||||
|
||||
export class HoverAdapter implements languages.HoverProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
export function createHoverProvider(getWorker: WorkerAccessor): languages.HoverProvider {
|
||||
return {
|
||||
provideHover(model, position) {
|
||||
const resource = model.uri;
|
||||
|
||||
provideHover(model: editor.IReadOnlyModel, position: Position): PromiseLike<languages.Hover> {
|
||||
const resource = model.uri;
|
||||
|
||||
return this._worker(resource)
|
||||
.then((worker) => worker.doHover(String(resource), fromPosition(position)))
|
||||
.then((info) => {
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
range: toRange(info.range),
|
||||
contents: toMarkedStringArray(info.contents),
|
||||
} as languages.Hover;
|
||||
});
|
||||
}
|
||||
return getWorker(resource)
|
||||
.then((worker) => worker.doHover(String(resource), fromPosition(position)))
|
||||
.then((info) => {
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
range: toRange(info.range),
|
||||
contents: toMarkedStringArray(info.contents),
|
||||
} as languages.Hover;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// --- document symbols ------
|
||||
|
|
@ -395,21 +396,23 @@ function toDocumentSymbol(item: ls.DocumentSymbol): languages.DocumentSymbol {
|
|||
};
|
||||
}
|
||||
|
||||
export class DocumentSymbolAdapter implements languages.DocumentSymbolProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
export function createDocumentSymbolProvider(
|
||||
getWorker: WorkerAccessor,
|
||||
): languages.DocumentSymbolProvider {
|
||||
return {
|
||||
provideDocumentSymbols(model) {
|
||||
const resource = model.uri;
|
||||
|
||||
provideDocumentSymbols(model: editor.IReadOnlyModel): PromiseLike<languages.DocumentSymbol[]> {
|
||||
const resource = model.uri;
|
||||
|
||||
return this._worker(resource)
|
||||
.then((worker) => worker.findDocumentSymbols(String(resource)))
|
||||
.then((items) => {
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
return items.map((item) => toDocumentSymbol(item));
|
||||
});
|
||||
}
|
||||
return getWorker(resource)
|
||||
.then((worker) => worker.findDocumentSymbols(String(resource)))
|
||||
.then((items) => {
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
return items.map((item) => toDocumentSymbol(item));
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function fromFormattingOptions(
|
||||
|
|
@ -422,22 +425,21 @@ function fromFormattingOptions(
|
|||
};
|
||||
}
|
||||
|
||||
export class DocumentFormattingEditProvider implements languages.DocumentFormattingEditProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
export function createDocumentFormattingEditProvider(
|
||||
getWorker: WorkerAccessor,
|
||||
): languages.DocumentFormattingEditProvider {
|
||||
return {
|
||||
provideDocumentFormattingEdits(model, options) {
|
||||
const resource = model.uri;
|
||||
|
||||
provideDocumentFormattingEdits(
|
||||
model: editor.IReadOnlyModel,
|
||||
options: languages.FormattingOptions,
|
||||
): PromiseLike<editor.ISingleEditOperation[]> {
|
||||
const resource = model.uri;
|
||||
|
||||
return this._worker(resource).then((worker) =>
|
||||
worker.format(String(resource), fromFormattingOptions(options)).then((edits) => {
|
||||
if (!edits || edits.length === 0) {
|
||||
return;
|
||||
}
|
||||
return edits.map(toTextEdit);
|
||||
}),
|
||||
);
|
||||
}
|
||||
return getWorker(resource).then((worker) =>
|
||||
worker.format(String(resource), fromFormattingOptions(options)).then((edits) => {
|
||||
if (!edits || edits.length === 0) {
|
||||
return;
|
||||
}
|
||||
return edits.map(toTextEdit);
|
||||
}),
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,36 @@
|
|||
import { Emitter, IEvent, languages } from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
import { Emitter, languages } from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
|
||||
import { setupMode } from './yamlMode';
|
||||
|
||||
// --- YAML configuration and defaults ---------
|
||||
|
||||
export class LanguageServiceDefaultsImpl implements languages.yaml.LanguageServiceDefaults {
|
||||
private _onDidChange = new Emitter<languages.yaml.LanguageServiceDefaults>();
|
||||
private _diagnosticsOptions: languages.yaml.DiagnosticsOptions;
|
||||
private _languageId: string;
|
||||
export function createLanguageServiceDefaults(
|
||||
languageId: string,
|
||||
initialDiagnosticsOptions: languages.yaml.DiagnosticsOptions,
|
||||
): languages.yaml.LanguageServiceDefaults {
|
||||
const onDidChange = new Emitter<languages.yaml.LanguageServiceDefaults>();
|
||||
let diagnosticsOptions = initialDiagnosticsOptions;
|
||||
|
||||
constructor(languageId: string, diagnosticsOptions: languages.yaml.DiagnosticsOptions) {
|
||||
this._languageId = languageId;
|
||||
this.setDiagnosticsOptions(diagnosticsOptions);
|
||||
}
|
||||
const languageServiceDefaults: languages.yaml.LanguageServiceDefaults = {
|
||||
get onDidChange() {
|
||||
return onDidChange.event;
|
||||
},
|
||||
|
||||
get onDidChange(): IEvent<languages.yaml.LanguageServiceDefaults> {
|
||||
return this._onDidChange.event;
|
||||
}
|
||||
get languageId() {
|
||||
return languageId;
|
||||
},
|
||||
|
||||
get languageId(): string {
|
||||
return this._languageId;
|
||||
}
|
||||
get diagnosticsOptions() {
|
||||
return diagnosticsOptions;
|
||||
},
|
||||
|
||||
get diagnosticsOptions(): languages.yaml.DiagnosticsOptions {
|
||||
return this._diagnosticsOptions;
|
||||
}
|
||||
setDiagnosticsOptions(options) {
|
||||
diagnosticsOptions = options || {};
|
||||
onDidChange.fire(languageServiceDefaults);
|
||||
},
|
||||
};
|
||||
|
||||
setDiagnosticsOptions(options: languages.yaml.DiagnosticsOptions): void {
|
||||
this._diagnosticsOptions = options || Object.create(null);
|
||||
this._onDidChange.fire(this);
|
||||
}
|
||||
return languageServiceDefaults;
|
||||
}
|
||||
|
||||
const diagnosticDefault: languages.yaml.DiagnosticsOptions = {
|
||||
|
|
@ -38,7 +39,7 @@ const diagnosticDefault: languages.yaml.DiagnosticsOptions = {
|
|||
enableSchemaRequest: false,
|
||||
};
|
||||
|
||||
const yamlDefaults = new LanguageServiceDefaultsImpl('yaml', diagnosticDefault);
|
||||
const yamlDefaults = createLanguageServiceDefaults('yaml', diagnosticDefault);
|
||||
|
||||
// Export API
|
||||
function createAPI(): typeof languages.yaml {
|
||||
|
|
|
|||
|
|
@ -1,85 +1,82 @@
|
|||
import { editor, IDisposable, Uri } from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
import { editor, IDisposable, languages, Uri } from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
|
||||
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
|
||||
import { YAMLWorker } from './yamlWorker';
|
||||
|
||||
export interface WorkerManager extends IDisposable {
|
||||
getLanguageServiceWorker: (...resources: Uri[]) => Promise<YAMLWorker>;
|
||||
}
|
||||
|
||||
// 2min
|
||||
const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000;
|
||||
|
||||
export class WorkerManager {
|
||||
private _defaults: LanguageServiceDefaultsImpl;
|
||||
private _idleCheckInterval: number;
|
||||
private _lastUsedTime: number;
|
||||
private _configChangeListener: IDisposable;
|
||||
export function createWorkerManager(
|
||||
defaults: languages.yaml.LanguageServiceDefaults,
|
||||
): WorkerManager {
|
||||
let worker: editor.MonacoWebWorker<YAMLWorker>;
|
||||
let client: Promise<YAMLWorker>;
|
||||
let lastUsedTime = 0;
|
||||
|
||||
private _worker: editor.MonacoWebWorker<YAMLWorker>;
|
||||
private _client: Promise<YAMLWorker>;
|
||||
|
||||
constructor(defaults: LanguageServiceDefaultsImpl) {
|
||||
this._defaults = defaults;
|
||||
this._worker = null;
|
||||
this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000);
|
||||
this._lastUsedTime = 0;
|
||||
this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker());
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
clearInterval(this._idleCheckInterval);
|
||||
this._configChangeListener.dispose();
|
||||
this._stopWorker();
|
||||
}
|
||||
|
||||
getLanguageServiceWorker(...resources: Uri[]): Promise<YAMLWorker> {
|
||||
let _client: YAMLWorker;
|
||||
return this._getClient()
|
||||
.then((client) => {
|
||||
_client = client;
|
||||
})
|
||||
.then(() => this._worker.withSyncedResources(resources))
|
||||
.then(() => _client);
|
||||
}
|
||||
|
||||
private _stopWorker(): void {
|
||||
if (this._worker) {
|
||||
this._worker.dispose();
|
||||
this._worker = null;
|
||||
const stopWorker = (): void => {
|
||||
if (worker) {
|
||||
worker.dispose();
|
||||
worker = null;
|
||||
}
|
||||
this._client = null;
|
||||
}
|
||||
client = null;
|
||||
};
|
||||
|
||||
private _checkIfIdle(): void {
|
||||
if (!this._worker) {
|
||||
const idleCheckInterval = setInterval(() => {
|
||||
if (!worker) {
|
||||
return;
|
||||
}
|
||||
const timePassedSinceLastUsed = Date.now() - this._lastUsedTime;
|
||||
const timePassedSinceLastUsed = Date.now() - lastUsedTime;
|
||||
if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) {
|
||||
this._stopWorker();
|
||||
stopWorker();
|
||||
}
|
||||
}
|
||||
}, 30 * 1000);
|
||||
|
||||
private _getClient(): Promise<YAMLWorker> {
|
||||
this._lastUsedTime = Date.now();
|
||||
const configChangeListener = defaults.onDidChange(() => stopWorker());
|
||||
|
||||
if (!this._client) {
|
||||
this._worker = editor.createWebWorker<YAMLWorker>({
|
||||
const getClient = (): Promise<YAMLWorker> => {
|
||||
lastUsedTime = Date.now();
|
||||
|
||||
if (!client) {
|
||||
worker = editor.createWebWorker<YAMLWorker>({
|
||||
// Module that exports the create() method and returns a `YAMLWorker` instance
|
||||
moduleId: 'vs/language/yaml/yamlWorker',
|
||||
|
||||
label: this._defaults.languageId,
|
||||
label: defaults.languageId,
|
||||
|
||||
// Passed in to the create() method
|
||||
createData: {
|
||||
languageSettings: this._defaults.diagnosticsOptions,
|
||||
languageId: this._defaults.languageId,
|
||||
enableSchemaRequest: this._defaults.diagnosticsOptions.enableSchemaRequest,
|
||||
prefix: this._defaults.diagnosticsOptions.prefix,
|
||||
isKubernetes: this._defaults.diagnosticsOptions.isKubernetes,
|
||||
languageSettings: defaults.diagnosticsOptions,
|
||||
languageId: defaults.languageId,
|
||||
enableSchemaRequest: defaults.diagnosticsOptions.enableSchemaRequest,
|
||||
prefix: defaults.diagnosticsOptions.prefix,
|
||||
isKubernetes: defaults.diagnosticsOptions.isKubernetes,
|
||||
},
|
||||
});
|
||||
|
||||
this._client = this._worker.getProxy();
|
||||
client = worker.getProxy();
|
||||
}
|
||||
|
||||
return this._client;
|
||||
}
|
||||
return client;
|
||||
};
|
||||
|
||||
return {
|
||||
dispose() {
|
||||
clearInterval(idleCheckInterval);
|
||||
configChangeListener.dispose();
|
||||
stopWorker();
|
||||
},
|
||||
|
||||
getLanguageServiceWorker(...resources) {
|
||||
let _client: YAMLWorker;
|
||||
return getClient()
|
||||
.then((client) => {
|
||||
_client = client;
|
||||
})
|
||||
.then(() => worker.withSyncedResources(resources))
|
||||
.then(() => _client);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import * as worker from 'monaco-editor/esm/vs/editor/editor.worker';
|
||||
import { initialize } from 'monaco-editor/esm/vs/editor/editor.worker';
|
||||
|
||||
import { YAMLWorker } from './yamlWorker';
|
||||
import { createYAMLWorker } from './yamlWorker';
|
||||
|
||||
self.onmessage = () => {
|
||||
// Ignore the first message
|
||||
worker.initialize((ctx, createData) => new YAMLWorker(ctx, createData));
|
||||
initialize((ctx, createData) => Object.create(createYAMLWorker(ctx, createData)));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
import { IDisposable, languages, Uri } from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
|
||||
import * as languageFeatures from './languageFeatures';
|
||||
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
|
||||
import { WorkerManager } from './workerManager';
|
||||
import {
|
||||
createCompletionItemProvider,
|
||||
createDiagnosticsAdapter,
|
||||
createDocumentFormattingEditProvider,
|
||||
createDocumentSymbolProvider,
|
||||
createHoverProvider,
|
||||
WorkerAccessor,
|
||||
} from './languageFeatures';
|
||||
import { createWorkerManager } from './workerManager';
|
||||
import { YAMLWorker } from './yamlWorker';
|
||||
|
||||
const richEditConfiguration: languages.LanguageConfiguration = {
|
||||
|
|
@ -37,32 +43,26 @@ const richEditConfiguration: languages.LanguageConfiguration = {
|
|||
],
|
||||
};
|
||||
|
||||
export function setupMode(defaults: LanguageServiceDefaultsImpl): void {
|
||||
export function setupMode(defaults: languages.yaml.LanguageServiceDefaults): void {
|
||||
const disposables: IDisposable[] = [];
|
||||
|
||||
const client = new WorkerManager(defaults);
|
||||
const client = createWorkerManager(defaults);
|
||||
disposables.push(client);
|
||||
|
||||
const worker: languageFeatures.WorkerAccessor = (...uris: Uri[]): Promise<YAMLWorker> =>
|
||||
const worker: WorkerAccessor = (...uris: Uri[]): Promise<YAMLWorker> =>
|
||||
client.getLanguageServiceWorker(...uris);
|
||||
|
||||
const { languageId } = defaults;
|
||||
|
||||
disposables.push(
|
||||
languages.registerCompletionItemProvider(
|
||||
languageId,
|
||||
new languageFeatures.CompletionAdapter(worker),
|
||||
),
|
||||
languages.registerHoverProvider(languageId, new languageFeatures.HoverAdapter(worker)),
|
||||
languages.registerDocumentSymbolProvider(
|
||||
languageId,
|
||||
new languageFeatures.DocumentSymbolAdapter(worker),
|
||||
),
|
||||
languages.registerCompletionItemProvider(languageId, createCompletionItemProvider(worker)),
|
||||
languages.registerHoverProvider(languageId, createHoverProvider(worker)),
|
||||
languages.registerDocumentSymbolProvider(languageId, createDocumentSymbolProvider(worker)),
|
||||
languages.registerDocumentFormattingEditProvider(
|
||||
languageId,
|
||||
new languageFeatures.DocumentFormattingEditProvider(worker),
|
||||
createDocumentFormattingEditProvider(worker),
|
||||
),
|
||||
new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults),
|
||||
createDiagnosticsAdapter(languageId, worker, defaults),
|
||||
languages.setLanguageConfiguration(languageId, richEditConfiguration),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import { worker } from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
import * as ls from 'vscode-languageserver-types';
|
||||
import * as yamlService from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService';
|
||||
import {
|
||||
CustomFormatterOptions,
|
||||
getLanguageService,
|
||||
LanguageSettings,
|
||||
} from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService';
|
||||
|
||||
let defaultSchemaRequestService: (url: string) => PromiseLike<string>;
|
||||
|
||||
|
|
@ -8,90 +12,96 @@ if (typeof fetch !== 'undefined') {
|
|||
defaultSchemaRequestService = (url) => fetch(url).then((response) => response.text());
|
||||
}
|
||||
|
||||
export class YAMLWorker {
|
||||
private _ctx: worker.IWorkerContext;
|
||||
private _languageService: yamlService.LanguageService;
|
||||
private _languageSettings: yamlService.LanguageSettings;
|
||||
private _languageId: string;
|
||||
private _isKubernetes: boolean;
|
||||
export interface YAMLWorker {
|
||||
doValidation: (uri: string) => PromiseLike<ls.Diagnostic[]>;
|
||||
|
||||
constructor(ctx: worker.IWorkerContext, createData: ICreateData) {
|
||||
const prefix = createData.prefix || '';
|
||||
const service = (url: string): PromiseLike<string> =>
|
||||
defaultSchemaRequestService(`${prefix}${url}`);
|
||||
this._ctx = ctx;
|
||||
this._languageSettings = createData.languageSettings;
|
||||
this._languageId = createData.languageId;
|
||||
this._languageService = yamlService.getLanguageService(
|
||||
createData.enableSchemaRequest && service,
|
||||
null,
|
||||
[],
|
||||
);
|
||||
this._isKubernetes = createData.isKubernetes || false;
|
||||
this._languageService.configure({
|
||||
...this._languageSettings,
|
||||
hover: true,
|
||||
isKubernetes: this._isKubernetes,
|
||||
});
|
||||
}
|
||||
doComplete: (uri: string, position: ls.Position) => PromiseLike<ls.CompletionList>;
|
||||
|
||||
doValidation(uri: string): PromiseLike<ls.Diagnostic[]> {
|
||||
const document = this._getTextDocument(uri);
|
||||
if (document) {
|
||||
return this._languageService.doValidation(document, this._isKubernetes);
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
doResolve: (item: ls.CompletionItem) => PromiseLike<ls.CompletionItem>;
|
||||
|
||||
doComplete(uri: string, position: ls.Position): PromiseLike<ls.CompletionList> {
|
||||
const document = this._getTextDocument(uri);
|
||||
return this._languageService.doComplete(document, position, this._isKubernetes);
|
||||
}
|
||||
doHover: (uri: string, position: ls.Position) => PromiseLike<ls.Hover>;
|
||||
|
||||
doResolve(item: ls.CompletionItem): PromiseLike<ls.CompletionItem> {
|
||||
return this._languageService.doResolve(item);
|
||||
}
|
||||
format: (uri: string, options: CustomFormatterOptions) => PromiseLike<ls.TextEdit[]>;
|
||||
|
||||
doHover(uri: string, position: ls.Position): PromiseLike<ls.Hover> {
|
||||
const document = this._getTextDocument(uri);
|
||||
return this._languageService.doHover(document, position);
|
||||
}
|
||||
resetSchema: (uri: string) => PromiseLike<boolean>;
|
||||
|
||||
format(uri: string, options: yamlService.CustomFormatterOptions): PromiseLike<ls.TextEdit[]> {
|
||||
const document = this._getTextDocument(uri);
|
||||
const textEdits = this._languageService.doFormat(document, options);
|
||||
return Promise.resolve(textEdits);
|
||||
}
|
||||
findDocumentSymbols: (uri: string) => PromiseLike<ls.DocumentSymbol[]>;
|
||||
}
|
||||
|
||||
resetSchema(uri: string): PromiseLike<boolean> {
|
||||
return Promise.resolve(this._languageService.resetSchema(uri));
|
||||
}
|
||||
export function createYAMLWorker(
|
||||
ctx: worker.IWorkerContext,
|
||||
{
|
||||
enableSchemaRequest,
|
||||
isKubernetes = false,
|
||||
languageId,
|
||||
languageSettings,
|
||||
prefix = '',
|
||||
}: ICreateData,
|
||||
): YAMLWorker {
|
||||
const service = (url: string): PromiseLike<string> =>
|
||||
defaultSchemaRequestService(`${prefix}${url}`);
|
||||
const languageService = getLanguageService(enableSchemaRequest && service, null, []);
|
||||
languageService.configure({
|
||||
...languageSettings,
|
||||
hover: true,
|
||||
isKubernetes,
|
||||
});
|
||||
|
||||
findDocumentSymbols(uri: string): PromiseLike<ls.DocumentSymbol[]> {
|
||||
const document = this._getTextDocument(uri);
|
||||
const symbols = this._languageService.findDocumentSymbols2(document);
|
||||
return Promise.resolve(symbols);
|
||||
}
|
||||
|
||||
private _getTextDocument(uri: string): ls.TextDocument {
|
||||
const models = this._ctx.getMirrorModels();
|
||||
const getTextDocument = (uri: string): ls.TextDocument => {
|
||||
const models = ctx.getMirrorModels();
|
||||
for (const model of models) {
|
||||
if (String(model.uri) === uri) {
|
||||
return ls.TextDocument.create(uri, this._languageId, model.version, model.getValue());
|
||||
return ls.TextDocument.create(uri, languageId, model.version, model.getValue());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
doValidation(uri) {
|
||||
const document = getTextDocument(uri);
|
||||
if (document) {
|
||||
return languageService.doValidation(document, isKubernetes);
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
},
|
||||
|
||||
doComplete(uri, position) {
|
||||
const document = getTextDocument(uri);
|
||||
return languageService.doComplete(document, position, isKubernetes);
|
||||
},
|
||||
|
||||
doResolve(item) {
|
||||
return languageService.doResolve(item);
|
||||
},
|
||||
|
||||
doHover(uri, position) {
|
||||
const document = getTextDocument(uri);
|
||||
return languageService.doHover(document, position);
|
||||
},
|
||||
|
||||
format(uri, options) {
|
||||
const document = getTextDocument(uri);
|
||||
const textEdits = languageService.doFormat(document, options);
|
||||
return Promise.resolve(textEdits);
|
||||
},
|
||||
|
||||
resetSchema(uri) {
|
||||
return Promise.resolve(languageService.resetSchema(uri));
|
||||
},
|
||||
|
||||
findDocumentSymbols(uri) {
|
||||
const document = getTextDocument(uri);
|
||||
const symbols = languageService.findDocumentSymbols2(document);
|
||||
return Promise.resolve(symbols);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export interface ICreateData {
|
||||
languageId: string;
|
||||
languageSettings: yamlService.LanguageSettings;
|
||||
languageSettings: LanguageSettings;
|
||||
enableSchemaRequest: boolean;
|
||||
prefix?: string;
|
||||
isKubernetes?: boolean;
|
||||
}
|
||||
|
||||
export function create(ctx: worker.IWorkerContext, createData: ICreateData): YAMLWorker {
|
||||
return new YAMLWorker(ctx, createData);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue