@@ -51,7 +51,7 @@ const UnifiedDiffView: React.FC<DiffViewProps> = ({
5151 const [ lineDiffs , setLineDiffs ] = React . useState < LineDiff [ ] > ( [ ] ) ;
5252 const [ loading , setLoading ] = React . useState ( true ) ;
5353 const [ viewMode , setViewMode ] = React . useState < ViewMode > ( 'unified' ) ;
54- const [ diffAlgorithm , setDiffAlgorithm ] = React . useState < DiffAlgorithm > ( 'lcs ' ) ;
54+ const [ diffAlgorithm , setDiffAlgorithm ] = React . useState < DiffAlgorithm > ( 'ast ' ) ;
5555 const scrollContainerRef = React . useRef < HTMLDivElement > ( null ) ;
5656
5757 React . useEffect ( ( ) => {
@@ -60,7 +60,7 @@ const UnifiedDiffView: React.FC<DiffViewProps> = ({
6060 setLoading ( true ) ;
6161
6262 // Call the Rust backend AST diff API
63- const response = await fetch ( 'http://localhost:8080/api/ast- diff' , {
63+ const response = await fetch ( 'http://localhost:8080/api/ast/ diff' , {
6464 method : 'POST' ,
6565 headers : { 'Content-Type' : 'application/json' } ,
6666 body : JSON . stringify ( {
@@ -81,7 +81,9 @@ const UnifiedDiffView: React.FC<DiffViewProps> = ({
8181 } ) ;
8282
8383 if ( ! response . ok ) {
84- throw new Error ( 'Failed to fetch diff' ) ;
84+ const errorText = await response . text ( ) ;
85+ console . warn ( 'AST diff API failed, falling back to simple diff:' , response . status , errorText ) ;
86+ throw new Error ( `Failed to fetch diff: ${ response . statusText } ` ) ;
8587 }
8688
8789 const data = await response . json ( ) ;
@@ -97,7 +99,7 @@ const UnifiedDiffView: React.FC<DiffViewProps> = ({
9799
98100 setLineDiffs ( diffs ) ;
99101 } catch ( error ) {
100- console . error ( 'Error fetching diff:' , error ) ;
102+ console . info ( 'Using fallback diff algorithm (AST backend not available)' ) ;
101103 // Fallback to simple line-by-line comparison
102104 const sourceLines = sourceContent . split ( '\n' ) ;
103105 const targetLines = targetContent . split ( '\n' ) ;
@@ -251,8 +253,84 @@ const UnifiedDiffView: React.FC<DiffViewProps> = ({
251253 </ div >
252254 </ div >
253255
254- { /* Unified View */ }
256+ { /* Unified View - Traditional single-column diff */ }
255257 { viewMode === 'unified' && (
258+ < div
259+ ref = { scrollContainerRef }
260+ className = "overflow-auto max-h-[600px] bg-slate-900"
261+ style = { { scrollbarGutter : 'stable' } }
262+ >
263+ < div >
264+ { lineDiffs . map ( ( diff , idx ) => {
265+ // For unified view, show each line with +/- prefix
266+ const showSourceLine = diff . sourceLineNum !== null && diff . type !== 'added' ;
267+ const showTargetLine = diff . targetLineNum !== null && diff . type !== 'deleted' ;
268+
269+ return (
270+ < React . Fragment key = { `unified-${ idx } ` } >
271+ { /* Show deleted/modified source line with - prefix */ }
272+ { showSourceLine && diff . type !== 'unchanged' && (
273+ < div
274+ className = { `flex ${ getLineBackgroundColor ( diff . type === 'modified' ? 'deleted' : diff . type ) } ${ getLineBorderColor ( 'deleted' ) } ` }
275+ >
276+ < div className = "w-12 flex-shrink-0 text-right pr-3 py-1 text-slate-500 text-xs font-mono select-none border-r border-slate-700" >
277+ { diff . sourceLineNum }
278+ </ div >
279+ < div className = "w-8 flex-shrink-0 text-center py-1 text-red-400 text-xs font-mono select-none" >
280+ -
281+ </ div >
282+ < div className = "flex-1 px-3 py-1" >
283+ < pre className = "font-mono text-sm text-slate-100 whitespace-pre" >
284+ { diff . sourceContent }
285+ </ pre >
286+ </ div >
287+ </ div >
288+ ) }
289+
290+ { /* Show added/modified target line with + prefix */ }
291+ { showTargetLine && diff . type !== 'unchanged' && (
292+ < div
293+ className = { `flex ${ getLineBackgroundColor ( diff . type === 'modified' ? 'added' : diff . type ) } ${ getLineBorderColor ( 'added' ) } ` }
294+ >
295+ < div className = "w-12 flex-shrink-0 text-right pr-3 py-1 text-slate-500 text-xs font-mono select-none border-r border-slate-700" >
296+ { diff . targetLineNum }
297+ </ div >
298+ < div className = "w-8 flex-shrink-0 text-center py-1 text-green-400 text-xs font-mono select-none" >
299+ +
300+ </ div >
301+ < div className = "flex-1 px-3 py-1" >
302+ < pre className = "font-mono text-sm text-slate-100 whitespace-pre" >
303+ { diff . targetContent }
304+ </ pre >
305+ </ div >
306+ </ div >
307+ ) }
308+
309+ { /* Show unchanged lines with no prefix */ }
310+ { diff . type === 'unchanged' && (
311+ < div className = { `flex ${ getLineBackgroundColor ( 'unchanged' ) } ` } >
312+ < div className = "w-12 flex-shrink-0 text-right pr-3 py-1 text-slate-500 text-xs font-mono select-none border-r border-slate-700" >
313+ { diff . sourceLineNum || diff . targetLineNum }
314+ </ div >
315+ < div className = "w-8 flex-shrink-0 text-center py-1 text-slate-600 text-xs font-mono select-none" >
316+ { ' ' }
317+ </ div >
318+ < div className = "flex-1 px-3 py-1" >
319+ < pre className = "font-mono text-sm text-slate-100 whitespace-pre" >
320+ { diff . sourceContent || diff . targetContent }
321+ </ pre >
322+ </ div >
323+ </ div >
324+ ) }
325+ </ React . Fragment >
326+ ) ;
327+ } ) }
328+ </ div >
329+ </ div >
330+ ) }
331+
332+ { /* Side-by-Side View - Synchronized two-column layout */ }
333+ { viewMode === 'side-by-side' && (
256334 < div
257335 ref = { scrollContainerRef }
258336 className = "overflow-auto max-h-[600px]"
@@ -313,71 +391,6 @@ const UnifiedDiffView: React.FC<DiffViewProps> = ({
313391 </ div >
314392 </ div >
315393 ) }
316-
317- { /* Side-by-Side View */ }
318- { viewMode === 'side-by-side' && (
319- < div className = "grid grid-cols-2 divide-x divide-slate-700" >
320- { /* Source Code */ }
321- < div className = "bg-slate-900" >
322- < div className = "sticky top-0 z-10 px-4 py-2 bg-slate-800 border-b border-slate-700" >
323- < span className = "text-xs font-medium text-slate-300 uppercase tracking-wide" > Source</ span >
324- </ div >
325- < div className = "overflow-auto max-h-[600px]" >
326- < div >
327- { lineDiffs
328- . filter ( diff => diff . sourceLineNum !== null )
329- . map ( ( diff , idx ) => (
330- < div
331- key = { `source-sbs-${ idx } ` }
332- className = { `flex ${ getLineBackgroundColor ( diff . type === 'added' ? 'unchanged' : diff . type ) } ${
333- diff . type === 'deleted' || diff . type === 'modified' ? getLineBorderColor ( diff . type ) : ''
334- } `}
335- >
336- < div className = "w-12 flex-shrink-0 text-right pr-3 py-1 text-slate-500 text-xs font-mono select-none border-r border-slate-700" >
337- { diff . sourceLineNum }
338- </ div >
339- < div className = "flex-1 px-3 py-1" >
340- < pre className = "font-mono text-sm text-slate-100 whitespace-pre" >
341- { diff . sourceContent }
342- </ pre >
343- </ div >
344- </ div >
345- ) ) }
346- </ div >
347- </ div >
348- </ div >
349-
350- { /* Target Code */ }
351- < div className = "bg-slate-900" >
352- < div className = "sticky top-0 z-10 px-4 py-2 bg-slate-800 border-b border-slate-700" >
353- < span className = "text-xs font-medium text-slate-300 uppercase tracking-wide" > Target</ span >
354- </ div >
355- < div className = "overflow-auto max-h-[600px]" >
356- < div >
357- { lineDiffs
358- . filter ( diff => diff . targetLineNum !== null )
359- . map ( ( diff , idx ) => (
360- < div
361- key = { `target-sbs-${ idx } ` }
362- className = { `flex ${ getLineBackgroundColor ( diff . type === 'deleted' ? 'unchanged' : diff . type ) } ${
363- diff . type === 'added' || diff . type === 'modified' ? getLineBorderColor ( diff . type ) : ''
364- } `}
365- >
366- < div className = "w-12 flex-shrink-0 text-right pr-3 py-1 text-slate-500 text-xs font-mono select-none border-r border-slate-700" >
367- { diff . targetLineNum }
368- </ div >
369- < div className = "flex-1 px-3 py-1" >
370- < pre className = "font-mono text-sm text-slate-100 whitespace-pre" >
371- { diff . targetContent }
372- </ pre >
373- </ div >
374- </ div >
375- ) ) }
376- </ div >
377- </ div >
378- </ div >
379- </ div >
380- ) }
381394 </ div >
382395 ) ;
383396} ;
0 commit comments