@@ -17,11 +17,14 @@ interface CodeBlockProps extends HTMLAttributes<HTMLDivElement> {
1717 githubUrl ?: string ;
1818}
1919
20- // Simple Python tokenizer for syntax highlighting
21- function tokenizePython ( code : string ) : Array < { type : string ; value : string } > {
22- const tokens : Array < { type : string ; value : string } > = [ ] ;
20+ type Token = { type : string ; value : string } ;
21+
22+ // Dead simple tokenizer - not trying to be a full parser, just good enough for display
23+ function tokenizePython ( code : string ) : Token [ ] {
24+ const tokens : Token [ ] = [ ] ;
2325
24- const patterns : Array < [ string , RegExp ] > = [
26+ // Order matters here - more specific patterns first
27+ const patterns : [ string , RegExp ] [ ] = [
2528 [ 'comment' , / ^ # .* / ] ,
2629 [ 'docstring' , / ^ ( " " " [ \s \S ] * ?" " " | ' ' ' [ \s \S ] * ?' ' ' ) / ] ,
2730 [ 'fstring' , / ^ f ( [ ' " ] ) ( (?: \\ .| (? ! \1) [ ^ \\ ] ) * ) \1/ ] ,
@@ -40,10 +43,8 @@ function tokenizePython(code: string): Array<{ type: string; value: string }> {
4043 ] ;
4144
4245 let remaining = code ;
43-
4446 while ( remaining . length > 0 ) {
4547 let matched = false ;
46-
4748 for ( const [ type , pattern ] of patterns ) {
4849 const match = remaining . match ( pattern ) ;
4950 if ( match ) {
@@ -53,7 +54,6 @@ function tokenizePython(code: string): Array<{ type: string; value: string }> {
5354 break ;
5455 }
5556 }
56-
5757 if ( ! matched ) {
5858 tokens . push ( { type : 'text' , value : remaining [ 0 ] } ) ;
5959 remaining = remaining . slice ( 1 ) ;
@@ -63,38 +63,24 @@ function tokenizePython(code: string): Array<{ type: string; value: string }> {
6363 return tokens ;
6464}
6565
66- function getTokenColor ( type : string ) : string {
67- const colorMap : Record < string , string > = {
68- keyword : syntax . keyword ,
69- builtin : syntax . builtin ,
70- function : syntax . function ,
71- className : syntax . className ,
72- decorator : syntax . decorator ,
73- string : syntax . string ,
74- fstring : syntax . string ,
75- docstring : syntax . docstring ,
76- comment : syntax . comment ,
77- number : syntax . number ,
78- parameter : syntax . parameter ,
79- operator : syntax . operator ,
80- punctuation : syntax . punctuation ,
81- variable : syntax . variable ,
82- } ;
83-
84- return colorMap [ type ] || syntax . variable ;
85- }
66+ const tokenColors : Record < string , string > = {
67+ keyword : syntax . keyword ,
68+ builtin : syntax . builtin ,
69+ function : syntax . function ,
70+ className : syntax . className ,
71+ decorator : syntax . decorator ,
72+ string : syntax . string ,
73+ fstring : syntax . string ,
74+ docstring : syntax . docstring ,
75+ comment : syntax . comment ,
76+ number : syntax . number ,
77+ parameter : syntax . parameter ,
78+ operator : syntax . operator ,
79+ punctuation : syntax . punctuation ,
80+ variable : syntax . variable ,
81+ } ;
8682
87- /**
88- * CodeBlock - Python code display with syntax highlighting
89- *
90- * Features:
91- * - Python syntax highlighting
92- * - Line numbers
93- * - Line highlighting for matches
94- * - Copy to clipboard
95- * - GitHub link
96- * - Hover effects on lines
97- */
83+ // Python code block with syntax highlighting and copy button
9884export function CodeBlock ( {
9985 code,
10086 language = 'python' ,
@@ -120,24 +106,17 @@ export function CodeBlock({
120106
121107 return (
122108 < div
123- className = { cn (
124- 'rounded-lg overflow-hidden' ,
125- 'border border-white/[0.08]' ,
126- className
127- ) }
109+ className = { cn ( 'rounded-lg overflow-hidden border border-white/[0.08]' , className ) }
128110 style = { { backgroundColor : codeBg . elevated } }
129111 { ...props }
130112 >
131- { /* Header */ }
132113 { ( filename || githubUrl ) && (
133114 < div
134115 className = "px-4 py-2 flex items-center justify-between border-b border-white/[0.08]"
135116 style = { { backgroundColor : codeBg . primary } }
136117 >
137118 { filename && (
138- < span className = "text-sm text-text-secondary font-mono" >
139- { filename }
140- </ span >
119+ < span className = "text-sm text-text-secondary font-mono" > { filename } </ span >
141120 ) }
142121 < div className = "flex items-center gap-2" >
143122 < button
@@ -146,25 +125,18 @@ export function CodeBlock({
146125 title = "Copy code"
147126 >
148127 < AnimatePresence mode = "wait" >
149- { copied ? (
150- < motion . div
151- key = "check"
152- initial = { { scale : 0.5 , opacity : 0 } }
153- animate = { { scale : 1 , opacity : 1 } }
154- exit = { { scale : 0.5 , opacity : 0 } }
155- >
128+ < motion . div
129+ key = { copied ? 'check' : 'copy' }
130+ initial = { { scale : 0.5 , opacity : 0 } }
131+ animate = { { scale : 1 , opacity : 1 } }
132+ exit = { { scale : 0.5 , opacity : 0 } }
133+ >
134+ { copied ? (
156135 < Check size = { 16 } className = "text-green-500" />
157- </ motion . div >
158- ) : (
159- < motion . div
160- key = "copy"
161- initial = { { scale : 0.5 , opacity : 0 } }
162- animate = { { scale : 1 , opacity : 1 } }
163- exit = { { scale : 0.5 , opacity : 0 } }
164- >
136+ ) : (
165137 < Copy size = { 16 } />
166- </ motion . div >
167- ) }
138+ ) }
139+ </ motion . div >
168140 </ AnimatePresence >
169141 </ button >
170142 { githubUrl && (
@@ -182,52 +154,40 @@ export function CodeBlock({
182154 </ div >
183155 ) }
184156
185- { /* Code */ }
186- < div
187- className = "overflow-auto scrollbar-thin"
188- style = { { maxHeight } }
189- >
157+ < div className = "overflow-auto scrollbar-thin" style = { { maxHeight } } >
190158 < pre className = "p-4 text-sm font-mono leading-relaxed" >
191159 < code >
192160 { lines . map ( ( line , index ) => {
193161 const lineNumber = lineStart + index ;
194162 const isHighlighted = highlightLines . includes ( lineNumber ) ;
195- const tokens = language === 'python' ? tokenizePython ( line ) : [ { type : 'text' , value : line } ] ;
163+ const tokens = language === 'python'
164+ ? tokenizePython ( line )
165+ : [ { type : 'text' , value : line } ] ;
196166
197167 return (
198168 < motion . div
199169 key = { index }
200- className = { cn (
201- 'flex' ,
202- isHighlighted && 'rounded'
203- ) }
170+ className = { cn ( 'flex' , isHighlighted && 'rounded' ) }
204171 variants = { lineHighlightVariants }
205172 initial = "idle"
206173 whileHover = "hover"
207174 style = { {
208- backgroundColor : isHighlighted
209- ? syntax . matchHighlight
210- : undefined ,
175+ backgroundColor : isHighlighted ? syntax . matchHighlight : undefined ,
211176 } }
212177 >
213178 { showLineNumbers && (
214179 < span
215180 className = "select-none pr-4 text-right min-w-[3rem]"
216181 style = { {
217- color : isHighlighted
218- ? syntax . lineNumberActive
219- : syntax . lineNumber ,
182+ color : isHighlighted ? syntax . lineNumberActive : syntax . lineNumber ,
220183 } }
221184 >
222185 { lineNumber }
223186 </ span >
224187 ) }
225188 < span className = "flex-1" >
226- { tokens . map ( ( token , tokenIndex ) => (
227- < span
228- key = { tokenIndex }
229- style = { { color : getTokenColor ( token . type ) } }
230- >
189+ { tokens . map ( ( token , i ) => (
190+ < span key = { i } style = { { color : tokenColors [ token . type ] || syntax . variable } } >
231191 { token . value }
232192 </ span >
233193 ) ) }
0 commit comments