mirror of
https://github.com/microsoft/monaco-editor.git
synced 2025-12-22 11:35:40 +01:00
Support html custom data. For microsoft/monaco-editor#2284
This commit is contained in:
parent
e3f8dd8f34
commit
c8b5d5b6d5
7 changed files with 165 additions and 161 deletions
63
monaco.d.ts
vendored
63
monaco.d.ts
vendored
|
|
@ -21,7 +21,7 @@ declare namespace monaco.languages.html {
|
|||
readonly wrapAttributes: 'auto' | 'force' | 'force-aligned' | 'force-expand-multiline';
|
||||
}
|
||||
export interface CompletionConfiguration {
|
||||
[provider: string]: boolean;
|
||||
[providerId: string]: boolean;
|
||||
}
|
||||
export interface Options {
|
||||
/**
|
||||
|
|
@ -32,6 +32,10 @@ declare namespace monaco.languages.html {
|
|||
* A list of known schemas and/or associations of schemas to file names.
|
||||
*/
|
||||
readonly suggest?: CompletionConfiguration;
|
||||
/**
|
||||
* Configures the HTML data types known by the HTML langauge service.
|
||||
*/
|
||||
readonly data?: HTMLDataConfiguration;
|
||||
}
|
||||
export interface ModeConfiguration {
|
||||
/**
|
||||
|
|
@ -102,9 +106,9 @@ declare namespace monaco.languages.html {
|
|||
}
|
||||
/**
|
||||
* Registers a new HTML language service for the languageId.
|
||||
* Note: 'html', 'handlebar' and 'razor' registered by default.
|
||||
* Note: 'html', 'handlebar' and 'razor' are registered by default.
|
||||
*
|
||||
* Use this method only to register additional language ids with a HTML service.
|
||||
* Use this method to register additional language ids with a HTML service.
|
||||
* The language server has to be registered before an editor model is opened.
|
||||
*/
|
||||
export function registerHTMLLanguageService(
|
||||
|
|
@ -112,4 +116,57 @@ declare namespace monaco.languages.html {
|
|||
options: Options,
|
||||
modeConfiguration: ModeConfiguration
|
||||
): LanguageServiceRegistration;
|
||||
export interface HTMLDataConfiguration {
|
||||
/**
|
||||
* Defines whether the standard HTML tags and attributes are shown
|
||||
*/
|
||||
useDefaultDataProvider?: boolean;
|
||||
/**
|
||||
* Provides a set of custom data providers.
|
||||
*/
|
||||
dataProviders?: {
|
||||
[providerId: string]: HTMLDataV1;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Custom HTML tags attributes and attribute values
|
||||
* https://github.com/microsoft/vscode-html-languageservice/blob/main/docs/customData.md
|
||||
*/
|
||||
export interface HTMLDataV1 {
|
||||
version: 1 | 1.1;
|
||||
tags?: ITagData[];
|
||||
globalAttributes?: IAttributeData[];
|
||||
valueSets?: IValueSet[];
|
||||
}
|
||||
export interface IReference {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
export interface ITagData {
|
||||
name: string;
|
||||
description?: string | MarkupContent;
|
||||
attributes: IAttributeData[];
|
||||
references?: IReference[];
|
||||
}
|
||||
export interface IAttributeData {
|
||||
name: string;
|
||||
description?: string | MarkupContent;
|
||||
valueSet?: string;
|
||||
values?: IValueData[];
|
||||
references?: IReference[];
|
||||
}
|
||||
export interface IValueData {
|
||||
name: string;
|
||||
description?: string | MarkupContent;
|
||||
references?: IReference[];
|
||||
}
|
||||
export interface IValueSet {
|
||||
name: string;
|
||||
values: IValueData[];
|
||||
}
|
||||
export interface MarkupContent {
|
||||
kind: MarkupKind;
|
||||
value: string;
|
||||
}
|
||||
export type MarkupKind = 'plaintext' | 'markdown';
|
||||
}
|
||||
|
|
|
|||
14
package-lock.json
generated
14
package-lock.json
generated
|
|
@ -443,15 +443,23 @@
|
|||
"dev": true
|
||||
},
|
||||
"vscode-html-languageservice": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-4.0.1.tgz",
|
||||
"integrity": "sha512-CZtnuQoDwZdmPLKLMC6RqFlRTw0jvZK71l53u5ZIM3hSoVKAqW33gahBVNFpC3TPFxZSx0jqEhBTLf37RUMkWg==",
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-4.0.5.tgz",
|
||||
"integrity": "sha512-9ZKp7nfR6ObUA+K65GfgDPdOmXaPH8MOWxE2RwWF3tVnVMq2w+COKjDNHMvv+uNxtmaRT7/skls7CD/HzrW99w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"vscode-languageserver-textdocument": "^1.0.1",
|
||||
"vscode-languageserver-types": "^3.16.0",
|
||||
"vscode-nls": "^5.0.0",
|
||||
"vscode-uri": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-languageserver-types": {
|
||||
"version": "3.16.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz",
|
||||
"integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"vscode-languageserver-textdocument": {
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@
|
|||
"prettier": "^2.2.1",
|
||||
"pretty-quick": "^3.1.0",
|
||||
"requirejs": "^2.3.6",
|
||||
"typescript": "^4.2.3",
|
||||
"terser": "^5.6.0",
|
||||
"vscode-html-languageservice": "4.0.1",
|
||||
"typescript": "^4.2.3",
|
||||
"vscode-html-languageservice": "^4.0.5",
|
||||
"vscode-languageserver-types": "3.16.0",
|
||||
"vscode-languageserver-textdocument": "^1.0.1"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ export function setupMode1(defaults: LanguageServiceDefaults): void {
|
|||
languageId,
|
||||
new languageFeatures.DocumentRangeFormattingEditProvider(worker)
|
||||
);
|
||||
new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,9 +144,6 @@ export function setupMode(defaults: LanguageServiceDefaults): IDisposable {
|
|||
)
|
||||
);
|
||||
}
|
||||
if (modeConfiguration.diagnostics) {
|
||||
providers.push(new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults));
|
||||
}
|
||||
}
|
||||
|
||||
registerProviders();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
import { worker } from './fillers/monaco-editor-core';
|
||||
import * as htmlService from 'vscode-html-languageservice';
|
||||
import type { Options } from './monaco.contribution';
|
||||
import { IHTMLDataProvider } from 'vscode-html-languageservice';
|
||||
|
||||
export class HTMLWorker {
|
||||
private _ctx: worker.IWorkerContext;
|
||||
|
|
@ -17,13 +18,19 @@ export class HTMLWorker {
|
|||
this._ctx = ctx;
|
||||
this._languageSettings = createData.languageSettings;
|
||||
this._languageId = createData.languageId;
|
||||
this._languageService = htmlService.getLanguageService();
|
||||
|
||||
const data = this._languageSettings.data;
|
||||
|
||||
const useDefaultDataProvider = data?.useDefaultDataProvider;
|
||||
const customDataProviders: IHTMLDataProvider[] = [];
|
||||
if (data?.dataProviders) {
|
||||
for (const id in data.dataProviders) {
|
||||
customDataProviders.push(htmlService.newHTMLDataProvider(id, data.dataProviders[id]));
|
||||
}
|
||||
}
|
||||
this._languageService = htmlService.getLanguageService({ useDefaultDataProvider, customDataProviders });
|
||||
}
|
||||
|
||||
async doValidation(uri: string): Promise<htmlService.Diagnostic[]> {
|
||||
// not yet suported
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
async doComplete(
|
||||
uri: string,
|
||||
position: htmlService.Position
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { LanguageServiceDefaults } from './monaco.contribution';
|
||||
import type { HTMLWorker } from './htmlWorker';
|
||||
import * as htmlService from 'vscode-html-languageservice';
|
||||
import {
|
||||
|
|
@ -13,139 +12,13 @@ import {
|
|||
Position,
|
||||
Range,
|
||||
CancellationToken,
|
||||
IDisposable,
|
||||
MarkerSeverity,
|
||||
IMarkdownString
|
||||
} from './fillers/monaco-editor-core';
|
||||
import { InsertReplaceEdit, TextEdit } from 'vscode-html-languageservice';
|
||||
|
||||
export interface WorkerAccessor {
|
||||
(...more: Uri[]): Promise<HTMLWorker>;
|
||||
}
|
||||
|
||||
// --- diagnostics --- ---
|
||||
|
||||
export class DiagnosticsAdapter {
|
||||
private _disposables: IDisposable[] = [];
|
||||
private _listener: { [uri: string]: IDisposable } = Object.create(null);
|
||||
|
||||
constructor(
|
||||
private _languageId: string,
|
||||
private _worker: WorkerAccessor,
|
||||
defaults: LanguageServiceDefaults
|
||||
) {
|
||||
const onModelAdd = (model: editor.IModel): void => {
|
||||
const modeId = model.getModeId();
|
||||
if (modeId !== this._languageId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let handle: number;
|
||||
this._listener[model.uri.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 = model.uri.toString();
|
||||
const listener = this._listener[uriStr];
|
||||
if (listener) {
|
||||
listener.dispose();
|
||||
delete this._listener[uriStr];
|
||||
}
|
||||
};
|
||||
|
||||
this._disposables.push(editor.onDidCreateModel(onModelAdd));
|
||||
this._disposables.push(
|
||||
editor.onWillDisposeModel((model) => {
|
||||
onModelRemoved(model);
|
||||
})
|
||||
);
|
||||
this._disposables.push(
|
||||
editor.onDidChangeModelLanguage((event) => {
|
||||
onModelRemoved(event.model);
|
||||
onModelAdd(event.model);
|
||||
})
|
||||
);
|
||||
|
||||
this._disposables.push(
|
||||
defaults.onDidChange((_) => {
|
||||
editor.getModels().forEach((model) => {
|
||||
if (model.getModeId() === this._languageId) {
|
||||
onModelRemoved(model);
|
||||
onModelAdd(model);
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
this._disposables.push({
|
||||
dispose: () => {
|
||||
for (const key in this._listener) {
|
||||
this._listener[key].dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
editor.getModels().forEach(onModelAdd);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._disposables.forEach((d) => d && d.dispose());
|
||||
this._disposables = [];
|
||||
}
|
||||
|
||||
private _doValidate(resource: Uri, languageId: string): void {
|
||||
this._worker(resource)
|
||||
.then((worker) => {
|
||||
return worker.doValidation(resource.toString()).then((diagnostics) => {
|
||||
const markers = diagnostics.map((d) => toDiagnostics(resource, d));
|
||||
const model = editor.getModel(resource);
|
||||
if (model && model.getModeId() === languageId) {
|
||||
editor.setModelMarkers(model, languageId, markers);
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(undefined, (err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toSeverity(lsSeverity: number): MarkerSeverity {
|
||||
switch (lsSeverity) {
|
||||
case htmlService.DiagnosticSeverity.Error:
|
||||
return MarkerSeverity.Error;
|
||||
case htmlService.DiagnosticSeverity.Warning:
|
||||
return MarkerSeverity.Warning;
|
||||
case htmlService.DiagnosticSeverity.Information:
|
||||
return MarkerSeverity.Info;
|
||||
case htmlService.DiagnosticSeverity.Hint:
|
||||
return MarkerSeverity.Hint;
|
||||
default:
|
||||
return MarkerSeverity.Info;
|
||||
}
|
||||
}
|
||||
|
||||
function toDiagnostics(resource: Uri, diag: htmlService.Diagnostic): editor.IMarkerData {
|
||||
const code = typeof diag.code === 'number' ? String(diag.code) : <string>diag.code;
|
||||
|
||||
return {
|
||||
severity: toSeverity(diag.severity),
|
||||
startLineNumber: diag.range.start.line + 1,
|
||||
startColumn: diag.range.start.character + 1,
|
||||
endLineNumber: diag.range.end.line + 1,
|
||||
endColumn: diag.range.end.character + 1,
|
||||
message: diag.message,
|
||||
code: code,
|
||||
source: diag.source
|
||||
};
|
||||
}
|
||||
|
||||
// --- completion ------
|
||||
|
||||
function fromPosition(position: Position): htmlService.Position {
|
||||
|
|
@ -177,10 +50,10 @@ function toRange(range: htmlService.Range): Range {
|
|||
);
|
||||
}
|
||||
|
||||
function isInsertReplaceEdit(edit: TextEdit | InsertReplaceEdit): edit is InsertReplaceEdit {
|
||||
function isInsertReplaceEdit(edit: htmlService.TextEdit | htmlService.InsertReplaceEdit): edit is htmlService.InsertReplaceEdit {
|
||||
return (
|
||||
typeof (<InsertReplaceEdit>edit).insert !== 'undefined' &&
|
||||
typeof (<InsertReplaceEdit>edit).replace !== 'undefined'
|
||||
typeof (<htmlService.InsertReplaceEdit>edit).insert !== 'undefined' &&
|
||||
typeof (<htmlService.InsertReplaceEdit>edit).replace !== 'undefined'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -285,7 +158,7 @@ function toTextEdit(textEdit: htmlService.TextEdit): editor.ISingleEditOperation
|
|||
}
|
||||
|
||||
export class CompletionAdapter implements languages.CompletionItemProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
public get triggerCharacters(): string[] {
|
||||
return ['.', ':', '<', '"', '=', '/'];
|
||||
|
|
@ -399,7 +272,7 @@ function toMarkedStringArray(
|
|||
}
|
||||
|
||||
export class HoverAdapter implements languages.HoverProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
provideHover(
|
||||
model: editor.IReadOnlyModel,
|
||||
|
|
@ -441,7 +314,7 @@ function toHighlighKind(kind: htmlService.DocumentHighlightKind): languages.Docu
|
|||
}
|
||||
|
||||
export class DocumentHighlightAdapter implements languages.DocumentHighlightProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
public provideDocumentHighlights(
|
||||
model: editor.IReadOnlyModel,
|
||||
|
|
@ -511,7 +384,7 @@ function toSymbolKind(kind: htmlService.SymbolKind): languages.SymbolKind {
|
|||
}
|
||||
|
||||
export class DocumentSymbolAdapter implements languages.DocumentSymbolProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
public provideDocumentSymbols(
|
||||
model: editor.IReadOnlyModel,
|
||||
|
|
@ -539,7 +412,7 @@ export class DocumentSymbolAdapter implements languages.DocumentSymbolProvider {
|
|||
}
|
||||
|
||||
export class DocumentLinkAdapter implements languages.LinkProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
public provideLinks(
|
||||
model: editor.IReadOnlyModel,
|
||||
|
|
@ -573,7 +446,7 @@ function fromFormattingOptions(
|
|||
}
|
||||
|
||||
export class DocumentFormattingEditProvider implements languages.DocumentFormattingEditProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
public provideDocumentFormattingEdits(
|
||||
model: editor.IReadOnlyModel,
|
||||
|
|
@ -597,7 +470,7 @@ export class DocumentFormattingEditProvider implements languages.DocumentFormatt
|
|||
|
||||
export class DocumentRangeFormattingEditProvider
|
||||
implements languages.DocumentRangeFormattingEditProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
public provideDocumentRangeFormattingEdits(
|
||||
model: editor.IReadOnlyModel,
|
||||
|
|
@ -621,7 +494,7 @@ export class DocumentRangeFormattingEditProvider
|
|||
}
|
||||
|
||||
export class RenameAdapter implements languages.RenameProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
provideRenameEdits(
|
||||
model: editor.IReadOnlyModel,
|
||||
|
|
@ -664,7 +537,7 @@ function toWorkspaceEdit(edit: htmlService.WorkspaceEdit): languages.WorkspaceEd
|
|||
}
|
||||
|
||||
export class FoldingRangeAdapter implements languages.FoldingRangeProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
public provideFoldingRanges(
|
||||
model: editor.IReadOnlyModel,
|
||||
|
|
@ -705,7 +578,7 @@ function toFoldingRangeKind(kind: htmlService.FoldingRangeKind): languages.Foldi
|
|||
}
|
||||
|
||||
export class SelectionRangeAdapter implements languages.SelectionRangeProvider {
|
||||
constructor(private _worker: WorkerAccessor) {}
|
||||
constructor(private _worker: WorkerAccessor) { }
|
||||
|
||||
public provideSelectionRanges(
|
||||
model: editor.IReadOnlyModel,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export interface HTMLFormatConfiguration {
|
|||
}
|
||||
|
||||
export interface CompletionConfiguration {
|
||||
[provider: string]: boolean;
|
||||
[providerId: string]: boolean;
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
|
|
@ -34,6 +34,10 @@ export interface Options {
|
|||
* A list of known schemas and/or associations of schemas to file names.
|
||||
*/
|
||||
readonly suggest?: CompletionConfiguration;
|
||||
/**
|
||||
* Configures the HTML data types known by the HTML langauge service.
|
||||
*/
|
||||
readonly data?: HTMLDataConfiguration;
|
||||
}
|
||||
|
||||
export interface ModeConfiguration {
|
||||
|
|
@ -165,17 +169,20 @@ const formatDefaults: Required<HTMLFormatConfiguration> = {
|
|||
|
||||
const htmlOptionsDefault: Required<Options> = {
|
||||
format: formatDefaults,
|
||||
suggest: { html5: true, angular1: true, ionic: true }
|
||||
suggest: { html5: true, angular1: true, ionic: true },
|
||||
data: { useDefaultDataProvider: true }
|
||||
};
|
||||
|
||||
const handlebarOptionsDefault: Required<Options> = {
|
||||
format: formatDefaults,
|
||||
suggest: { html5: true }
|
||||
suggest: { html5: true },
|
||||
data: { useDefaultDataProvider: true }
|
||||
};
|
||||
|
||||
const razorOptionsDefault: Required<Options> = {
|
||||
format: formatDefaults,
|
||||
suggest: { html5: true, razor: true }
|
||||
suggest: { html5: true, razor: true },
|
||||
data: { useDefaultDataProvider: true }
|
||||
};
|
||||
|
||||
function getConfigurationDefault(languageId: string): Required<ModeConfiguration> {
|
||||
|
|
@ -261,3 +268,59 @@ export function registerHTMLLanguageService(
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
export interface HTMLDataConfiguration {
|
||||
/**
|
||||
* Defines whether the standard HTML tags and attributes are shown
|
||||
*/
|
||||
useDefaultDataProvider?: boolean;
|
||||
/**
|
||||
* Provides a set of custom data providers.
|
||||
*/
|
||||
dataProviders?: { [providerId: string]: HTMLDataV1 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom HTML tags attributes and attribute values
|
||||
* https://github.com/microsoft/vscode-html-languageservice/blob/main/docs/customData.md
|
||||
*/
|
||||
export interface HTMLDataV1 {
|
||||
version: 1 | 1.1;
|
||||
tags?: ITagData[];
|
||||
globalAttributes?: IAttributeData[];
|
||||
valueSets?: IValueSet[];
|
||||
}
|
||||
|
||||
export interface IReference {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
export interface ITagData {
|
||||
name: string;
|
||||
description?: string | MarkupContent;
|
||||
attributes: IAttributeData[];
|
||||
references?: IReference[];
|
||||
}
|
||||
export interface IAttributeData {
|
||||
name: string;
|
||||
description?: string | MarkupContent;
|
||||
valueSet?: string;
|
||||
values?: IValueData[];
|
||||
references?: IReference[];
|
||||
}
|
||||
export interface IValueData {
|
||||
name: string;
|
||||
description?: string | MarkupContent;
|
||||
references?: IReference[];
|
||||
}
|
||||
export interface IValueSet {
|
||||
name: string;
|
||||
values: IValueData[];
|
||||
}
|
||||
export interface MarkupContent {
|
||||
kind: MarkupKind;
|
||||
value: string;
|
||||
}
|
||||
export declare type MarkupKind = 'plaintext' | 'markdown';
|
||||
Loading…
Add table
Add a link
Reference in a new issue