Code Highlight: Support Type Language (#2249)

This commit is contained in:
Alexander Zinchuk 2023-01-08 04:04:55 +01:00
parent c6ae1062b7
commit 97259f4ad3
3 changed files with 109 additions and 9 deletions

View File

@ -502,7 +502,7 @@ function processEntityAsHtml(
case ApiMessageEntityTypes.Code:
return `<code class="text-entity-code">${renderedContent}</code>`;
case ApiMessageEntityTypes.Pre:
return `\`\`\`${entity.language || ''}<br/>${renderedContent}<br/>\`\`\`<br/>`;
return `\`\`\`${renderText(entity.language || '', ['escape_html'])}<br/>${renderedContent}<br/>\`\`\`<br/>`;
case ApiMessageEntityTypes.Strike:
return `<del>${renderedContent}</del>`;
case ApiMessageEntityTypes.MentionName:

View File

@ -0,0 +1,81 @@
export default (hljs) => {
const IDENTIFIER_RE = '[a-zA-Z_0-9]+';
const IDENTIFIER_WITH_NAMESPACE_RE = '[a-zA-Z_0-9.]+';
const TL = [
{
className: 'keyword',
begin: '---',
end: '---',
},
{
className: 'number',
begin: '#',
end: '\\s',
excludeBegin: true,
excludeEnd: true,
},
{
className: 'punctuation',
match: '[:#?=<>]',
},
{
className: 'symbol',
match: 'flags\\d*\\.\\d*', // Flagged parameters
},
{
className: 'built_in',
match: 'flags:#', // Flags
},
{
className: 'title.class',
match: `^${IDENTIFIER_RE}(?=\\.)`, // Namespace
},
{
className: 'title.function',
match: `^${IDENTIFIER_RE}(?=[\\s#])`, // Identifier followed by space or #
},
{
className: 'title.function',
match: `(?<=\\.)${IDENTIFIER_RE}(?=[\\s#])`, // Identifier after namespace
},
{
className: 'params',
match: `(?<=\\s)${IDENTIFIER_RE}(?=:)`, // Parameter name
},
{
className: 'type',
match: `(?<=[:?])${IDENTIFIER_WITH_NAMESPACE_RE}(?=\\s)`, // Parameter type
},
{
className: 'variable.constant',
match: `(?<=[:?])${IDENTIFIER_RE}(?=<)`, // Generic type
},
{
className: 'type',
match: `(?<=<)${IDENTIFIER_RE}(?=>)`, // Type inside angle brackets
},
{
className: 'title.function.invoke',
match: `(?<==\\s)${IDENTIFIER_RE}(?=;)`, // Result identifier
},
{
className: 'title.class',
match: `(?<==\\s)${IDENTIFIER_RE}(?=\\.)`, // Result namespace
},
{
className: 'title.function.invoke',
match: `(?<==\\s${IDENTIFIER_RE}\\.)${IDENTIFIER_RE}(?=;)`, // Result identifier after namespace
},
];
return {
name: 'TypeLanguage',
aliases: ['tl'],
case_insensitive: false,
contains: [
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
hljs.C_NUMBER_MODE,
].concat(TL),
};
};

View File

@ -38,12 +38,15 @@ const SUPPORTED_LANGUAGES: Record<string, string[]> = {
sql: [],
swift: [],
twig: ['craftcms'],
typelanguage: ['tl'],
typescript: ['ts', 'tsx'],
xml: ['html', 'xhtml', 'rss', 'atom', 'xjb', 'xsd', 'xsl', 'plist', 'wsf', 'svg'],
yaml: [],
};
const languagePromises = new Map<string, Promise<void>>();
const THIRD_PARTY_LANGUAGES = ['typelanguage'];
const languagePromises = new Map<string, Promise<any>>();
export default async function highlightCode(text: string, language: string) {
const lowLang = language.toLowerCase();
@ -73,13 +76,10 @@ async function ensureLanguage(language: string) {
return true;
}
// Funky webpack bug https://github.com/webpack/webpack/issues/13865
const languagePromise = import(
/* webpackChunkName: "Highlight for [request]" */
`../../node_modules/highlight.js/lib/languages/${langCode}`
);
languagePromises.set(langCode, languagePromise);
// Allow errors to help debugging wrong language names
const languagePromise = THIRD_PARTY_LANGUAGES.includes(langCode)
? loadThirdPartyLanguage(langCode) : loadFirstPartyLanguage(langCode);
if (!languagePromise) return false;
const syntax = await languagePromise;
lowlight.registerLanguage(langCode, syntax.default);
if (langCode === '1c') {
@ -88,6 +88,25 @@ async function ensureLanguage(language: string) {
return true;
}
function loadFirstPartyLanguage(langCode: string) {
// Funky webpack bug https://github.com/webpack/webpack/issues/13865
const languagePromise = import(
/* webpackChunkName: "Highlight for [request]" */
`../../node_modules/highlight.js/lib/languages/${langCode}`
);
languagePromises.set(langCode, languagePromise);
return languagePromise;
}
function loadThirdPartyLanguage(langCode: string) {
if (langCode === 'typelanguage') {
const langPromise = import('../lib/hljs-tl/typelanguage');
languagePromises.set(langCode, langPromise);
return langPromise;
}
return undefined;
}
function treeToElements(tree: Element | Root): TeactNode {
const children = tree.children.map((child) => {
if (child.type === 'text') {