3v324v23 commited on
Commit
c52abbd
·
1 Parent(s): 041b2bd

FIX: HTML entity rendering in syntax highilghter (> -> >)

Browse files
pr_review_dashboard/components/DiffView.js CHANGED
@@ -7,7 +7,6 @@ import { useState, useCallback } from "react";
7
  function highlightCode(text) {
8
  if (!text) return text;
9
 
10
- // Order matters for some regexes
11
  const rules = [
12
  { cls: 'tk-cm', re: /(#.*$|\/\/.*$|\/\*[\s\S]*?\*\/)/gm }, // Comments
13
  { cls: 'tk-st', re: /(['"`])(?:(?!\1)[^\\]|\\.)*\1/g }, // Strings
@@ -18,26 +17,35 @@ function highlightCode(text) {
18
  { cls: 'tk-op', re: /([-+*/%=<>!&|^~]+)/g }, // Operators
19
  ];
20
 
21
- let html = text
22
- .replace(/&/g, "&amp;")
23
- .replace(/</g, "&lt;")
24
- .replace(/>/g, "&gt;");
25
 
26
- // We use a placeholder approach to prevent nested tags
27
- const placeholders = [];
28
- rules.forEach((rule, idx) => {
29
- html = html.replace(rule.re, (match) => {
30
- const id = `__TK_${idx}_${placeholders.length}__`;
31
- placeholders.push({ id, html: `<span class="${rule.cls}">${match}</span>` });
32
  return id;
33
  });
34
  });
35
 
36
- placeholders.forEach(p => {
37
- html = html.replace(p.id, p.html);
38
- });
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- return html;
41
  }
42
 
43
  export default function DiffView({ diff, onCodeSubmit, isProcessing, isAccepted }) {
@@ -172,7 +180,6 @@ export default function DiffView({ diff, onCodeSubmit, isProcessing, isAccepted
172
  dangerouslySetInnerHTML={{ __html: line.type === 'meta' ? line.text : highlightCode(line.text) }}
173
  />
174
 
175
- {/* Intra-line Action Buttons (Shown on Hover) */}
176
  {(line.type === 'add' || line.type === 'del') && !isAccepted && (
177
  <div className="hunk-actions">
178
  <button className="hunk-btn accept">Accept</button>
 
7
  function highlightCode(text) {
8
  if (!text) return text;
9
 
 
10
  const rules = [
11
  { cls: 'tk-cm', re: /(#.*$|\/\/.*$|\/\*[\s\S]*?\*\/)/gm }, // Comments
12
  { cls: 'tk-st', re: /(['"`])(?:(?!\1)[^\\]|\\.)*\1/g }, // Strings
 
17
  { cls: 'tk-op', re: /([-+*/%=<>!&|^~]+)/g }, // Operators
18
  ];
19
 
20
+ // 1. First, we identify all tokens and replace them with unique placeholders
21
+ // This prevents HTML escaping from breaking the regex matching later.
22
+ const tokens = [];
23
+ let processed = text;
24
 
25
+ rules.forEach((rule, ruleIdx) => {
26
+ processed = processed.replace(rule.re, (match) => {
27
+ const id = `__TOKEN_${ruleIdx}_${tokens.length}__`;
28
+ tokens.push({ id, html: `<span class="${rule.cls}">${match}</span>` });
 
 
29
  return id;
30
  });
31
  });
32
 
33
+ // 2. Now escape the remaining text (non-tokens) for HTML safety
34
+ let finalHtml = processed
35
+ .replace(/&/g, "&amp;")
36
+ .replace(/</g, "&lt;")
37
+ .replace(/>/g, "&gt;");
38
+
39
+ // 3. Put the highlighted tokens back into the escaped string
40
+ // We go backwards to handle any nested-like replacements (though regexes here are flat)
41
+ for (let i = tokens.length - 1; i >= 0; i--) {
42
+ const t = tokens[i];
43
+ // We need to make sure the token HTML itself is not escaped in step 2.
44
+ // Since we used IDs like __TOKEN... they are safe.
45
+ finalHtml = finalHtml.replace(t.id, t.html);
46
+ }
47
 
48
+ return finalHtml;
49
  }
50
 
51
  export default function DiffView({ diff, onCodeSubmit, isProcessing, isAccepted }) {
 
180
  dangerouslySetInnerHTML={{ __html: line.type === 'meta' ? line.text : highlightCode(line.text) }}
181
  />
182
 
 
183
  {(line.type === 'add' || line.type === 'del') && !isAccepted && (
184
  <div className="hunk-actions">
185
  <button className="hunk-btn accept">Accept</button>