6
6
import 'vs/css!./media/tabstitlecontrol' ;
7
7
import { isMacintosh , isWindows } from 'vs/base/common/platform' ;
8
8
import { shorten } from 'vs/base/common/labels' ;
9
- import { EditorResourceAccessor , GroupIdentifier , Verbosity , IEditorPartOptions , SideBySideEditor , DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor' ;
9
+ import { EditorResourceAccessor , GroupIdentifier , Verbosity , IEditorPartOptions , SideBySideEditor , DEFAULT_EDITOR_ASSOCIATION , EditorInputCapabilities } from 'vs/workbench/common/editor' ;
10
10
import { EditorInput } from 'vs/workbench/common/editor/editorInput' ;
11
11
import { computeEditorAriaLabel } from 'vs/workbench/browser/editor' ;
12
12
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent' ;
@@ -40,7 +40,7 @@ import { CloseOneEditorAction, UnpinEditorAction } from 'vs/workbench/browser/pa
40
40
import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
41
41
import { BreadcrumbsControl } from 'vs/workbench/browser/parts/editor/breadcrumbsControl' ;
42
42
import { IFileService } from 'vs/platform/files/common/files' ;
43
- import { withNullAsUndefined , assertAllDefined , assertIsDefined } from 'vs/base/common/types' ;
43
+ import { assertAllDefined , assertIsDefined } from 'vs/base/common/types' ;
44
44
import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
45
45
import { basenameOrAuthority } from 'vs/base/common/resources' ;
46
46
import { RunOnceScheduler } from 'vs/base/common/async' ;
@@ -56,11 +56,12 @@ import { UNLOCK_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/edito
56
56
interface IEditorInputLabel {
57
57
name ?: string ;
58
58
description ?: string ;
59
+ forceDescription ?: boolean ;
59
60
title ?: string ;
60
61
ariaLabel ?: string ;
61
62
}
62
63
63
- type AugmentedLabel = IEditorInputLabel & { editor : EditorInput } ;
64
+ type IEditorInputLabelAndEditor = IEditorInputLabel & { editor : EditorInput } ;
64
65
65
66
export class TabsTitleControl extends TitleControl {
66
67
@@ -218,7 +219,7 @@ export class TabsTitleControl extends TitleControl {
218
219
} ) ) ;
219
220
220
221
// New file when double clicking on tabs container (but not tabs)
221
- [ TouchEventType . Tap , EventType . DBLCLICK ] . forEach ( eventType => {
222
+ for ( const eventType of [ TouchEventType . Tap , EventType . DBLCLICK ] ) {
222
223
this . _register ( addDisposableListener ( tabsContainer , eventType , ( e : MouseEvent | GestureEvent ) => {
223
224
if ( eventType === EventType . DBLCLICK ) {
224
225
if ( e . target !== tabsContainer ) {
@@ -245,7 +246,7 @@ export class TabsTitleControl extends TitleControl {
245
246
}
246
247
} , this . group . id ) ;
247
248
} ) ) ;
248
- } ) ;
249
+ }
249
250
250
251
// Prevent auto-scrolling (https://github.com/microsoft/vscode/issues/16690)
251
252
this . _register ( addDisposableListener ( tabsContainer , EventType . MOUSE_DOWN , e => {
@@ -784,7 +785,7 @@ export class TabsTitleControl extends TitleControl {
784
785
} ) ) ;
785
786
786
787
// Double click: either pin or toggle maximized
787
- [ TouchEventType . Tap , EventType . DBLCLICK ] . forEach ( eventType => {
788
+ for ( const eventType of [ TouchEventType . Tap , EventType . DBLCLICK ] ) {
788
789
disposables . add ( addDisposableListener ( tab , eventType , ( e : MouseEvent | GestureEvent ) => {
789
790
if ( eventType === EventType . DBLCLICK ) {
790
791
EventHelper . stop ( e ) ;
@@ -799,7 +800,7 @@ export class TabsTitleControl extends TitleControl {
799
800
this . group . pinEditor ( editor ) ;
800
801
}
801
802
} ) ) ;
802
- } ) ;
803
+ }
803
804
804
805
// Context menu
805
806
disposables . add ( addDisposableListener ( tab , EventType . CONTEXT_MENU , e => {
@@ -953,11 +954,12 @@ export class TabsTitleControl extends TitleControl {
953
954
const { verbosity, shortenDuplicates } = this . getLabelConfigFlags ( labelFormat ) ;
954
955
955
956
// Build labels and descriptions for each editor
956
- const labels = this . group . editors . map ( ( editor , index ) => ( {
957
+ const labels : IEditorInputLabelAndEditor [ ] = this . group . editors . map ( ( editor , index ) => ( {
957
958
editor,
958
959
name : editor . getName ( ) ,
959
960
description : editor . getDescription ( verbosity ) ,
960
- title : withNullAsUndefined ( editor . getTitle ( Verbosity . LONG ) ) ,
961
+ forceDescription : editor . hasCapability ( EditorInputCapabilities . ForceDescription ) ,
962
+ title : editor . getTitle ( Verbosity . LONG ) ,
961
963
ariaLabel : computeEditorAriaLabel ( editor , index , this . group , this . editorGroupService . count )
962
964
} ) ) ;
963
965
@@ -969,63 +971,68 @@ export class TabsTitleControl extends TitleControl {
969
971
this . tabLabels = labels ;
970
972
}
971
973
972
- private shortenTabLabels ( labels : AugmentedLabel [ ] ) : void {
974
+ private shortenTabLabels ( labels : IEditorInputLabelAndEditor [ ] ) : void {
973
975
974
976
// Gather duplicate titles, while filtering out invalid descriptions
975
- const mapTitleToDuplicates = new Map < string , AugmentedLabel [ ] > ( ) ;
977
+ const mapNameToDuplicates = new Map < string , IEditorInputLabelAndEditor [ ] > ( ) ;
976
978
for ( const label of labels ) {
977
979
if ( typeof label . description === 'string' ) {
978
- getOrSet ( mapTitleToDuplicates , label . name , [ ] ) . push ( label ) ;
980
+ getOrSet ( mapNameToDuplicates , label . name , [ ] ) . push ( label ) ;
979
981
} else {
980
982
label . description = '' ;
981
983
}
982
984
}
983
985
984
- // Identify duplicate titles and shorten descriptions
985
- mapTitleToDuplicates . forEach ( duplicateTitles => {
986
+ // Identify duplicate names and shorten descriptions
987
+ for ( const [ , duplicateLabels ] of mapNameToDuplicates ) {
986
988
987
989
// Remove description if the title isn't duplicated
988
- if ( duplicateTitles . length === 1 ) {
989
- duplicateTitles [ 0 ] . description = '' ;
990
+ // and we have no indication to enforce description
991
+ if ( duplicateLabels . length === 1 && ! duplicateLabels [ 0 ] . forceDescription ) {
992
+ duplicateLabels [ 0 ] . description = '' ;
990
993
991
- return ;
994
+ continue ;
992
995
}
993
996
994
997
// Identify duplicate descriptions
995
- const mapDescriptionToDuplicates = new Map < string , AugmentedLabel [ ] > ( ) ;
996
- for ( const label of duplicateTitles ) {
997
- getOrSet ( mapDescriptionToDuplicates , label . description , [ ] ) . push ( label ) ;
998
+ const mapDescriptionToDuplicates = new Map < string , IEditorInputLabelAndEditor [ ] > ( ) ;
999
+ for ( const duplicateLabel of duplicateLabels ) {
1000
+ getOrSet ( mapDescriptionToDuplicates , duplicateLabel . description , [ ] ) . push ( duplicateLabel ) ;
998
1001
}
999
1002
1000
1003
// For editors with duplicate descriptions, check whether any long descriptions differ
1001
1004
let useLongDescriptions = false ;
1002
- mapDescriptionToDuplicates . forEach ( ( duplicateDescriptions , name ) => {
1003
- if ( ! useLongDescriptions && duplicateDescriptions . length > 1 ) {
1004
- const [ first , ...rest ] = duplicateDescriptions . map ( ( { editor } ) => editor . getDescription ( Verbosity . LONG ) ) ;
1005
+ for ( const [ , duplicateLabels ] of mapDescriptionToDuplicates ) {
1006
+ if ( ! useLongDescriptions && duplicateLabels . length > 1 ) {
1007
+ const [ first , ...rest ] = duplicateLabels . map ( ( { editor } ) => editor . getDescription ( Verbosity . LONG ) ) ;
1005
1008
useLongDescriptions = rest . some ( description => description !== first ) ;
1006
1009
}
1007
- } ) ;
1010
+ }
1008
1011
1009
1012
// If so, replace all descriptions with long descriptions
1010
1013
if ( useLongDescriptions ) {
1011
1014
mapDescriptionToDuplicates . clear ( ) ;
1012
- duplicateTitles . forEach ( label => {
1013
- label . description = label . editor . getDescription ( Verbosity . LONG ) ;
1014
- getOrSet ( mapDescriptionToDuplicates , label . description , [ ] ) . push ( label ) ;
1015
- } ) ;
1015
+ for ( const duplicateLabel of duplicateLabels ) {
1016
+ duplicateLabel . description = duplicateLabel . editor . getDescription ( Verbosity . LONG ) ;
1017
+ getOrSet ( mapDescriptionToDuplicates , duplicateLabel . description , [ ] ) . push ( duplicateLabel ) ;
1018
+ }
1016
1019
}
1017
1020
1018
1021
// Obtain final set of descriptions
1019
1022
const descriptions : string [ ] = [ ] ;
1020
- mapDescriptionToDuplicates . forEach ( ( _ , description ) => descriptions . push ( description ) ) ;
1023
+ for ( const [ description ] of mapDescriptionToDuplicates ) {
1024
+ descriptions . push ( description ) ;
1025
+ }
1021
1026
1022
- // Remove description if all descriptions are identical
1027
+ // Remove description if all descriptions are identical unless forced
1023
1028
if ( descriptions . length === 1 ) {
1024
1029
for ( const label of mapDescriptionToDuplicates . get ( descriptions [ 0 ] ) || [ ] ) {
1025
- label . description = '' ;
1030
+ if ( ! label . forceDescription ) {
1031
+ label . description = '' ;
1032
+ }
1026
1033
}
1027
1034
1028
- return ;
1035
+ continue ;
1029
1036
}
1030
1037
1031
1038
// Shorten descriptions
@@ -1035,7 +1042,7 @@ export class TabsTitleControl extends TitleControl {
1035
1042
label . description = shortenedDescriptions [ index ] ;
1036
1043
}
1037
1044
} ) ;
1038
- } ) ;
1045
+ }
1039
1046
}
1040
1047
1041
1048
private getLabelConfigFlags ( value : string | undefined ) {
@@ -1096,21 +1103,21 @@ export class TabsTitleControl extends TitleControl {
1096
1103
1097
1104
// Settings
1098
1105
const tabActionsVisibility = isTabSticky && options . pinnedTabSizing === 'compact' ? 'off' /* treat sticky compact tabs as tabCloseButton: 'off' */ : options . tabCloseButton ;
1099
- [ 'off' , 'left' , 'right' ] . forEach ( option => {
1106
+ for ( const option of [ 'off' , 'left' , 'right' ] ) {
1100
1107
tabContainer . classList . toggle ( `tab-actions-${ option } ` , tabActionsVisibility === option ) ;
1101
- } ) ;
1108
+ }
1102
1109
1103
1110
const tabSizing = isTabSticky && options . pinnedTabSizing === 'shrink' ? 'shrink' /* treat sticky shrink tabs as tabSizing: 'shrink' */ : options . tabSizing ;
1104
- [ 'fit' , 'shrink' ] . forEach ( option => {
1111
+ for ( const option of [ 'fit' , 'shrink' ] ) {
1105
1112
tabContainer . classList . toggle ( `sizing-${ option } ` , tabSizing === option ) ;
1106
- } ) ;
1113
+ }
1107
1114
1108
1115
tabContainer . classList . toggle ( 'has-icon' , options . showIcons && options . hasIcons ) ;
1109
1116
1110
1117
tabContainer . classList . toggle ( 'sticky' , isTabSticky ) ;
1111
- [ 'normal' , 'compact' , 'shrink' ] . forEach ( option => {
1118
+ for ( const option of [ 'normal' , 'compact' , 'shrink' ] ) {
1112
1119
tabContainer . classList . toggle ( `sticky-${ option } ` , isTabSticky && options . pinnedTabSizing === option ) ;
1113
- } ) ;
1120
+ }
1114
1121
1115
1122
// Sticky compact/shrink tabs need a position to remain at their location
1116
1123
// when scrolling to stay in view (requirement for position: sticky)
0 commit comments