@@ -309,25 +309,49 @@ public struct HtmlRenderer: MarkupWalker {
309
309
let language = codeBlock. language ?? " "
310
310
logger. trace ( " Rendering code block with language: \( language) " )
311
311
let ( filename, codeWithoutFilename) = extractFilename ( from: codeBlock. code, language: language)
312
- let codeToRender : String
313
- if enableSyntaxHighlighting {
314
- codeToRender = highlightCode ( codeWithoutFilename, language: language)
315
- } else {
316
- codeToRender = codeWithoutFilename
317
- }
318
- let ( linesHTML, numbersHTML) = wrapWithLineNumbers ( codeToRender)
312
+
313
+ // Escape HTML in the code to prevent injection
314
+ let escapedCode = escapeHTML ( codeWithoutFilename)
315
+
316
+ // Count the number of lines for line numbers
317
+ let lines = codeWithoutFilename. components ( separatedBy: . newlines)
318
+ let lineCount = lines. count
319
+
320
+ // Build the HTML for the code block
319
321
html += " <div class= \" code-block-wrapper \" style= \" position:relative; \" > "
322
+
323
+ // Add filename if available and enabled
320
324
if showCodeFilename, let filename = filename {
321
325
html += " <div class= \" code-language \" > \( filename) </div> "
322
326
}
327
+
328
+ // Add copy button if enabled
323
329
if showCopyButton {
324
- html += " <button class= \" copy-button \" >Copy</button> "
330
+ html += " <button class= \" copy-button \" onclick= \" navigator.clipboard.writeText(this.parentElement.querySelector('code').innerText) \" >Copy</button> "
325
331
}
332
+
326
333
if showLineNumbers {
327
- html += " <pre class= \" line-numbers \" style= \" display:flex; \" ><div class= \" line-numbers \" style= \" text-align:right;user-select:none;color:#888;padding-right:8px; \" > \( numbersHTML) </div><code class= \" language- \( language) \" style= \" flex:1; \" > \( linesHTML) </code></pre> "
334
+ // Generate line numbers HTML
335
+ let lineNumbersHTML = ( 1 ... lineCount) . map { " <span> \( $0) </span> " } . joined ( separator: " \n " )
336
+
337
+ html += " <pre class= \" line-numbers \" style= \" display:flex; \" ><div class= \" line-numbers \" style= \" text-align:right;user-select:none;color:#888;padding-right:8px; \" > \( lineNumbersHTML) </div> "
338
+ } else {
339
+ html += " <pre> "
340
+ }
341
+
342
+ // Add the code with basic syntax highlighting
343
+ html += " <code class= \" language- \( language) \" style= \" flex:1; \" > "
344
+
345
+ // For now, we'll use a very simple approach to avoid HTML escaping issues
346
+ // Just display the escaped code without syntax highlighting
347
+ if enableSyntaxHighlighting {
348
+ // In a future version, implement proper syntax highlighting
349
+ html += escapedCode
328
350
} else {
329
- html += " <pre><code class= \" language- \( language ) \" > \( codeToRender ) </code></pre> "
351
+ html += escapedCode
330
352
}
353
+
354
+ html += " </code></pre> "
331
355
html += " </div> "
332
356
}
333
357
@@ -463,6 +487,11 @@ public struct HtmlRenderer: MarkupWalker {
463
487
. replacingOccurrences ( of: " \" " , with: " " " )
464
488
. replacingOccurrences ( of: " ' " , with: " ' " )
465
489
}
490
+
491
+ /// Unescapes HTML span tags used for syntax highlighting while keeping other HTML escaping intact
492
+ /// - Parameter string: The string containing escaped HTML span tags
493
+ /// - Returns: A string with span tags unescaped but other HTML escaping intact
494
+
466
495
467
496
/// Extracts a filename from the first line of the code block if it matches a comment convention for the language.
468
497
///
@@ -502,30 +531,38 @@ public struct HtmlRenderer: MarkupWalker {
502
531
/// - code: The code string.
503
532
/// - language: The language identifier.
504
533
/// - Returns: The HTML string with syntax highlighting.
505
- public func highlightCode( _ code: String , language: String ) -> String {
506
- // First escape the code to prevent HTML injection
507
- switch language {
508
- case " sh " :
509
- return highlightShell ( code)
510
- case " swift " :
511
- return highlightSwift ( code)
512
- case " yml " , " yaml " :
513
- return highlightYAML ( code)
514
- default :
515
- return code
516
- }
534
+ /// This function will be implemented in a future version
535
+ /// to provide proper syntax highlighting for Swift code
536
+ private func applySwiftHighlighting( _ code: String ) -> String {
537
+ // Placeholder for future implementation
538
+ return code
539
+ }
540
+
541
+ /// For future implementation of proper syntax highlighting
542
+ /// Currently, this is a placeholder that will be implemented in a future version
543
+ private func applySyntaxHighlighting( _ code: String , language: String ) -> String {
544
+ // This is a placeholder for future syntax highlighting implementation
545
+ // Currently, we just return the code as-is to avoid HTML escaping issues
546
+ return code
517
547
}
518
548
519
549
/// Wraps code lines in spans and generates line numbers HTML.
520
550
///
521
- /// - Parameter code: The highlighted code string (may contain HTML) .
522
- /// - Returns: Tuple of (linesHTML, numbersHTML) .
551
+ /// - Parameter code: The code to wrap .
552
+ /// - Returns: A tuple containing the wrapped code lines and the HTML for line numbers .
523
553
public func wrapWithLineNumbers( _ code: String ) -> ( String , String ) {
524
554
let lines = code. components ( separatedBy: . newlines)
525
555
let linesHTML = lines. map { " <span> \( $0) </span> " } . joined ( separator: " \n " )
526
556
let numbersHTML = ( 1 ... lines. count) . map { " <span> \( $0) </span> " } . joined ( separator: " \n " )
527
557
return ( linesHTML, numbersHTML)
528
558
}
559
+
560
+ /// This function will be implemented in a future version
561
+ /// to provide proper syntax highlighting for JavaScript code
562
+ private func applyJavaScriptHighlighting( _ code: String ) -> String {
563
+ // Placeholder for future implementation
564
+ return code
565
+ }
529
566
530
567
/// Highlights shell script code.
531
568
///
@@ -554,32 +591,11 @@ public struct HtmlRenderer: MarkupWalker {
554
591
///
555
592
/// - Parameter code: The code string.
556
593
/// - Returns: The HTML string with Swift syntax highlighting.
594
+ /// Highlights Swift code
595
+ /// This will be implemented properly in a future version
557
596
public func highlightSwift( _ code: String ) -> String {
558
- let keywords = [
559
- " let " , " var " , " func " , " if " , " else " , " for " , " while " , " return " , " struct " , " class " , " enum " , " import " , " public " , " private " , " internal " , " extension " , " protocol " , " guard " , " in " , " do " , " try " , " catch " , " switch " , " case " , " break " , " continue " , " default " , " where " , " throw " , " throws " , " rethrows " , " defer " , " init " , " self " , " super " , " static " , " subscript " , " associatedtype " , " typealias " , " open " , " final " , " lazy " , " weak " , " unowned " , " override " , " mutating " , " nonmutating " , " convenience " , " required " , " optional " , " nil " , " true " , " false " , " as " , " is " , " inout " , " operator " , " precedence " , " infix " , " prefix " , " postfix " , " dynamic " , " didSet " , " willSet " , " get " , " set " , " Type " , " Any " , " some "
560
- ]
561
- let literals = [ " true " , " false " , " nil " ]
562
- let builtins = [ " print " , " abs " , " min " , " max " , " map " , " filter " , " reduce " , " append " , " remove " , " count " , " contains " ]
563
- let keywordPattern = " \\ b( " + keywords. joined ( separator: " | " ) + " ) \\ b "
564
- let literalPattern = " \\ b( " + literals. joined ( separator: " | " ) + " ) \\ b "
565
- let builtinPattern = " \\ b( " + builtins. joined ( separator: " | " ) + " ) \\ b "
566
- let typePattern = #"(?<![.\w])([A-Z][A-Za-z0-9_]*)\b"#
567
- let stringPattern = #"("[^"]*"|'[^']*')"#
568
- let commentPattern = #"(?m)(\/\/.*$|\/\*[\s\S]*?\*\/)"#
569
- let numberPattern = #"(?<![\w.])(\d+(\.\d+)?)(?![\w.])"#
570
- let functionPattern = #"(?<=func\s)([a-zA-Z_][a-zA-Z0-9_]*)|([a-zA-Z_][a-zA-Z0-9_]*)\s*\("#
571
- let operatorPattern = #"(\+|-|\*|/|=|==|!=|<=|>=|<|>|\|\||&&|!|\?|:|\.\.\.|\.|%)"#
572
- var html = code // Code is already escaped in highlightCode
573
- html = html. replacingOccurrences ( of: commentPattern, with: " <span class= \" hl-comment \" >$1</span> " , options: . regularExpression)
574
- html = html. replacingOccurrences ( of: stringPattern, with: " <span class= \" hl-string \" >$1</span> " , options: . regularExpression)
575
- html = html. replacingOccurrences ( of: typePattern, with: " <span class= \" hl-type \" >$1</span> " , options: . regularExpression)
576
- html = html. replacingOccurrences ( of: keywordPattern, with: " <span class= \" hl-keyword \" >$1</span> " , options: . regularExpression)
577
- html = html. replacingOccurrences ( of: literalPattern, with: " <span class= \" hl-literal \" >$1</span> " , options: . regularExpression)
578
- html = html. replacingOccurrences ( of: builtinPattern, with: " <span class= \" hl-built_in \" >$1</span> " , options: . regularExpression)
579
- html = html. replacingOccurrences ( of: numberPattern, with: " <span class= \" hl-number \" >$1</span> " , options: . regularExpression)
580
- html = html. replacingOccurrences ( of: functionPattern, with: " <span class= \" hl-function \" >$1$2</span> " , options: . regularExpression)
581
- html = html. replacingOccurrences ( of: operatorPattern, with: " <span class= \" hl-operator \" >$1</span> " , options: . regularExpression)
582
- return html
597
+ // Return the code as-is for now to avoid HTML escaping issues
598
+ return code
583
599
}
584
600
585
601
/// Highlights YAML code.
0 commit comments