katex-gpt.js 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import katex from 'katex';
  2. // Adapted from https://github.com/SchneeHertz/markdown-it-katex-gpt
  3. // MIT license
  4. const defaultOptions = {
  5. delimiters: [
  6. { left: '\\[', right: '\\]', display: true },
  7. { left: '\\(', right: '\\)', display: false },
  8. ],
  9. };
  10. export function renderLatexHTML(content, display = false) {
  11. return katex.renderToString(content, {
  12. throwOnError: false,
  13. output: 'mathml',
  14. displayMode: display,
  15. });
  16. }
  17. function escapedBracketRule(options) {
  18. return (state, silent) => {
  19. const max = state.posMax;
  20. const start = state.pos;
  21. for (const { left, right, display } of options.delimiters) {
  22. // Check if it starts with the left delimiter
  23. if (!state.src.slice(start).startsWith(left)) continue;
  24. // Skip the length of the left delimiter
  25. let pos = start + left.length;
  26. // Find the matching right delimiter
  27. while (pos < max) {
  28. if (state.src.slice(pos).startsWith(right)) {
  29. break;
  30. }
  31. pos++;
  32. }
  33. // No matching right delimiter found, skip to the next match
  34. if (pos >= max) continue;
  35. // If not in silent mode, convert LaTeX formula to MathML
  36. if (!silent) {
  37. const content = state.src.slice(start + left.length, pos);
  38. try {
  39. const renderedContent = renderLatexHTML(content, display);
  40. const token = state.push('html_inline', '', 0);
  41. token.content = renderedContent;
  42. } catch (e) {
  43. console.error(e);
  44. }
  45. }
  46. // Update position, skip the length of the right delimiter
  47. state.pos = pos + right.length;
  48. return true;
  49. }
  50. }
  51. }
  52. export default function (md, options = defaultOptions) {
  53. md.inline.ruler.after('text', 'escaped_bracket', escapedBracketRule(options));
  54. }