@@ -58,8 +58,12 @@ export function register(on: On) {
5858 attempted : number
5959 release : ( ready : boolean ) => void
6060 }
61+ type PaneLookup =
62+ | { kind : 'placed' | 'waiting' | 'absent' }
63+ | { kind : 'unknown' ; reason : string }
6164 let sessionChange : SessionChange | null = null
6265 let isPaneOpen = false
66+ let isPaneUnknown = false
6367 let openingPane : Promise < boolean > | null = null
6468 let paneCloses = 0
6569 let dialogRows : number | null = null
@@ -487,7 +491,7 @@ export function register(on: On) {
487491 const opening = ( openingPane ?? Promise . resolve ( false ) )
488492 . catch ( ( ) => false )
489493 . then ( ( ) => {
490- if ( epoch !== pin . epoch ) {
494+ if ( epoch !== pin . epoch || isPaneUnknown ) {
491495 return false
492496 }
493497
@@ -533,13 +537,22 @@ export function register(on: On) {
533537 return false
534538 }
535539
536- const opened = await engine . openPane (
537- isDialog
538- ? { ...dialogPane ( ) , focus : true }
539- : { id : Names . PANE_ID , title : Names . PANE_TITLE , holdToasts : true } ,
540- )
540+ const closesAtOpen = paneCloses
541+ let isWaiting = false
542+
543+ try {
544+ const opened = await engine . openPane (
545+ isDialog
546+ ? { ...dialogPane ( ) , focus : true }
547+ : { id : Names . PANE_ID , title : Names . PANE_TITLE , holdToasts : true } ,
548+ )
541549
542- const isWaiting = isRecord ( opened ) && opened . isPlaced === false
550+ isWaiting = isRecord ( opened ) && opened . isPlaced === false
551+ } catch ( error ) {
552+ if ( ! ( await isPlacedAfterRejection ( engine , error , epoch , closesAtOpen , trigger ) ) ) {
553+ return false
554+ }
555+ }
543556
544557 if ( epoch !== pin . epoch ) {
545558 const closedBefore = paneCloses
@@ -585,6 +598,112 @@ export function register(on: On) {
585598 return true
586599 }
587600
601+ async function paneOf ( engine : Host ) : Promise < PaneLookup > {
602+ let panes : unknown
603+
604+ try {
605+ panes = await engine . panes ( )
606+ } catch ( error ) {
607+ return { kind : 'unknown' , reason : messageOf ( error ) }
608+ }
609+
610+ if ( ! Array . isArray ( panes ) ) {
611+ return { kind : 'unknown' , reason : 'the engine listed no panes' }
612+ }
613+
614+ const pane = panes
615+ . filter ( isRecord )
616+ . find ( listed => listed . id === Names . PANE_ID )
617+
618+ if ( ! pane ) {
619+ return { kind : 'absent' }
620+ }
621+
622+ return typeof pane . isPlaced === 'boolean'
623+ ? { kind : pane . isPlaced ? 'placed' : 'waiting' }
624+ : { kind : 'unknown' , reason : 'the engine did not say whether the diff panel is placed' }
625+ }
626+
627+ async function isPlacedAfterRejection (
628+ engine : Host ,
629+ error : unknown ,
630+ epoch : number ,
631+ closesAtOpen : number ,
632+ trigger : ( typeof Record . SHOWN_TRIGGERS ) [ number ] ,
633+ ) : Promise < boolean > {
634+ const pane = epoch === pin . epoch ? await paneOf ( engine ) : null
635+
636+ if ( pane === null || epoch !== pin . epoch ) {
637+ try {
638+ await engine . closePane ( { id : Names . PANE_ID } )
639+ } catch ( closeError ) {
640+ engine . uiLog (
641+ `Could not close the diff panel after the session changed: ${ Views . sanitizeName ( messageOf ( closeError ) ) } ` ,
642+ )
643+
644+ if ( paneCloses === closesAtOpen ) {
645+ isPaneUnknown = true
646+ }
647+ }
648+
649+ throw error
650+ }
651+
652+ if ( paneCloses !== closesAtOpen ) {
653+ throw error
654+ }
655+
656+ const reason = Views . sanitizeName ( messageOf ( error ) )
657+
658+ switch ( pane . kind ) {
659+ case 'absent' :
660+ throw error
661+ case 'waiting' :
662+ await engine . closePane ( { id : Names . PANE_ID } ) . catch ( ( ) => undefined )
663+ throw error
664+ case 'unknown' :
665+ isPaneUnknown = true
666+ paneTrigger = trigger
667+ engine . uiLog (
668+ `Could not tell whether the diff panel opened: ${ reason } ; the pane lookup failed: ${ Views . sanitizeName ( pane . reason ) } ` ,
669+ )
670+ return false
671+ case 'placed' :
672+ engine . uiLog ( `The diff panel opened, but opening it reported: ${ reason } ` )
673+ return true
674+ }
675+ }
676+
677+ async function settleUnknownPane ( engine : Host ) : Promise < void > {
678+ const { epoch } = pin
679+ const closedBefore = paneCloses
680+ const opened = opens
681+ const pane = await paneOf ( engine )
682+
683+ if ( ! isPaneUnknown || epoch !== pin . epoch || paneCloses !== closedBefore || opens !== opened ) {
684+ return
685+ }
686+
687+ if ( pane . kind === 'unknown' ) {
688+ engine . uiLog (
689+ `Could not tell whether the diff panel is shown: ${ Views . sanitizeName ( pane . reason ) } ` ,
690+ )
691+
692+ return
693+ }
694+
695+ isPaneUnknown = false
696+ isPaneOpen = pane . kind === 'placed'
697+
698+ if ( isPaneOpen ) {
699+ void recordShown ( engine )
700+ }
701+
702+ if ( pane . kind === 'waiting' ) {
703+ await closePane ( engine , true ) . catch ( ( ) => undefined )
704+ }
705+ }
706+
588707 async function recordShown ( engine : Host ) : Promise < void > {
589708 const { epoch } = pin
590709 const closedBefore = paneCloses
@@ -611,6 +730,7 @@ export function register(on: On) {
611730 return ( await lifecycle . run ( isCleanup ? 'pane-cleanup' : 'pane-close' , owner , async ( ) => {
612731 await engine . closePane ( { id : Names . PANE_ID } )
613732 isPaneOpen = false
733+ isPaneUnknown = false
614734 return true
615735 } , true ) ) ?? false
616736 }
@@ -622,7 +742,7 @@ export function register(on: On) {
622742 } )
623743 }
624744
625- const isTaken = ( ) => isPaneOpen || hasAutoOpened
745+ const isTaken = ( ) => isPaneOpen || hasAutoOpened || isPaneUnknown
626746
627747 const hasRoomFor = ( floor : number ) =>
628748 model . isFullscreen === true && columns !== null && columns >= floor
@@ -922,6 +1042,7 @@ export function register(on: On) {
9221042 uiLog : text => $ . ui . log ( text ) ,
9231043 openPane : pane => $ . ui . open ( pane ) ,
9241044 closePane : pane => $ . ui . close ( pane ) ,
1045+ panes : ( ) => $ . ui . panes ( ) ,
9251046 registerCommand : spec => $ . command . register ( spec ) ,
9261047 sessionId : ( ) => $ . session . id ( ) ,
9271048 startedAt : ( ) =>
@@ -1005,6 +1126,11 @@ export function register(on: On) {
10051126 }
10061127
10071128 const commandOwner = lifecycle . owner ( )
1129+ if ( isPaneUnknown ) {
1130+ await settleUnknownPane ( host )
1131+ if ( ! lifecycle . isSession ( commandOwner ) ) return { text : Names . SESSION_CHANGED_TEXT }
1132+ if ( isPaneUnknown ) return { text : Names . PANEL_STATE_UNKNOWN_TEXT }
1133+ }
10081134 if ( ! isPaneOpen ) {
10091135 let isAnswered = await pinBackend ( host )
10101136 if ( ! lifecycle . isSession ( commandOwner ) ) return { text : Names . SESSION_CHANGED_TEXT }
@@ -1047,6 +1173,8 @@ export function register(on: On) {
10471173 return {
10481174 text : epoch !== pin . epoch
10491175 ? Names . SESSION_CHANGED_TEXT
1176+ : isPaneUnknown
1177+ ? Names . PANEL_STATE_UNKNOWN_TEXT
10501178 : Names . RESIZE_TERMINAL_TEXT ,
10511179 }
10521180 }
@@ -1089,6 +1217,7 @@ export function register(on: On) {
10891217 if ( isClosed ) {
10901218 paneCloses += 1
10911219 isPaneOpen = false
1220+ isPaneUnknown = false
10921221 paneTrigger = null
10931222 }
10941223
@@ -1201,7 +1330,7 @@ export function register(on: On) {
12011330 const starting = resetSessionStart ( engine )
12021331 void starting . catch ( ( ) => undefined )
12031332
1204- if ( isPaneOpen && change . reason === 'resume' ) {
1333+ if ( ( isPaneOpen || isPaneUnknown ) && change . reason === 'resume' ) {
12051334 try {
12061335 await closePane ( engine , true )
12071336 } catch ( error ) {
0 commit comments