Skip to content

Commit

Permalink
Contribute to html language server with a custom language.
Browse files Browse the repository at this point in the history
Fixes microsoft#146730

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Apr 5, 2022
1 parent 3c3c149 commit ecc8637
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 10 deletions.
8 changes: 7 additions & 1 deletion extensions/handlebars/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,16 @@
"scopeName": "text.html.handlebars",
"path": "./syntaxes/Handlebars.tmLanguage.json"
}
],
"htmlLanguages": [
{
"languageId": "handlebars",
"autoInsert": true
}
]
},
"repository": {
"type": "git",
"url": "https://github.com/microsoft/vscode.git"
}
}
}
9 changes: 5 additions & 4 deletions extensions/html-language-features/client/src/htmlClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { FileSystemProvider, serveFileSystemRequests } from './requests';
import { getCustomDataSource } from './customData';
import { activateAutoInsertion } from './autoInsertion';
import { collectHtmlLanguageContributions, getSupportedLanguagesAutoInsert, getDocumentSelector, HtmlLanguageContribution } from './htmlLanguageContribution';

namespace CustomDataChangedNotification {
export const type: NotificationType<string[]> = new NotificationType('html/customDataChanged');
Expand Down Expand Up @@ -87,8 +88,8 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua

let toDispose = context.subscriptions;


let documentSelector = ['html', 'handlebars'];
const htmlContributions: HtmlLanguageContribution[] = collectHtmlLanguageContributions(extensions.all);
let documentSelector = getDocumentSelector(htmlContributions);
let embeddedLanguages = { css: true, javascript: true };

let rangeFormatting: Disposable | undefined = undefined;
Expand Down Expand Up @@ -158,7 +159,8 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
};
return client.sendRequest(AutoInsertRequest.type, param);
};
let disposable = activateAutoInsertion(insertRequestor, { html: true, handlebars: true }, runtime);
const supportedLanguages = getSupportedLanguagesAutoInsert(htmlContributions);
let disposable = activateAutoInsertion(insertRequestor, supportedLanguages, runtime);
toDispose.push(disposable);

disposable = client.onTelemetry(e => {
Expand Down Expand Up @@ -299,5 +301,4 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
toDispose.push(activeEditorListener);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { DocumentSelector } from 'vscode-languageclient';
import { isDeepStrictEqual } from 'util';

const RELOAD_WINDOW = 'workbench.action.reloadWindow';

let existingExtensions: HtmlLanguageContribution[];

/**
* Html language contribution.
*/
export interface HtmlLanguageContribution {
languageId: string;
autoInsert: false;
}

/**
* Returns all Html language contributions from package.json
*
* @param extensions array of extensions to search contributions from
*/
export function collectHtmlLanguageContributions(extensions: readonly vscode.Extension<any>[]): HtmlLanguageContribution[] {
const result: HtmlLanguageContribution[] = [];
if (extensions && extensions.length) {
for (const extension of extensions) {
const htmlLanguages = extension.packageJSON?.contributes?.htmlLanguages;
if (Array.isArray(htmlLanguages)) {
htmlLanguages.forEach(htmlLanguage => {
const htmlLanguageContribution = createHtmlLanguageContribution(htmlLanguage);
if (htmlLanguageContribution) {
result.push(htmlLanguageContribution);
}
});
}
}
}
// Make a copy of extensions:
existingExtensions = result.slice();
return result;
}

export function handleExtensionChange(extensions: readonly vscode.Extension<any>[]): void {
if (!existingExtensions) {
return;
}
const oldExtensions = new Set(existingExtensions.slice());
const newExtensions = collectHtmlLanguageContributions(extensions);
let hasChanged = (oldExtensions.size !== newExtensions.length);
if (!hasChanged) {
for (const newExtension of newExtensions) {
let found = false;
for (const oldExtension of oldExtensions) {
if (isDeepStrictEqual(oldExtension, newExtension)) {
found = true;
break;
}
}
if (found) {
continue;
} else {
hasChanged = true;
break;
}
}
}

if (hasChanged) {
const msg = `Extensions to the Html Language Server changed, reloading ${vscode.env.appName} is required for the changes to take effect.`;
const action = 'Reload';
vscode.window.showWarningMessage(msg, action).then((selection) => {
if (action === selection) {
vscode.commands.executeCommand(RELOAD_WINDOW);
}
});
}
}

/**
* Returns the document selector.
*
* The returned document selector contains the html document selectors
* and all document selectors contained in `htmlContributions`.
*
* @param htmlContributions Html language server contributions from other VS Code extensions
*/
export function getDocumentSelector(htmlContributions: HtmlLanguageContribution[]): DocumentSelector {
let documentSelector: DocumentSelector = [
'html'
];
htmlContributions.forEach((contribution: HtmlLanguageContribution) => {
documentSelector = documentSelector.concat(contribution.languageId);
});
return documentSelector;
}

export function getSupportedLanguagesAutoInsert(htmlContributions: HtmlLanguageContribution[]): { [id: string]: boolean } {
const supportedLanguages: { [id: string]: boolean } = { html: true };
htmlContributions.forEach((contribution: HtmlLanguageContribution) => {
supportedLanguages[contribution.languageId] = contribution.autoInsert;
});
return supportedLanguages;
}

function createHtmlLanguageContribution(section: any): HtmlLanguageContribution | undefined {
const languageId: string | undefined = section.languageId;
if (!languageId) {
return;
}
const autoInsert = section.autoInsert === true ? true : false;
return { languageId, autoInsert } as HtmlLanguageContribution;
}
32 changes: 27 additions & 5 deletions extensions/html-language-features/schemas/package.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,37 @@
"contributes": {
"type": "object",
"properties": {
"html.customData": {
"html": {
"type": "object",
"properties": {
"customData": {
"type": "array",
"markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-html-languageservice/blob/master/docs/customData.md).\n\nVS Code loads custom data on startup to enhance its HTML support for the custom HTML tags, attributes and attribute values you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.",
"items": {
"type": "string",
"description": "Relative path to a HTML custom data file"
}
}
}
},
"htmlLanguages": {
"type": "array",
"markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-html-languageservice/blob/master/docs/customData.md).\n\nVS Code loads custom data on startup to enhance its HTML support for the custom HTML tags, attributes and attribute values you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.",
"description": "A list of custom languages which contributes to the Html language server.",
"items": {
"type": "string",
"description": "Relative path to a HTML custom data file"
"type": "object",
"properties": {
"languageId": {
"type": "object",
"description": "The language Id which defines the custom language."
},
"autoInsert": {
"type": "boolean",
"description": "true if the custom language activates the auto insertion and false otherwise."
}
}
}
}
}
}
}
}
}

0 comments on commit ecc8637

Please sign in to comment.