@tanstack/highlight
Version:
Tiny class-based syntax highlighting for documentation.
92 lines (91 loc) • 3.85 kB
JavaScript
import { defineLanguage } from '../core.js';
import { collectPatternRanges } from '../internal/patterns.js';
const patterns = [
{ className: 'meta', regex: /^#!(?!\s*\[).*/g },
{ className: 'attr', regex: /#!?\[\s*[A-Za-z_][\w:]*/g },
{ className: 'function', regex: /\bmacro_rules!|\b[A-Za-z_]\w*!(?=\s*[([{])/g },
{
className: 'keyword',
regex: /\b(?|->|::|\.\.[.=]?|<<=?|>>=?|&&|\|\||[+\-*/%&|^!<>=]=?|\?/g },
];
const charLiteral = /'(?:\\(?:u\{[\da-fA-F_]*\}|x[\da-fA-F]{2}|[^\n])|[^\\'\n\r])'/uy;
const lifetime = /'[A-Za-z_]\w*/y;
export const rust = defineLanguage({
name: 'rust',
aliases: ['rs'],
tokenize: (code) => collectPatternRanges(code, patterns, scanRust(code)),
});
function scanRust(code) {
const ranges = [];
const lexical = /\/[/*]|(?<!\w)(?:[bc]?r(#*)"|[bc]?"|b?')|["']/g;
let match;
while ((match = lexical.exec(code))) {
const token = match[0];
const start = match.index;
let end = code.length;
let className = 'comment';
if (token === '//') {
end = code.indexOf('\n', start);
if (end < 0)
end = code.length;
}
else if (token === '/*') {
// Block comments nest.
const delimiter = /\/\*|\*\//g;
delimiter.lastIndex = start + 2;
let depth = 1;
let next;
while (depth && (next = delimiter.exec(code)))
depth += next[0] === '/*' ? 1 : -1;
if (!depth)
end = delimiter.lastIndex;
}
else if (token.endsWith("'")) {
className = 'string';
charLiteral.lastIndex = start + token.length - 1;
lifetime.lastIndex = start;
if (charLiteral.test(code))
end = charLiteral.lastIndex;
else if (token === "'" && lifetime.test(code)) {
end = lifetime.lastIndex;
className = 'meta';
}
else
continue;
}
else {
className = 'string';
if (match[1] != null) {
const close = code.indexOf(`"${match[1]}`, start + token.length);
if (close >= 0)
end = close + 1 + match[1].length;
}
else {
for (let index = start + token.length; index < code.length; index++) {
if (code[index] === '\\')
index++;
else if (code[index] === '"') {
end = index + 1;
break;
}
}
}
}
ranges.push({ start, end, className });
lexical.lastIndex = end;
}
return ranges;
}