@@ -49,6 +49,12 @@ import {
4949 shouldLoadDiffSectionContents ,
5050} from './lib/diff.ts' ;
5151import { compactPath , fuzzyMatches , sortFiles } from './lib/files.ts' ;
52+ import {
53+ consumeReloadSelection ,
54+ getReloadDeltaPaths ,
55+ getReloadSelectionPath ,
56+ writeReloadSelection ,
57+ } from './lib/reload-selection.ts' ;
5258import {
5359 buildReviewCommentsMarkdown ,
5460 getCommentKey ,
@@ -133,6 +139,7 @@ export default function App() {
133139 useState < CodexSkillStatus > ( defaultCodexSkillStatus ) ;
134140 const [ preferences , setPreferences ] = useState < CodiffPreferences > ( defaultPreferences ) ;
135141 const [ reviewComments , setReviewComments ] = useState < ReadonlyArray < ReviewComment > > ( [ ] ) ;
142+ const [ reloadDeltaPaths , setReloadDeltaPaths ] = useState < ReadonlySet < string > > ( ( ) => new Set ( ) ) ;
136143 const [ pullRequestReviewSubmitting , setPullRequestReviewSubmitting ] =
137144 useState < PullRequestReviewEvent | null > ( null ) ;
138145 const [ scrollTarget , setScrollTarget ] = useState < { path : string ; request : number } | null > ( null ) ;
@@ -273,6 +280,22 @@ export default function App() {
273280 [ bumpItemVersion ] ,
274281 ) ;
275282
283+ const scrollPathIntoReview = useCallback ( ( path : string ) => {
284+ setScrollTarget ( ( current ) => ( {
285+ path,
286+ request : ( current ?. request ?? 0 ) + 1 ,
287+ } ) ) ;
288+ programmaticScrollPathRef . current = path ;
289+ if ( programmaticScrollTimerRef . current != null ) {
290+ window . clearTimeout ( programmaticScrollTimerRef . current ) ;
291+ }
292+
293+ programmaticScrollTimerRef . current = window . setTimeout ( ( ) => {
294+ programmaticScrollPathRef . current = null ;
295+ programmaticScrollTimerRef . current = null ;
296+ } , 1200 ) ;
297+ } , [ ] ) ;
298+
276299 const saveCurrentSourceSession = useCallback ( ( ) => {
277300 const currentState = stateRef . current ;
278301 if ( ! currentState ) {
@@ -293,6 +316,7 @@ export default function App() {
293316 let canceled = false ;
294317
295318 const load = async ( ) => {
319+ const reloadSelection = consumeReloadSelection ( ) ;
296320 const nextLaunchOptions = await window . codiff . getLaunchOptions ( ) ;
297321 if ( canceled ) {
298322 return ;
@@ -315,7 +339,7 @@ export default function App() {
315339 }
316340 setTerminalHelperStatus ( nextTerminalHelperStatus ) ;
317341
318- const nextState = await window . codiff . getRepositoryState ( ) ;
342+ const nextState = await window . codiff . getRepositoryState ( reloadSelection ?. source ) ;
319343
320344 if ( canceled ) {
321345 return ;
@@ -375,6 +399,8 @@ export default function App() {
375399 const initialFiles = nextLaunchOptions . walkthrough
376400 ? orderFilesByWalkthrough ( orderedState . files , nextWalkthrough )
377401 : orderedState . files ;
402+ const reloadSelectedPath = getReloadSelectionPath ( reloadSelection , orderedState ) ;
403+ const nextReloadDeltaPaths = getReloadDeltaPaths ( reloadSelection , orderedState ) ;
378404
379405 setHistoryEntries ( history . entries ) ;
380406 setHistoryHasMore ( history . entries . length >= HISTORY_PAGE_SIZE ) ;
@@ -396,9 +422,14 @@ export default function App() {
396422 setItemVersionByPath ( { } ) ;
397423 setFocusCommentId ( null ) ;
398424 setFocusCommentRequest ( 0 ) ;
425+ setReloadDeltaPaths ( nextReloadDeltaPaths ) ;
399426 setReviewComments ( getReviewCommentsFromState ( orderedState ) ) ;
400427 setViewed ( nextViewed ) ;
401- setSelectedPath ( ( current ) => current ?? initialFiles [ 0 ] ?. path ?? null ) ;
428+ const nextSelectedPath = reloadSelectedPath ?? initialFiles [ 0 ] ?. path ?? null ;
429+ setSelectedPath ( nextSelectedPath ) ;
430+ if ( reloadSelectedPath ) {
431+ scrollPathIntoReview ( reloadSelectedPath ) ;
432+ }
402433 } ;
403434
404435 load ( ) . catch ( ( error : unknown ) => {
@@ -413,7 +444,7 @@ export default function App() {
413444 return ( ) => {
414445 canceled = true ;
415446 } ;
416- } , [ ] ) ;
447+ } , [ scrollPathIntoReview ] ) ;
417448
418449 useEffect (
419450 ( ) =>
@@ -861,21 +892,25 @@ export default function App() {
861892 setSelectedPath ( path ) ;
862893 } , [ ] ) ;
863894
864- const activatePath = useCallback ( ( path : string ) => {
865- setSelectedPath ( path ) ;
866- setScrollTarget ( ( current ) => ( {
867- path,
868- request : ( current ?. request ?? 0 ) + 1 ,
869- } ) ) ;
870- programmaticScrollPathRef . current = path ;
871- if ( programmaticScrollTimerRef . current != null ) {
872- window . clearTimeout ( programmaticScrollTimerRef . current ) ;
873- }
895+ const activatePath = useCallback (
896+ ( path : string ) => {
897+ setSelectedPath ( path ) ;
898+ scrollPathIntoReview ( path ) ;
899+ } ,
900+ [ scrollPathIntoReview ] ,
901+ ) ;
874902
875- programmaticScrollTimerRef . current = window . setTimeout ( ( ) => {
876- programmaticScrollPathRef . current = null ;
877- programmaticScrollTimerRef . current = null ;
878- } , 1200 ) ;
903+ const reloadWindow = useCallback ( ( ) => {
904+ window . location . reload ( ) ;
905+ } , [ ] ) ;
906+
907+ useEffect ( ( ) => {
908+ const writeCurrentReloadSelection = ( ) => {
909+ writeReloadSelection ( stateRef . current , selectedPathRef . current ) ;
910+ } ;
911+
912+ window . addEventListener ( 'beforeunload' , writeCurrentReloadSelection ) ;
913+ return ( ) => window . removeEventListener ( 'beforeunload' , writeCurrentReloadSelection ) ;
879914 } , [ ] ) ;
880915
881916 const selectSource = useCallback (
@@ -894,6 +929,7 @@ export default function App() {
894929 setLoadError ( null ) ;
895930 setFocusCommentId ( null ) ;
896931 setFocusCommentRequest ( 0 ) ;
932+ setReloadDeltaPaths ( new Set ( ) ) ;
897933 setDiffSearchQuery ( '' ) ;
898934 setActiveDiffSearchMatchIndex ( 0 ) ;
899935 setScrollTarget ( null ) ;
@@ -936,6 +972,7 @@ export default function App() {
936972 setCollapsed ( new Set ( nextCollapsed ) ) ;
937973 setItemVersionByPath ( { } ) ;
938974 setReviewComments ( session ?. reviewComments ?? getReviewCommentsFromState ( orderedState ) ) ;
975+ setReloadDeltaPaths ( new Set ( ) ) ;
939976 setViewed ( nextViewed ) ;
940977 setSelectedPath ( nextSelectedPath ) ;
941978 setWalkthrough ( session ?. walkthrough ?? null ) ;
@@ -1248,7 +1285,7 @@ export default function App() {
12481285 title : 'Toggle Word Wrap' ,
12491286 } ) ,
12501287 registry . register ( {
1251- execute : ( ) => window . location . reload ( ) ,
1288+ execute : reloadWindow ,
12521289 id : 'reload' ,
12531290 title : 'Reload Window' ,
12541291 } ) ,
@@ -1260,7 +1297,14 @@ export default function App() {
12601297 unregister ( ) ;
12611298 }
12621299 } ;
1263- } , [ bumpItemVersion , changeSidebarMode , expandSidebar , openDiffSearch , toggleSidebar ] ) ;
1300+ } , [
1301+ bumpItemVersion ,
1302+ changeSidebarMode ,
1303+ expandSidebar ,
1304+ openDiffSearch ,
1305+ reloadWindow ,
1306+ toggleSidebar ,
1307+ ] ) ;
12641308
12651309 const toggleCollapsed = useCallback (
12661310 ( file : ChangedFile , isCollapsed : boolean ) => {
@@ -1744,6 +1788,7 @@ export default function App() {
17441788 </ div >
17451789 ) : null }
17461790 < RepositoryChangeBanner
1791+ onReload = { reloadWindow }
17471792 visible = { localChangesDetected && ( pendingSource ?? state . source ) . type === 'working-tree' }
17481793 />
17491794 < DiffSearchPanel
@@ -1828,6 +1873,7 @@ export default function App() {
18281873 onSelectPath = { selectPath }
18291874 onSelectSource = { selectSource }
18301875 pullRequestSource = { historySource ?. type === 'pull-request' ? historySource : null }
1876+ reloadDeltaPaths = { reloadDeltaPaths }
18311877 searchQuery = { sidebarMode === 'history' ? historySearchQuery : fileSearchQuery }
18321878 selectedPath = { visibleSelectedPath }
18331879 showWhitespace = { showWhitespace }
0 commit comments