1- import { DIFFS_TAG_NAME , FileDiff , type SelectedLineRange } from "@pierre/diffs"
1+ import { DIFFS_TAG_NAME , FileDiff , type SelectedLineRange , VirtualizedFileDiff } from "@pierre/diffs"
22import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
33import { createEffect , onCleanup , onMount , Show , splitProps } from "solid-js"
44import { Dynamic , isServer } from "solid-js/web"
55import { createDefaultOptions , styleVariables , type DiffProps } from "../pierre"
6+ import { acquireVirtualizer , virtualMetrics } from "../pierre/virtualizer"
67import { useWorkerPool } from "../context/worker-pool"
78
89export type SSRDiffProps < T = { } > = DiffProps < T > & {
@@ -24,10 +25,21 @@ export function Diff<T>(props: SSRDiffProps<T>) {
2425 const workerPool = useWorkerPool ( props . diffStyle )
2526
2627 let fileDiffInstance : FileDiff < T > | undefined
28+ let sharedVirtualizer : NonNullable < ReturnType < typeof acquireVirtualizer > > | undefined
2729 const cleanupFunctions : Array < ( ) => void > = [ ]
2830
2931 const getRoot = ( ) => fileDiffRef ?. shadowRoot ?? undefined
3032
33+ const getVirtualizer = ( ) => {
34+ if ( sharedVirtualizer ) return sharedVirtualizer . virtualizer
35+
36+ const result = acquireVirtualizer ( container )
37+ if ( ! result ) return
38+
39+ sharedVirtualizer = result
40+ return result . virtualizer
41+ }
42+
3143 const applyScheme = ( ) => {
3244 const scheme = document . documentElement . dataset . colorScheme
3345 if ( scheme === "dark" || scheme === "light" ) {
@@ -70,10 +82,10 @@ export function Diff<T>(props: SSRDiffProps<T>) {
7082 const root = getRoot ( )
7183 if ( ! root ) return
7284
73- const diffs = root . querySelector ( "[data-diffs ]" )
85+ const diffs = root . querySelector ( "[data-diff ]" )
7486 if ( ! ( diffs instanceof HTMLElement ) ) return
7587
76- const split = diffs . dataset . type === "split"
88+ const split = diffs . dataset . diffType === "split"
7789
7890 const start = rowIndex ( root , split , range . start , range . side )
7991 const end = rowIndex ( root , split , range . end , range . endSide ?? range . side )
@@ -132,15 +144,19 @@ export function Diff<T>(props: SSRDiffProps<T>) {
132144 node . removeAttribute ( "data-comment-selected" )
133145 }
134146
135- const diffs = root . querySelector ( "[data-diffs ]" )
147+ const diffs = root . querySelector ( "[data-diff ]" )
136148 if ( ! ( diffs instanceof HTMLElement ) ) return
137149
138- const split = diffs . dataset . type === "split"
150+ const split = diffs . dataset . diffType === "split"
151+
152+ const rows = Array . from ( diffs . querySelectorAll ( "[data-line-index]" ) ) . filter (
153+ ( node ) : node is HTMLElement => node instanceof HTMLElement ,
154+ )
155+ if ( rows . length === 0 ) return
139156
140- const code = Array . from ( diffs . querySelectorAll ( "[data-code ]" ) ) . filter (
157+ const annotations = Array . from ( diffs . querySelectorAll ( "[data-line-annotation ]" ) ) . filter (
141158 ( node ) : node is HTMLElement => node instanceof HTMLElement ,
142159 )
143- if ( code . length === 0 ) return
144160
145161 const lineIndex = ( element : HTMLElement ) => {
146162 const raw = element . dataset . lineIndex
@@ -183,19 +199,18 @@ export function Diff<T>(props: SSRDiffProps<T>) {
183199 const first = Math . min ( start , end )
184200 const last = Math . max ( start , end )
185201
186- for ( const block of code ) {
187- for ( const element of Array . from ( block . children ) ) {
188- if ( ! ( element instanceof HTMLElement ) ) continue
189- const idx = lineIndex ( element )
190- if ( idx === undefined ) continue
191- if ( idx > last ) break
192- if ( idx < first ) continue
193- element . setAttribute ( "data-comment-selected" , "" )
194- const next = element . nextSibling
195- if ( next instanceof HTMLElement && next . hasAttribute ( "data-line-annotation" ) ) {
196- next . setAttribute ( "data-comment-selected" , "" )
197- }
198- }
202+ for ( const row of rows ) {
203+ const idx = lineIndex ( row )
204+ if ( idx === undefined ) continue
205+ if ( idx < first || idx > last ) continue
206+ row . setAttribute ( "data-comment-selected" , "" )
207+ }
208+
209+ for ( const annotation of annotations ) {
210+ const idx = parseInt ( annotation . dataset . lineAnnotation ?. split ( "," ) [ 1 ] ?? "" , 10 )
211+ if ( Number . isNaN ( idx ) ) continue
212+ if ( idx < first || idx > last ) continue
213+ annotation . setAttribute ( "data-comment-selected" , "" )
199214 }
200215 }
201216 }
@@ -212,14 +227,27 @@ export function Diff<T>(props: SSRDiffProps<T>) {
212227 onCleanup ( ( ) => monitor . disconnect ( ) )
213228 }
214229
215- fileDiffInstance = new FileDiff < T > (
216- {
217- ...createDefaultOptions ( props . diffStyle ) ,
218- ...others ,
219- ...props . preloadedDiff ,
220- } ,
221- workerPool ,
222- )
230+ const virtualizer = getVirtualizer ( )
231+
232+ fileDiffInstance = virtualizer
233+ ? new VirtualizedFileDiff < T > (
234+ {
235+ ...createDefaultOptions ( props . diffStyle ) ,
236+ ...others ,
237+ ...props . preloadedDiff ,
238+ } ,
239+ virtualizer ,
240+ virtualMetrics ,
241+ workerPool ,
242+ )
243+ : new FileDiff < T > (
244+ {
245+ ...createDefaultOptions ( props . diffStyle ) ,
246+ ...others ,
247+ ...props . preloadedDiff ,
248+ } ,
249+ workerPool ,
250+ )
223251 // @ts -expect-error - fileContainer is private but needed for SSR hydration
224252 fileDiffInstance . fileContainer = fileDiffRef
225253 fileDiffInstance . hydrate ( {
@@ -273,6 +301,8 @@ export function Diff<T>(props: SSRDiffProps<T>) {
273301 // Clean up FileDiff event handlers and dispose SolidJS components
274302 fileDiffInstance ?. cleanUp ( )
275303 cleanupFunctions . forEach ( ( dispose ) => dispose ( ) )
304+ sharedVirtualizer ?. release ( )
305+ sharedVirtualizer = undefined
276306 } )
277307
278308 return (
0 commit comments