forked from microsoft/vscode
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Contribute to html language server with a custom language.
Fixes microsoft#146730 Signed-off-by: azerr <[email protected]>
- Loading branch information
1 parent
145e593
commit 7a2af7d
Showing
3 changed files
with
174 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
157 changes: 157 additions & 0 deletions
157
extensions/html-language-features/client/src/htmlExtension.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* 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 { DocumentFilter, DocumentSelector } from 'vscode-languageclient'; | ||
import { isDeepStrictEqual } from 'util'; | ||
|
||
const RELOAD_WINDOW = 'workbench.action.reloadWindow'; | ||
|
||
let existingExtensions: HtmlContribution[]; | ||
|
||
/** | ||
* Html language contribution | ||
*/ | ||
export interface HtmlContribution { | ||
documentSelector: DocumentSelector; | ||
activateAutoInsertion: false; | ||
} | ||
|
||
/** | ||
* Returns all Html language contributions from package.json | ||
* | ||
* @param extensions array of extensions to search contributions from | ||
*/ | ||
export function collectHtmlExtensions(extensions: readonly vscode.Extension<any>[]): HtmlContribution[] { | ||
const result: HtmlContribution[] = []; | ||
if (extensions && extensions.length) { | ||
for (const extension of extensions) { | ||
const contributesSection = extension.packageJSON.contributes; | ||
if (contributesSection && contributesSection.html) { | ||
const htmlSection = contributesSection.html; | ||
if (Array.isArray(htmlSection)) { | ||
htmlSection.forEach(htmlExtensionSection => { | ||
const htmlExtension = createHtmlExtension(htmlExtensionSection); | ||
if (htmlExtension) { | ||
result.push(htmlExtension); | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
// 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 = collectHtmlExtensions(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: HtmlContribution[]): DocumentSelector { | ||
let documentSelector: DocumentSelector = [ | ||
'html' | ||
]; | ||
htmlContributions.forEach((contribution: HtmlContribution) => { | ||
documentSelector = documentSelector.concat(contribution.documentSelector); | ||
}); | ||
return documentSelector; | ||
} | ||
|
||
export function getActivateAutoInsertionSupportedLanguages(htmlContributions: HtmlContribution[]): { [id: string]: boolean } { | ||
const supportedLanguages: { [id: string]: boolean } = { html: true }; | ||
htmlContributions.forEach((contribution: HtmlContribution) => { | ||
contribution.documentSelector.forEach(selector => { | ||
if (typeof selector === 'string') { | ||
const language: string = selector; | ||
supportedLanguages[language] = contribution.activateAutoInsertion; | ||
} else { | ||
const language = (<DocumentFilter>selector).language; | ||
if (language) { | ||
supportedLanguages[language] = contribution.activateAutoInsertion; | ||
} | ||
} | ||
}); | ||
}); | ||
return supportedLanguages; | ||
} | ||
|
||
function createHtmlExtension(section: any): HtmlContribution | undefined { | ||
const documentSelector = createSelector(section); | ||
if (documentSelector.length > 0) { | ||
const activateAutoInsertion = section.activateAutoInsertion === true ? true : false; | ||
return { documentSelector, activateAutoInsertion } as HtmlContribution; | ||
} | ||
return; | ||
} | ||
|
||
function createSelector(section: any): DocumentSelector { | ||
if (!Array.isArray(section.documentSelector)) { | ||
return []; | ||
} | ||
const documentSelector: DocumentSelector = []; | ||
section.documentSelector.forEach((selector: any) => { | ||
if (typeof selector === 'string') { | ||
documentSelector.push(selector); | ||
} else if (selector) { | ||
const documentFilter: { [key: string]: string } = {}; | ||
if (typeof selector.language === 'string') { | ||
documentFilter.language = selector.language; | ||
} | ||
if (typeof selector.scheme === 'string') { | ||
documentFilter.scheme = selector.scheme; | ||
} | ||
if (typeof selector.pattern === 'string') { | ||
documentFilter.pattern = selector.pattern; | ||
} | ||
if (documentFilter.language || documentFilter.scheme || documentFilter.pattern) { | ||
documentSelector.push(documentFilter as DocumentFilter); | ||
} | ||
} | ||
}); | ||
return documentSelector; | ||
} | ||
|