@@ -1322,16 +1322,16 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1322
1322
//#region closeEditor()
1323
1323
1324
1324
async closeEditor ( editor : EditorInput | undefined = this . activeEditor || undefined , options ?: ICloseEditorOptions ) : Promise < boolean > {
1325
- return this . doCloseEditorWithDirtyHandling ( editor , options ) ;
1325
+ return this . doCloseEditorWithConfirmationHandling ( editor , options ) ;
1326
1326
}
1327
1327
1328
- private async doCloseEditorWithDirtyHandling ( editor : EditorInput | undefined = this . activeEditor || undefined , options ?: ICloseEditorOptions , internalOptions ?: IInternalEditorCloseOptions ) : Promise < boolean > {
1328
+ private async doCloseEditorWithConfirmationHandling ( editor : EditorInput | undefined = this . activeEditor || undefined , options ?: ICloseEditorOptions , internalOptions ?: IInternalEditorCloseOptions ) : Promise < boolean > {
1329
1329
if ( ! editor ) {
1330
1330
return false ;
1331
1331
}
1332
1332
1333
- // Check for dirty and veto
1334
- const veto = await this . handleDirtyClosing ( [ editor ] ) ;
1333
+ // Check for confirmation and veto
1334
+ const veto = await this . handleCloseConfirmation ( [ editor ] ) ;
1335
1335
if ( veto ) {
1336
1336
return false ;
1337
1337
}
@@ -1461,7 +1461,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1461
1461
return this . model . closeEditor ( editor , internalOptions ?. context ) ?. editorIndex ;
1462
1462
}
1463
1463
1464
- private async handleDirtyClosing ( editors : EditorInput [ ] ) : Promise < boolean /* veto */ > {
1464
+ private async handleCloseConfirmation ( editors : EditorInput [ ] ) : Promise < boolean /* veto */ > {
1465
1465
if ( ! editors . length ) {
1466
1466
return false ; // no veto
1467
1467
}
@@ -1470,15 +1470,15 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1470
1470
1471
1471
// To prevent multiple confirmation dialogs from showing up one after the other
1472
1472
// we check if a pending confirmation is currently showing and if so, join that
1473
- let handleDirtyClosingPromise = this . mapEditorToPendingConfirmation . get ( editor ) ;
1474
- if ( ! handleDirtyClosingPromise ) {
1475
- handleDirtyClosingPromise = this . doHandleDirtyClosing ( editor ) ;
1476
- this . mapEditorToPendingConfirmation . set ( editor , handleDirtyClosingPromise ) ;
1473
+ let handleCloseConfirmationPromise = this . mapEditorToPendingConfirmation . get ( editor ) ;
1474
+ if ( ! handleCloseConfirmationPromise ) {
1475
+ handleCloseConfirmationPromise = this . doHandleCloseConfirmation ( editor ) ;
1476
+ this . mapEditorToPendingConfirmation . set ( editor , handleCloseConfirmationPromise ) ;
1477
1477
}
1478
1478
1479
1479
let veto : boolean ;
1480
1480
try {
1481
- veto = await handleDirtyClosingPromise ;
1481
+ veto = await handleCloseConfirmationPromise ;
1482
1482
} finally {
1483
1483
this . mapEditorToPendingConfirmation . delete ( editor ) ;
1484
1484
}
@@ -1489,12 +1489,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1489
1489
}
1490
1490
1491
1491
// Otherwise continue with the remainders
1492
- return this . handleDirtyClosing ( editors ) ;
1492
+ return this . handleCloseConfirmation ( editors ) ;
1493
1493
}
1494
1494
1495
- private async doHandleDirtyClosing ( editor : EditorInput , options ?: { skipAutoSave : boolean } ) : Promise < boolean /* veto */ > {
1496
- if ( ! editor . isDirty ( ) || editor . isSaving ( ) ) {
1497
- return false ; // editor must be dirty and not saving
1495
+ private async doHandleCloseConfirmation ( editor : EditorInput , options ?: { skipAutoSave : boolean } ) : Promise < boolean /* veto */ > {
1496
+ if ( ! this . shouldConfirmClose ( editor ) ) {
1497
+ return false ; // no veto
1498
1498
}
1499
1499
1500
1500
if ( editor instanceof SideBySideEditorInput && this . model . contains ( editor . primary ) ) {
@@ -1531,10 +1531,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1531
1531
// on auto-save configuration.
1532
1532
// However, make sure to respect `skipAutoSave` option in case the automated
1533
1533
// save fails which would result in the editor never closing.
1534
+ // Also, we only do this if no custom confirmation handling is implemented.
1534
1535
let confirmation = ConfirmResult . CANCEL ;
1535
1536
let saveReason = SaveReason . EXPLICIT ;
1536
1537
let autoSave = false ;
1537
- if ( ! editor . hasCapability ( EditorInputCapabilities . Untitled ) && ! options ?. skipAutoSave ) {
1538
+ if ( ! editor . hasCapability ( EditorInputCapabilities . Untitled ) && ! options ?. skipAutoSave && ! editor . closeHandler ) {
1538
1539
1539
1540
// Auto-save on focus change: save, because a dialog would steal focus
1540
1541
// (see https://github.com/microsoft/vscode/issues/108752)
@@ -1554,15 +1555,15 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1554
1555
}
1555
1556
}
1556
1557
1557
- // No auto-save on focus change: ask user
1558
+ // No auto-save on focus change or custom confirmation handler : ask user
1558
1559
if ( ! autoSave ) {
1559
1560
1560
- // Switch to editor that we want to handle and confirm to save/revert
1561
+ // Switch to editor that we want to handle for confirmation
1561
1562
await this . doOpenEditor ( editor ) ;
1562
1563
1563
1564
// Let editor handle confirmation if implemented
1564
- if ( typeof editor . confirm === 'function' ) {
1565
- confirmation = await editor . confirm ( ) ;
1565
+ if ( typeof editor . closeHandler ?. confirm === 'function' ) {
1566
+ confirmation = await editor . closeHandler . confirm ( ) ;
1566
1567
}
1567
1568
1568
1569
// Show a file specific confirmation
@@ -1578,11 +1579,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1578
1579
}
1579
1580
}
1580
1581
1581
- // It could be that the editor saved meanwhile or is saving, so we check
1582
+ // It could be that the editor's choice of confirmation has changed
1583
+ // given the check for confirmation is long running, so we check
1582
1584
// again to see if anything needs to happen before closing for good.
1583
- // This can happen for example if autoSave: onFocusChange is configured
1585
+ // This can happen for example if ` autoSave: onFocusChange` is configured
1584
1586
// so that the save happens when the dialog opens.
1585
- if ( ! editor . isDirty ( ) || editor . isSaving ( ) ) {
1587
+ if ( ! this . shouldConfirmClose ( editor ) ) {
1586
1588
return confirmation === ConfirmResult . CANCEL ? true : false ;
1587
1589
}
1588
1590
@@ -1595,7 +1597,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1595
1597
// we handle the dirty editor again but this time ensuring to
1596
1598
// show the confirm dialog
1597
1599
// (see https://github.com/microsoft/vscode/issues/108752)
1598
- return this . doHandleDirtyClosing ( editor , { skipAutoSave : true } ) ;
1600
+ return this . doHandleCloseConfirmation ( editor , { skipAutoSave : true } ) ;
1599
1601
}
1600
1602
1601
1603
return editor . isDirty ( ) ; // veto if still dirty
@@ -1621,6 +1623,14 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1621
1623
}
1622
1624
}
1623
1625
1626
+ private shouldConfirmClose ( editor : EditorInput ) : boolean {
1627
+ if ( editor . closeHandler ) {
1628
+ return editor . closeHandler . showConfirm ( ) ; // custom handling of confirmation on close
1629
+ }
1630
+
1631
+ return editor . isDirty ( ) && ! editor . isSaving ( ) ; // editor must be dirty and not saving
1632
+ }
1633
+
1624
1634
//#endregion
1625
1635
1626
1636
//#region closeEditors()
@@ -1632,8 +1642,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1632
1642
1633
1643
const editors = this . doGetEditorsToClose ( args ) ;
1634
1644
1635
- // Check for dirty and veto
1636
- const veto = await this . handleDirtyClosing ( editors . slice ( 0 ) ) ;
1645
+ // Check for confirmation and veto
1646
+ const veto = await this . handleCloseConfirmation ( editors . slice ( 0 ) ) ;
1637
1647
if ( veto ) {
1638
1648
return false ;
1639
1649
}
@@ -1714,8 +1724,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1714
1724
return true ;
1715
1725
}
1716
1726
1717
- // Check for dirty and veto
1718
- const veto = await this . handleDirtyClosing ( this . model . getEditors ( EditorsOrder . MOST_RECENTLY_ACTIVE , options ) ) ;
1727
+ // Check for confirmation and veto
1728
+ const veto = await this . handleCloseConfirmation ( this . model . getEditors ( EditorsOrder . MOST_RECENTLY_ACTIVE , options ) ) ;
1719
1729
if ( veto ) {
1720
1730
return false ;
1721
1731
}
@@ -1795,7 +1805,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1795
1805
this . doCloseEditor ( editor , false , { context : EditorCloseContext . REPLACE } ) ;
1796
1806
closed = true ;
1797
1807
} else {
1798
- closed = await this . doCloseEditorWithDirtyHandling ( editor , { preserveFocus : true } , { context : EditorCloseContext . REPLACE } ) ;
1808
+ closed = await this . doCloseEditorWithConfirmationHandling ( editor , { preserveFocus : true } , { context : EditorCloseContext . REPLACE } ) ;
1799
1809
}
1800
1810
1801
1811
if ( ! closed ) {
@@ -1815,7 +1825,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
1815
1825
if ( activeReplacement . forceReplaceDirty ) {
1816
1826
this . doCloseEditor ( activeReplacement . editor , false , { context : EditorCloseContext . REPLACE } ) ;
1817
1827
} else {
1818
- await this . doCloseEditorWithDirtyHandling ( activeReplacement . editor , { preserveFocus : true } , { context : EditorCloseContext . REPLACE } ) ;
1828
+ await this . doCloseEditorWithConfirmationHandling ( activeReplacement . editor , { preserveFocus : true } , { context : EditorCloseContext . REPLACE } ) ;
1819
1829
}
1820
1830
}
1821
1831
0 commit comments