@tanstack/highlight
Version:
Tiny class-based syntax highlighting for documentation.
79 lines (78 loc) • 3.29 kB
JavaScript
import { blockCommentEnd } from '../internal/nested-comment.js';
import { defineLanguage } from '../core.js';
import { collectPatternRanges } from '../internal/patterns.js';
const patterns = [
[/^#!(?!\s*\[).*/g, 'meta'],
[/#!?\[\s*[A-Za-z_][\w:]*/g, 'attr'],
[/\bmacro_rules!|\b[A-Za-z_]\w*!(?=\s*[([{])/g, 'function'],
[/\b(?>=?|&&|\|\||[+\-*/%&|^!<>=]=?|\?/g, 'operator'],
];
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 === '/*') {
end = blockCommentEnd(code, start + 2);
}
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;
}