Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 53 additions & 32 deletions modules/home/code-line.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,61 @@

"use client";
import React from 'react';

export const CodeLine = ({ line }: { line: string }) => {
// Basic replacements to simulate syntax highlighting
// Note: This is a very simplistic implementation and should be replaced with a proper library like prismjs or shiki in production

const highlight = (text: string) => {
// We use a series of replacements. Order matters to avoid replacing inside already replaced spans.
// A better approach for robust highlighting is tokenization.
const KEYWORDS = [
"import",
"from",
"export",
"default",
"return",
"const",
"new",
"function",
"true",
"false",
];

const highlighted = text;

// Comments (simple // for now)
if (highlighted.includes('//')) {
const parts = highlighted.split('//');
return <><span dangerouslySetInnerHTML={{ __html: highlightCode(parts[0]) }} /><span className="text-slate-500 italic">{'//' + parts[1]}</span></>;
export const CodeLine = ({ line }: { line: string }) => {
// Handle comments
if (line.trim().startsWith("//")) {
return <span className="text-slate-500 italic">{line}</span>;
}

const parts = line.split(/(\s+)/);

return (
<>
{parts.map((part, index) => {
if (KEYWORDS.includes(part)) {
return (
<span
key={index}
className="text-red-500 dark:text-red-400 font-semibold"
>
{part}
</span>
);
}

return <span dangerouslySetInnerHTML={{ __html: highlightCode(highlighted) }} />;
};

const highlightCode = (code: string) => {
return code
.replace(/import|from|export|default|return|const|new/g, '<span class="text-red-500 dark:text-red-400 font-semibold">$&</span>')
.replace(/'[^']*'/g, '<span class="text-amber-600 dark:text-amber-400">$&</span>')
.replace(/"[^"]*"/g, '<span class="text-amber-600 dark:text-amber-400">$&</span>')
.replace(/Editron|console|editor/g, '<span class="text-rose-600 dark:text-rose-400">$&</span>');
}

const [highlighted, setHighlighted] = React.useState<React.ReactNode>(line);
if (
(part.startsWith("'") && part.endsWith("'")) ||
(part.startsWith('"') && part.endsWith('"'))
) {
return (
<span key={index} className="text-amber-600 dark:text-amber-400">
{part}
</span>
);
}

React.useEffect(() => {
setHighlighted(highlight(line));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [line]);
if (["Editron", "editor", "console"].includes(part)) {
return (
<span key={index} className="text-rose-600 dark:text-rose-400">
{part}
</span>
);
}
Comment on lines +22 to +55

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tokenization currently breaks highlighting for real snippet tokens.

On Line 22, splitting by whitespace causes punctuation-attached tokens (Editron({, editor.launch();, '@editron/core';) and multi-word strings ("Ready to build something amazing.") to miss the checks on Lines 38-55. This regresses expected syntax highlighting in HeroCodeDemo.

Suggested fix (tokenize strings/identifiers/punctuation before classification)
-  const parts = line.split(/(\s+)/);
+  const parts =
+    line.match(
+      /"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\s+|[A-Za-z_$][\w$]*|[^\s]/g
+    ) ?? [line];

   return (
     <>
       {parts.map((part, index) => {
         if (KEYWORDS.includes(part)) {
@@
-        if (
-          (part.startsWith("'") && part.endsWith("'")) ||
-          (part.startsWith('"') && part.endsWith('"'))
-        ) {
+        if (
+          (part.startsWith("'") && part.endsWith("'")) ||
+          (part.startsWith('"') && part.endsWith('"'))
+        ) {
           return (
             <span key={index} className="text-amber-600 dark:text-amber-400">
               {part}
             </span>
           );
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/home/code-line.tsx` around lines 22 - 55, The current tokenization
uses line.split(/(\s+)/) which keeps punctuation attached (e.g., "Editron({",
"editor.launch();", "'`@editron/core`';") so KEYWORDS, string checks and the
special identifier check (["Editron","editor","console"]) miss matches; update
tokenization in the parts creation (replace the line.split call) to use a regex
that separately captures quoted strings, identifiers, and punctuation OR
normalize each part before matching (trim surrounding punctuation like (){};.,)
so comparisons against KEYWORDS, the string-start/end checks, and the identifier
list succeed; ensure this change is applied where parts is defined and that
parts.map logic (the KEYWORDS check, the string literal check, and the
["Editron","editor","console"] check) uses the normalized token for comparisons
while still rendering the original part so spacing/punctuation is preserved.


return highlighted;
return <span key={index}>{part}</span>;
})}
</>
);
};
Loading