You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Hydro/packages/ui-default/components/highlighter/prismjs.js

123 lines
3.7 KiB
JavaScript

import Prism from 'prismjs'; // eslint-disable-line
import 'prismjs/plugins/toolbar/prism-toolbar';
import 'prismjs/plugins/toolbar/prism-toolbar.css';
import 'prismjs/plugins/line-numbers/prism-line-numbers';
import 'prismjs/plugins/line-numbers/prism-line-numbers.css';
import 'prismjs/plugins/line-highlight/prism-line-highlight';
import Clipboard from 'clipboard';
import $ from 'jquery';
import components from 'prismjs/components';
import getLoader from 'prismjs/dependencies';
import Notification from 'vj/components/notification/index';
import { i18n } from 'vj/utils';
import languageMeta from './meta';
const files = require.context('prismjs/components/', true, /prism-[a-z0-9-]+\.js/);
const loadedLanguages = new Set();
function loadLanguages() {
const languages = Object.keys(components.languages).filter((l) => l !== 'meta');
const loaded = [...loadedLanguages, ...Object.keys(Prism.languages)];
getLoader(components, languages, loaded).load((lang) => {
files(`./prism-${lang}.js`);
loadedLanguages.add(lang);
});
}
const languageExtMap = {};
loadLanguages();
// Map possible language names to Prism language name
languageMeta.forEach((meta) => {
for (let i = 0; i < meta.ext.length; ++i) {
if (Prism.languages[meta.ext[i]] !== undefined) {
meta.target = meta.ext[i];
break;
}
}
meta.ext.forEach((ext) => {
languageExtMap[ext] = meta.target;
});
});
// Copy to Clipboard
Prism.plugins.toolbar.registerButton('copy-to-clipboard', (env) => {
const linkCopy = document.createElement('a');
linkCopy.href = 'javascript:;';
linkCopy.textContent = 'Copy';
const clip = new Clipboard(linkCopy, { text: () => env.code });
clip.on('success', () => {
Notification.success(i18n('Content copied to clipboard!'), 1000);
});
clip.on('error', () => {
Notification.error(i18n('Copy failed :('));
});
return linkCopy;
});
const invisibles = {
tab: /\t/,
crlf: /\r\n/,
lf: /\n/,
cr: /\r/,
space: / /,
};
function addInvisibles(grammar) {
if (!grammar || grammar.tab) return;
for (const name in invisibles) {
if (Object.prototype.hasOwnProperty.call(invisibles, name)) {
grammar[name] = invisibles[name];
}
}
for (const name in grammar) {
if (Object.prototype.hasOwnProperty.call(grammar, name) && !invisibles[name]) {
if (name === 'rest') addInvisibles(grammar.rest);
else handlerInvisiblesToken(grammar, name); // eslint-disable-line @typescript-eslint/no-use-before-define
}
}
}
function handlerInvisiblesToken(tokens, name) {
const value = tokens[name];
const type = Prism.util.type(value);
if (type === 'RegExp') {
const inside = {};
tokens[name] = { pattern: value, inside };
addInvisibles(inside);
} else if (type === 'Array') {
for (let i = 0, l = value.length; i < l; i++) handlerInvisiblesToken(value, i);
} else {
value.inside ||= {};
addInvisibles(value.inside);
}
}
Prism.hooks.add('before-highlight', (env) => {
if (UserContext.showInvisibleChar) addInvisibles(env.grammar);
});
const prismjsApiWrap = {
highlightBlocks: ($dom) => {
$dom.find('pre code').get().forEach((code) => {
const $code = $(code);
const $pre = $code.parent();
$pre.addClass('syntax-hl');
const language = ($(code).attr('class') || '').trim();
// try to map the language name
const m = language.match(/language-([a-z]+)/);
if (m && m[1]) {
const languageName = m[1].toLowerCase();
if (languageExtMap[languageName]) {
$(code).attr('class', `language-${languageExtMap[languageName]}`);
}
}
Prism.highlightElement(code);
});
},
highlight: (text, grammar, language) => Prism.highlight(text, grammar, language),
Prism,
};
export default prismjsApiWrap;