.pragma library // This exists only beacause I haven't been able to get linkColor to work with MarkdownText // May not be necessary if that's possible tbh. function markdownToHtml(text) { if (!text) return ""; // Store code blocks and inline code to protect them from further processing const codeBlocks = []; const inlineCode = []; let blockIndex = 0; let inlineIndex = 0; // First, extract and replace code blocks with placeholders let html = text.replace(/```([\s\S]*?)```/g, (match, code) => { // Trim leading and trailing blank lines only const trimmedCode = code.replace(/^\n+|\n+$/g, ''); // Escape HTML entities in code const escapedCode = trimmedCode.replace(/&/g, '&') .replace(//g, '>'); codeBlocks.push(`
${escapedCode}
`); return `\x00CODEBLOCK${blockIndex++}\x00`; }); // Extract and replace inline code html = html.replace(/`([^`]+)`/g, (match, code) => { // Escape HTML entities in code const escapedCode = code.replace(/&/g, '&') .replace(//g, '>'); inlineCode.push(`${escapedCode}`); return `\x00INLINECODE${inlineIndex++}\x00`; }); // Now process everything else // Escape HTML entities (but not in code blocks) html = html.replace(/&/g, '&') .replace(//g, '>'); // Headers html = html.replace(/^### (.*?)$/gm, '

$1

'); html = html.replace(/^## (.*?)$/gm, '

$1

'); html = html.replace(/^# (.*?)$/gm, '

$1

'); // Bold and italic (order matters!) html = html.replace(/\*\*\*(.*?)\*\*\*/g, '$1'); html = html.replace(/\*\*(.*?)\*\*/g, '$1'); html = html.replace(/\*(.*?)\*/g, '$1'); html = html.replace(/___(.*?)___/g, '$1'); html = html.replace(/__(.*?)__/g, '$1'); html = html.replace(/_(.*?)_/g, '$1'); // Links html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); // Lists html = html.replace(/^\* (.*?)$/gm, '
  • $1
  • '); html = html.replace(/^- (.*?)$/gm, '
  • $1
  • '); html = html.replace(/^\d+\. (.*?)$/gm, '
  • $1
  • '); // Wrap consecutive list items in ul/ol tags html = html.replace(/(
  • [\s\S]*?<\/li>\s*)+/g, function(match) { return ''; }); // Detect plain URLs and wrap them in anchor tags (but not inside existing or markdown links) html = html.replace(/(^|[^"'>])((https?|file):\/\/[^\s<]+)/g, '$1$2'); // Restore code blocks and inline code BEFORE line break processing html = html.replace(/\x00CODEBLOCK(\d+)\x00/g, (match, index) => { return codeBlocks[parseInt(index)]; }); html = html.replace(/\x00INLINECODE(\d+)\x00/g, (match, index) => { return inlineCode[parseInt(index)]; }); // Line breaks (after code blocks are restored) html = html.replace(/\n\n/g, '

    '); html = html.replace(/\n/g, '
    '); // Wrap in paragraph tags if not already wrapped if (!html.startsWith('<')) { html = '

    ' + html + '

    '; } // Clean up the final HTML // Remove
    tags immediately before block elements html = html.replace(/\s*
    /g, '
    ');
        html = html.replace(/\s*
      /g, '
        '); html = html.replace(/\s*/g, ''); // Remove empty paragraphs html = html.replace(/

        \s*<\/p>/g, ''); html = html.replace(/

        \s*\s*<\/p>/g, ''); // Remove excessive line breaks html = html.replace(/(){3,}/g, '

        '); // Max 2 consecutive line breaks html = html.replace(/(<\/p>)\s*(

        )/g, '$1$2'); // Remove whitespace between paragraphs // Remove leading/trailing whitespace html = html.trim(); return html; }