1- import React from "react" ;
2- import { useCallback , useEffect , useMemo , useRef , useState } from "react" ;
1+ import React , { RefObject } from "react" ;
2+ import { useCallback , useEffect , useRef , useState } from "react" ;
3+ import { ListImperativeAPI , useListRef } from "react-window" ;
34
45import {
56 VerifierLogState ,
@@ -11,7 +12,6 @@ import {
1112import {
1213 fetchLogFromUrl ,
1314 getVisibleLogLineRange ,
14- scrollToLogLine ,
1515 scrollToCLine ,
1616 siblingInsLine ,
1717 getVisibleLogLines ,
@@ -70,9 +70,7 @@ function getVisualLogState(
7070const ContentRaw = ( {
7171 loadError,
7272 visualLogState,
73- selectedLine,
74- selectedMemSlotId,
75- selectedCLine,
73+ selectedState,
7674 handlePaste,
7775 handleMainContentClick,
7876 handleCLinesClick,
@@ -83,12 +81,15 @@ const ContentRaw = ({
8381 handleFullLogToggle,
8482 onGotoStart,
8583 onGotoEnd,
84+ logListRef,
85+ visualLogStart,
86+ visualLogEnd,
87+ onLogRowsRendered,
88+ testListHeight,
8689} : {
8790 loadError : string | null ;
8891 visualLogState : VisualLogState ;
89- selectedLine : number ;
90- selectedMemSlotId : string ;
91- selectedCLine : number ;
92+ selectedState : LogLineState ;
9293 handlePaste : ( event : React . ClipboardEvent ) => void ;
9394 handleMainContentClick : ( event : React . MouseEvent < HTMLDivElement > ) => void ;
9495 handleCLinesClick : ( event : React . MouseEvent < HTMLDivElement > ) => void ;
@@ -99,16 +100,19 @@ const ContentRaw = ({
99100 handleFullLogToggle : ( ) => void ;
100101 onGotoStart : ( ) => void ;
101102 onGotoEnd : ( ) => void ;
103+ logListRef : RefObject < ListImperativeAPI | null > ;
104+ visualLogStart : number ;
105+ visualLogEnd : number ;
106+ onLogRowsRendered : ( start : number , end : number ) => void ;
107+ testListHeight : number | undefined ;
102108} ) => {
103109 if ( loadError ) {
104110 return < div > { loadError } </ div > ;
105111 } else if ( visualLogState . logLines . length > 0 ) {
106112 return (
107113 < MainContent
108114 visualLogState = { visualLogState }
109- selectedLine = { selectedLine }
110- selectedMemSlotId = { selectedMemSlotId }
111- selectedCLine = { selectedCLine }
115+ selectedState = { selectedState }
112116 handleCLinesClick = { handleCLinesClick }
113117 handleMainContentClick = { handleMainContentClick }
114118 handleLogLinesClick = { handleLogLinesClick }
@@ -118,6 +122,11 @@ const ContentRaw = ({
118122 handleFullLogToggle = { handleFullLogToggle }
119123 onGotoStart = { onGotoStart }
120124 onGotoEnd = { onGotoEnd }
125+ logListRef = { logListRef }
126+ visualLogStart = { visualLogStart }
127+ visualLogEnd = { visualLogEnd }
128+ onLogRowsRendered = { onLogRowsRendered }
129+ testListHeight = { testListHeight }
121130 />
122131 ) ;
123132 } else {
@@ -133,7 +142,10 @@ const ContentRaw = ({
133142
134143const Content = React . memo ( ContentRaw ) ;
135144
136- function App ( ) {
145+ // testListHeight is only used in our unit tests because react-window
146+ // doesn't seem to respond to scroll events in the virtual dom
147+ // so we set the height manually to include more log lines
148+ function App ( { testListHeight } : { testListHeight ?: number } ) {
137149 const [ visualLogState , setVisualLogState ] = useState < VisualLogState > (
138150 getEmptyVisualLogState ( ) ,
139151 ) ;
@@ -145,8 +157,16 @@ function App() {
145157 ) ;
146158 const [ loadError , setLoadError ] = useState < string | null > ( null ) ;
147159 const [ isLoading , setIsLoading ] = useState < boolean > ( false ) ;
160+ const [ visualIndexRange , setVisualIndexRange ] = useState < {
161+ visualLogStart : number ;
162+ visualLogEnd : number ;
163+ } > ( { visualLogStart : 0 , visualLogEnd : 0 } ) ;
164+ const onLogRowsRendered = useCallback ( ( start : number , end : number ) => {
165+ setVisualIndexRange ( { visualLogStart : start , visualLogEnd : end } ) ;
166+ } , [ ] ) ;
148167
149168 const fileInputRef = useRef < HTMLInputElement > ( null ) ;
169+ const logListRef = useListRef ( null ) ;
150170
151171 const {
152172 verifierLogState,
@@ -156,29 +176,24 @@ function App() {
156176 logLineIdxToVisualIdx,
157177 } = visualLogState ;
158178
159- const { line : selectedLine , memSlotId : selectedMemSlotId } = selectedState ;
179+ const { line : selectedLine } = selectedState ;
160180 const selectedLineVisualIdx = logLineIdxToVisualIdx . get ( selectedLine ) || 0 ;
161181 const hoveredLineVisualIdx =
162182 logLineIdxToVisualIdx . get ( hoveredState . line ) || 0 ;
163- const selectedCLine = useMemo ( ( ) => {
164- let clineId = "" ;
165- if ( selectedState . cLine ) {
166- clineId = selectedState . cLine ;
167- } else {
168- const parsedLine = verifierLogState . lines [ selectedState . line ] ;
169- if ( ! parsedLine ) {
170- return 0 ;
171- }
172- if ( parsedLine . type === ParsedLineType . C_SOURCE ) {
173- clineId = parsedLine . id ;
174- } else {
175- clineId =
176- verifierLogState . cSourceMap . logLineToCLine . get ( selectedState . line ) ||
177- "" ;
183+
184+ const scrollToLogLine = useCallback (
185+ ( index : number ) => {
186+ if ( index < 0 ) {
187+ return ;
178188 }
179- }
180- return verifierLogState . cSourceMap . cSourceLines . get ( clineId ) ?. lineNum || 0 ;
181- } , [ verifierLogState , selectedState ] ) ;
189+ const list = logListRef . current ;
190+ list ?. scrollToRow ( {
191+ index,
192+ align : "center" ,
193+ } ) ;
194+ } ,
195+ [ logListRef ] ,
196+ ) ;
182197
183198 const setSelectedAndScroll = useCallback (
184199 (
@@ -188,7 +203,7 @@ function App() {
188203 nextCLineVisualIdx : number ,
189204 memSlotId : string = "" ,
190205 ) => {
191- scrollToLogLine ( nextInsLineVisualIdx , logLines . length ) ;
206+ scrollToLogLine ( nextInsLineVisualIdx ) ;
192207 scrollToCLine ( nextCLineVisualIdx , cLines . length ) ;
193208 setSelectedState ( { line : nextInsLineId , memSlotId, cLine : nextCLineId } ) ;
194209 } ,
@@ -248,9 +263,17 @@ function App() {
248263 const handleKeyDown = ( e : KeyboardEvent ) => {
249264 let delta = 0 ;
250265 let areCLinesInFocus = selectedState . cLine !== "" ;
251- let { min, max } = getVisibleLogLineRange (
252- areCLinesInFocus ? cLines . length : logLines . length ,
253- ) ;
266+ let min = 0 ;
267+ let max = 0 ;
268+
269+ if ( areCLinesInFocus ) {
270+ const range = getVisibleLogLineRange ( cLines . length ) ;
271+ min = range . min ;
272+ max = range . max ;
273+ } else {
274+ min = visualIndexRange . visualLogStart ;
275+ max = visualIndexRange . visualLogEnd ;
276+ }
254277 let page = max - min + 1 ;
255278 switch ( e . key ) {
256279 case "ArrowDown" :
@@ -528,7 +551,7 @@ function App() {
528551 const maxIdx = arr [ arr . length - 1 ] ;
529552 const visualIdx = logLineIdxToVisualIdx . get ( maxIdx ) ;
530553 if ( visualIdx !== undefined ) {
531- scrollToLogLine ( visualIdx , logLines . length ) ;
554+ scrollToLogLine ( visualIdx ) ;
532555 }
533556 }
534557
@@ -677,9 +700,7 @@ function App() {
677700 < Content
678701 loadError = { loadError }
679702 visualLogState = { visualLogState }
680- selectedLine = { selectedLine }
681- selectedMemSlotId = { selectedMemSlotId }
682- selectedCLine = { selectedCLine }
703+ selectedState = { selectedState }
683704 handlePaste = { handlePaste }
684705 handleMainContentClick = { handleMainContentClick }
685706 handleCLinesClick = { handleCLinesClick }
@@ -690,6 +711,11 @@ function App() {
690711 handleFullLogToggle = { handleFullLogToggle }
691712 onGotoStart = { onGotoStart }
692713 onGotoEnd = { onGotoEnd }
714+ logListRef = { logListRef }
715+ visualLogStart = { visualIndexRange . visualLogStart }
716+ visualLogEnd = { visualIndexRange . visualLogEnd }
717+ onLogRowsRendered = { onLogRowsRendered }
718+ testListHeight = { testListHeight }
693719 />
694720 < div id = "hint" >
695721 < SelectedLineHint
0 commit comments