60 lines
2.3 KiB
TypeScript
60 lines
2.3 KiB
TypeScript
|
|
import React from 'react';
|
|
|
|
// Basic syntax highlighting for keywords, strings, numbers, comments
|
|
const highlightLua = (code: string): React.ReactNode => {
|
|
const keywords = ['local', 'function', 'return', 'if', 'then', 'else', 'end', 'for', 'in', 'do', 'while', 'break', 'true', 'false', 'nil'];
|
|
|
|
// Regex for matching keywords in a part
|
|
const keywordRegex = new RegExp(`^\\b(${keywords.join('|')})\\b$`);
|
|
|
|
// Construct the main splitting regex pattern as a string
|
|
// Ensure backslashes and special characters are correctly escaped for the RegExp constructor
|
|
const keywordsPatternForSplit = keywords.join('|');
|
|
// Changed \\/ to / in the character class for punctuation
|
|
const splitPatternString = `(--\\[\\[.*?\\]\\]--|--.*?$|"[^"]*"|'[^']*'|\\b\\d+(\\.\\d+)?\\b|\\b(?:${keywordsPatternForSplit})\\b|[(){}[\\]\\.,:;=+\\-*\/%^#~<>&|@!])`;
|
|
const splitRegex = new RegExp(splitPatternString, 'gm');
|
|
|
|
const parts = code.split(splitRegex);
|
|
|
|
return parts.map((part, index) => {
|
|
if (!part) return null; // split can produce empty strings or undefined for some cases
|
|
|
|
if (keywordRegex.test(part)) {
|
|
return <span key={index} className="token keyword">{part}</span>;
|
|
}
|
|
if ((part.startsWith('"') && part.endsWith('"')) || (part.startsWith("'") && part.endsWith("'"))) {
|
|
return <span key={index} className="token string">{part}</span>;
|
|
}
|
|
if (part.match(/^\b\d+(\.\d+)?\b/)) {
|
|
return <span key={index} className="token number">{part}</span>;
|
|
}
|
|
if (part.startsWith('--')) {
|
|
return <span key={index} className="token comment">{part}</span>;
|
|
}
|
|
// Check for punctuation using a set for clarity
|
|
const punctuationChars = new Set(['{', '}', '(', ')', '[', ']', '.', ',', ':', ';', '=', '+', '-', '*', '/', '%', '^', '#', '~', '<', '>', '&', '|', '@', '!']);
|
|
if (punctuationChars.has(part)) {
|
|
return <span key={index} className="token punctuation">{part}</span>;
|
|
}
|
|
return part;
|
|
});
|
|
};
|
|
|
|
|
|
interface CodeBlockProps {
|
|
code: string;
|
|
language: string; // e.g., 'lua', 'typescript'
|
|
}
|
|
|
|
export const CodeBlock: React.FC<CodeBlockProps> = ({ code, language }) => {
|
|
const highlightedCode = language === 'lua' ? highlightLua(code.trim()) : code.trim();
|
|
|
|
return (
|
|
<pre className={`language-${language} text-sm rounded-md shadow-md`}>
|
|
<code>
|
|
{highlightedCode}
|
|
</code>
|
|
</pre>
|
|
);
|
|
};
|