@@ -10,13 +10,24 @@ export class MarkdownParser {
1010 // Track link index for anchor naming
1111 static linkIndex = 0 ;
1212
13+ // Global code highlighter function
14+ static codeHighlighter = null ;
15+
1316 /**
1417 * Reset link index (call before parsing a new document)
1518 */
1619 static resetLinkIndex ( ) {
1720 this . linkIndex = 0 ;
1821 }
1922
23+ /**
24+ * Set global code highlighter function
25+ * @param {Function|null } highlighter - Function that takes (code, language) and returns highlighted HTML
26+ */
27+ static setCodeHighlighter ( highlighter ) {
28+ this . codeHighlighter = highlighter ;
29+ }
30+
2031 /**
2132 * Escape HTML special characters
2233 * @param {string } text - Raw text to escape
@@ -323,9 +334,15 @@ export class MarkdownParser {
323334 * @param {string } text - Full markdown text
324335 * @param {number } activeLine - Currently active line index (optional)
325336 * @param {boolean } showActiveLineRaw - Show raw markdown on active line
337+ * @param {Function } instanceHighlighter - Instance-specific code highlighter (optional)
326338 * @returns {string } Parsed HTML
327339 */
328- static parse ( text , activeLine = - 1 , showActiveLineRaw = false ) {
340+ static parse (
341+ text ,
342+ activeLine = - 1 ,
343+ showActiveLineRaw = false ,
344+ instanceHighlighter = null
345+ ) {
329346 // Reset link counter for each parse
330347 this . resetLinkIndex ( ) ;
331348
@@ -362,19 +379,20 @@ export class MarkdownParser {
362379 const html = parsedLines . join ( "" ) ;
363380
364381 // Apply post-processing for list consolidation
365- return this . postProcessHTML ( html ) ;
382+ return this . postProcessHTML ( html , instanceHighlighter ) ;
366383 }
367384
368385 /**
369386 * Post-process HTML to consolidate lists and code blocks
370387 * @param {string } html - HTML to post-process
388+ * @param {Function } instanceHighlighter - Instance-specific code highlighter (optional)
371389 * @returns {string } Post-processed HTML with consolidated lists and code blocks
372390 */
373- static postProcessHTML ( html ) {
391+ static postProcessHTML ( html , instanceHighlighter = null ) {
374392 // Check if we're in a browser environment
375393 if ( typeof document === "undefined" || ! document ) {
376394 // In Node.js environment - do manual post-processing
377- return this . postProcessHTMLManual ( html ) ;
395+ return this . postProcessHTMLManual ( html , instanceHighlighter ) ;
378396 }
379397
380398 // Parse HTML string into DOM
@@ -421,9 +439,29 @@ export class MarkdownParser {
421439
422440 // Store reference to the code element for adding content
423441 currentCodeBlock . _codeElement = codeElement ;
442+ currentCodeBlock . _language = lang ;
443+ currentCodeBlock . _codeContent = "" ;
424444 continue ;
425445 } else {
426- // End of code block - fence stays visible
446+ // End of code block - apply highlighting if needed
447+ const highlighter = instanceHighlighter || this . codeHighlighter ;
448+ if (
449+ currentCodeBlock &&
450+ highlighter &&
451+ currentCodeBlock . _codeContent
452+ ) {
453+ try {
454+ const highlightedCode = highlighter (
455+ currentCodeBlock . _codeContent ,
456+ currentCodeBlock . _language || ""
457+ ) ;
458+ currentCodeBlock . _codeElement . innerHTML = highlightedCode ;
459+ } catch ( error ) {
460+ console . warn ( "Code highlighting failed:" , error ) ;
461+ // Keep the plain text content as fallback
462+ }
463+ }
464+
427465 inCodeBlock = false ;
428466 currentCodeBlock = null ;
429467 continue ;
@@ -441,14 +479,18 @@ export class MarkdownParser {
441479 const codeElement =
442480 currentCodeBlock . _codeElement ||
443481 currentCodeBlock . querySelector ( "code" ) ;
444- // Add the line content to the code block
445- if ( codeElement . textContent . length > 0 ) {
446- codeElement . textContent += "\n" ;
482+ // Add the line content to the code block content (for highlighting)
483+ if ( currentCodeBlock . _codeContent . length > 0 ) {
484+ currentCodeBlock . _codeContent += "\n" ;
447485 }
448486 // Get the actual text content, preserving spaces
449- // Use textContent instead of innerHTML to avoid double-escaping
450- // textContent automatically decodes HTML entities
451487 const lineText = child . textContent . replace ( / \u00A0 / g, " " ) ; // \u00A0 is nbsp
488+ currentCodeBlock . _codeContent += lineText ;
489+
490+ // Also add to the code element (fallback if no highlighter)
491+ if ( codeElement . textContent . length > 0 ) {
492+ codeElement . textContent += "\n" ;
493+ }
452494 codeElement . textContent += lineText ;
453495 child . remove ( ) ;
454496 continue ;
@@ -498,9 +540,10 @@ export class MarkdownParser {
498540 /**
499541 * Manual post-processing for Node.js environments (without DOM)
500542 * @param {string } html - HTML to post-process
543+ * @param {Function } instanceHighlighter - Instance-specific code highlighter (optional)
501544 * @returns {string } Post-processed HTML
502545 */
503- static postProcessHTMLManual ( html ) {
546+ static postProcessHTMLManual ( html , instanceHighlighter = null ) {
504547 let processed = html ;
505548
506549 // Process unordered lists
@@ -549,10 +592,22 @@ export class MarkdownParser {
549592 const lang = openFence . slice ( 3 ) . trim ( ) ;
550593 const langClass = lang ? ` class="language-${ lang } "` : "" ;
551594
595+ // Apply code highlighting if available
596+ let highlightedContent = codeContent ;
597+ const highlighter = instanceHighlighter || this . codeHighlighter ;
598+ if ( highlighter ) {
599+ try {
600+ highlightedContent = highlighter ( codeContent , lang ) ;
601+ } catch ( error ) {
602+ console . warn ( "Code highlighting failed:" , error ) ;
603+ // Fall back to original content
604+ }
605+ }
606+
552607 // Keep fence markers visible as separate divs, with pre/code block between them
553608 let result = `<div><span class="code-fence">${ openFence } </span></div>` ;
554- // Content is already escaped, don't double-escape
555- result += `<pre class="code-block"><code${ langClass } >${ codeContent } </code></pre>` ;
609+ // Use highlighted content if available, otherwise use escaped content
610+ result += `<pre class="code-block"><code${ langClass } >${ highlightedContent } </code></pre>` ;
556611 result += `<div><span class="code-fence">${ closeFence } </span></div>` ;
557612
558613 return result ;
0 commit comments