@@ -65,6 +65,19 @@ export function register(on: On) {
6565 let isPaneOpen = false
6666 let isPaneUnknown = false
6767 let openingPane : Promise < boolean > | null = null
68+ type DialogFit = {
69+ engine : Host
70+ epoch : number
71+ revision : number
72+ focus : boolean
73+ }
74+ const paneOperations = {
75+ tail : null as Promise < unknown > | null ,
76+ closes : new Set < Promise < boolean > > ( ) ,
77+ revision : 0 ,
78+ fit : null as DialogFit | null ,
79+ fitting : null as Promise < void > | null ,
80+ }
6881 let paneCloses = 0
6982 let dialogRows : number | null = null
7083 let hasAutoOpened = false
@@ -228,18 +241,69 @@ export function register(on: On) {
228241 }
229242 }
230243
231- function fitDialog ( engine : Host ) {
244+ function queuePane < T > ( task : ( ) => Promise < T > ) : Promise < T > {
245+ const queued = ( paneOperations . tail ?? Promise . resolve ( ) )
246+ . catch ( ( ) => undefined )
247+ . then ( task )
248+ paneOperations . tail = queued
249+ return queued . finally ( ( ) => {
250+ if ( paneOperations . tail === queued ) paneOperations . tail = null
251+ } )
252+ }
253+
254+ function fitDialog ( engine : Host , focus = false ) {
232255 const rows = Views . dialogRowsOf ( model )
233256
234257 const isStale =
235- isPaneOpen && model . isFullscreen === false && rows !== dialogRows
258+ isPaneOpen && ! isPaneUnknown && model . isFullscreen === false &&
259+ ( focus || rows !== dialogRows || paneOperations . fitting !== null )
236260
237261 if ( isStale ) {
238- dialogRows = rows
239- void engine . openPane ( dialogPane ( ) ) . catch ( ( ) => undefined )
262+ const previous = paneOperations . fit
263+ paneOperations . fit = {
264+ engine,
265+ epoch : pin . epoch ,
266+ revision : paneOperations . revision ,
267+ focus : focus || ( previous ?. epoch === pin . epoch &&
268+ previous . revision === paneOperations . revision && previous . focus ) ,
269+ }
270+ drainDialogFit ( )
240271 }
241272 }
242273
274+ function drainDialogFit ( ) {
275+ if ( paneOperations . fitting !== null || paneOperations . fit === null ) return
276+ const queued = paneOperations . fit
277+ const closes = [ ...paneOperations . closes ]
278+ const fitting = queuePane ( async ( ) => {
279+ const request = paneOperations . fit
280+ if ( request ?. epoch !== queued . epoch || request . revision !== queued . revision ) return
281+ paneOperations . fit = null
282+ if ( ! request || request . epoch !== pin . epoch ||
283+ request . revision !== paneOperations . revision ||
284+ ! isPaneOpen || isPaneUnknown || model . isFullscreen !== false ) return
285+
286+ await Promise . allSettled ( closes )
287+ if ( request . epoch !== pin . epoch || request . revision !== paneOperations . revision ||
288+ ! isPaneOpen || isPaneUnknown || model . isFullscreen !== false ) return
289+
290+ const pane = dialogPane ( )
291+ if ( ! request . focus && pane . rows === dialogRows ) return
292+ dialogRows = null
293+ await request . engine . openPane ( { ...pane , ...( request . focus && { focus : true } ) } )
294+ if ( request . epoch === pin . epoch && request . revision === paneOperations . revision && isPaneOpen ) {
295+ dialogRows = pane . rows ?? null
296+ } else {
297+ dialogRows = null
298+ }
299+ } )
300+ paneOperations . fitting = fitting
301+ void fitting . catch ( ( ) => undefined ) . finally ( ( ) => {
302+ if ( paneOperations . fitting === fitting ) paneOperations . fitting = null
303+ drainDialogFit ( )
304+ } )
305+ }
306+
243307 function redraw ( engine : Host ) {
244308 fitDialog ( engine )
245309
@@ -483,20 +547,20 @@ export function register(on: On) {
483547 read : PaneState . Fetched | null = null ,
484548 ) : Promise < boolean > {
485549 const { epoch } = pin
550+ const closes = [ ...paneOperations . closes ]
486551 opens += 1
487- if ( openingPane !== null ) {
552+ paneOperations . revision += 1
553+ if ( paneOperations . tail !== null || closes . length > 0 ) {
488554 engine . uiLog ( 'The diff panel is waiting for an earlier pane operation to finish.' )
489555 }
490556
491- const opening = ( openingPane ?? Promise . resolve ( false ) )
492- . catch ( ( ) => false )
493- . then ( ( ) => {
494- if ( epoch !== pin . epoch || isPaneUnknown ) {
495- return false
496- }
557+ const opening = queuePane ( async ( ) => {
558+ if ( epoch !== pin . epoch || isPaneUnknown ) {
559+ return false
560+ }
497561
498- return isPaneOpen || placePane ( engine , trigger , read )
499- } )
562+ return isPaneOpen || placePane ( engine , trigger , read , closes )
563+ } )
500564
501565 openingPane = opening
502566
@@ -511,6 +575,7 @@ export function register(on: On) {
511575 engine : Host ,
512576 trigger : ( typeof Record . SHOWN_TRIGGERS ) [ number ] ,
513577 read : PaneState . Fetched | null ,
578+ closes : readonly Promise < boolean > [ ] ,
514579 ) : Promise < boolean > {
515580 const { epoch } = pin
516581 const owner = lifecycle . owner ( )
@@ -533,7 +598,8 @@ export function register(on: On) {
533598 await refresh ( engine ) . catch ( ( ) => undefined )
534599 }
535600
536- if ( ! ( await lifecycle . waitForPaneCloses ( owner ) ) || epoch !== pin . epoch ) {
601+ await Promise . allSettled ( closes )
602+ if ( epoch !== pin . epoch ) {
537603 return false
538604 }
539605
@@ -727,12 +793,23 @@ export function register(on: On) {
727793
728794 async function closePane ( engine : Host , isCleanup = false ) : Promise < boolean > {
729795 const owner = lifecycle . owner ( )
730- return ( await lifecycle . run ( isCleanup ? 'pane-cleanup' : 'pane-close' , owner , async ( ) => {
731- await engine . closePane ( { id : Names . PANE_ID } )
732- isPaneOpen = false
733- isPaneUnknown = false
734- return true
735- } , true ) ) ?? false
796+ const placements = paneOperations . tail
797+ if ( paneOperations . tail !== null ) {
798+ engine . uiLog ( 'The diff panel is waiting for an earlier pane operation to finish.' )
799+ }
800+ const closing = lifecycle . run (
801+ isCleanup ? 'pane-cleanup' : 'pane-close' , owner , async ( ) => {
802+ await placements ?. catch ( ( ) => undefined )
803+ if ( ! lifecycle . isSession ( owner ) ) return false
804+ await engine . closePane ( { id : Names . PANE_ID } )
805+ paneOperations . revision += 1
806+ isPaneOpen = false
807+ isPaneUnknown = false
808+ return true
809+ } , true ,
810+ ) . then ( result => result ?? false )
811+ paneOperations . closes . add ( closing )
812+ return closing . finally ( ( ) => { paneOperations . closes . delete ( closing ) } )
736813 }
737814
738815 function markTabSwitch ( engine : Host , tab : ( typeof Record . TABS ) [ number ] ) {
@@ -1201,11 +1278,7 @@ export function register(on: On) {
12011278 model = { ...model , dialogView : 'list' }
12021279 redraw ( host )
12031280
1204- dialogRows = Views . dialogRowsOf ( model )
1205-
1206- void host
1207- . openPane ( { ...dialogPane ( ) , focus : true } )
1208- . catch ( ( ) => undefined )
1281+ fitDialog ( host , true )
12091282
12101283 return { deny : 'back to the file list' }
12111284 }
0 commit comments