The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/explore/slate-plugins/prism/index.tsx

123 lines
3.5 KiB

import React from 'react';
import Prism from 'prismjs';
const TOKEN_MARK = 'prism-token';
export function setPrismTokens(language, field, values, alias = 'variable') {
Prism.languages[language][field] = {
alias,
pattern: new RegExp(`(?:^|\\s)(${values.join('|')})(?:$|\\s)`),
};
}
/**
* Code-highlighting plugin based on Prism and
* https://github.com/ianstormtaylor/slate/blob/master/examples/code-highlighting/index.js
*
* (Adapted to handle nested grammar definitions.)
*/
export default function PrismPlugin({ definition, language }) {
if (definition) {
// Don't override exising modified definitions
Prism.languages[language] = Prism.languages[language] || definition;
}
return {
/**
* Render a Slate mark with appropiate CSS class names
*
* @param {Object} props
* @return {Element}
*/
renderMark(props) {
const { children, mark } = props;
// Only apply spans to marks identified by this plugin
if (mark.type !== TOKEN_MARK) {
return undefined;
}
const className = `token ${mark.data.get('types')}`;
return <span className={className}>{children}</span>;
},
/**
* Decorate code blocks with Prism.js highlighting.
*
* @param {Node} node
* @return {Array}
*/
decorateNode(node) {
if (node.type !== 'paragraph') {
return [];
}
const texts = node.getTexts().toArray();
const tstring = texts.map(t => t.text).join('\n');
const grammar = Prism.languages[language];
const tokens = Prism.tokenize(tstring, grammar);
const decorations: any[] = [];
let startText = texts.shift();
let endText = startText;
let startOffset = 0;
let endOffset = 0;
let start = 0;
function processToken(token, acc?) {
// Accumulate token types down the tree
const types = `${acc || ''} ${token.type || ''} ${token.alias || ''}`;
// Add mark for token node
if (typeof token === 'string' || typeof token.content === 'string') {
startText = endText;
startOffset = endOffset;
const content = typeof token === 'string' ? token : token.content;
const newlines = content.split('\n').length - 1;
const length = content.length - newlines;
const end = start + length;
let available = startText.text.length - startOffset;
let remaining = length;
endOffset = startOffset + remaining;
while (available < remaining) {
endText = texts.shift();
remaining = length - available;
available = endText.text.length;
endOffset = remaining;
}
// Inject marks from up the tree (acc) as well
if (typeof token !== 'string' || acc) {
const range = {
anchorKey: startText.key,
anchorOffset: startOffset,
focusKey: endText.key,
focusOffset: endOffset,
marks: [{ type: TOKEN_MARK, data: { types } }],
};
decorations.push(range);
}
start = end;
} else if (token.content && token.content.length) {
// Tokens can be nested
for (const subToken of token.content) {
processToken(subToken, types);
}
}
}
// Process top-level tokens
for (const token of tokens) {
processToken(token);
}
return decorations;
},
};
}