Skip to content

Commit cbbd922

Browse files
Add settings for fixed-width tabs (microsoft#181729)
* Add settings for fixed-width tabs This is meant at least partially to address microsoft#40290 and is a continuation of the unfinished work from microsoft#40750. * Only apply fixed width when the setting is on * Implement chrome-like tab width behavior Tabs shrink uniformly (down to a limit) but stay fixed-width when the mouse is over the tab bar. * Rename width setting to max width * Make the ifs more readable * Have event handlers only if the option is set * 🎨 * Handle sizing artifacts present with wrapping tabs To achieve this, it's best to remove the transition delay. * Rename setting to apply only for fixed-sized tabs * Set default fixed max tab width to 160px * Minor code tweaks from review comments * formatting Co-authored-by: Benjamin Pasero <[email protected]> * Use disposable listeners * Remove redundant check for last-in-row * Apply fade gradient from shrink tabSizing to fixed * Trying to make the code cleaner and understandable * Remove transition On advice of @bpasero, removed transition because the editor doesn't really use transition that much. * some cleanup * fix typo * Simplify workaround for the overflow issue * 💄 * 💄 * Let the tabs fix their width before closing the editor * 💄 --------- Co-authored-by: Benjamin Pasero <[email protected]> Co-authored-by: Benjamin Pasero <[email protected]>
1 parent 4d0b34b commit cbbd922

File tree

9 files changed

+164
-36
lines changed

9 files changed

+164
-36
lines changed

build/lib/stylelint/vscode-known-variables.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,8 @@
692692
"--tab-border-top-color",
693693
"--tab-dirty-border-top-color",
694694
"--tabs-border-bottom-color",
695+
"--tab-sizing-current-width",
696+
"--tab-sizing-fixed-max-width",
695697
"--testMessageDecorationFontFamily",
696698
"--testMessageDecorationFontSize",
697699
"--title-border-bottom-color",

src/vs/workbench/browser/parts/editor/editor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
2828
highlightModifiedTabs: false,
2929
tabCloseButton: 'right',
3030
tabSizing: 'fit',
31+
tabSizingFixedMaxWidth: 160,
3132
pinnedTabSizing: 'normal',
3233
titleScrollbarSizing: 'default',
3334
focusRecentEditorAfterClose: true,

src/vs/workbench/browser/parts/editor/editorGroupView.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
13371337
private doCloseEditor(editor: EditorInput, focusNext = (this.accessor.activeGroup === this), internalOptions?: IInternalEditorCloseOptions): void {
13381338
let index: number | undefined;
13391339

1340+
// Forward to title control unless skipped via internal options
1341+
if (!internalOptions?.skipTitleUpdate) {
1342+
this.titleAreaControl.beforeCloseEditor(editor, index);
1343+
}
1344+
13401345
// Closing the active editor of the group is a bit more work
13411346
if (this.model.isActive(editor)) {
13421347
index = this.doCloseActiveEditor(focusNext, internalOptions);

src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@
111111
}
112112

113113
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon.tab-actions-right,
114-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon.tab-actions-off:not(.sticky-compact) {
114+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon.tab-actions-off:not(.sticky-compact),
115+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.has-icon.tab-actions-right,
116+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.has-icon.tab-actions-off:not(.sticky-compact) {
115117
padding-left: 5px; /* reduce padding when we show icons and are in shrinking mode and tab actions is not left (unless sticky-compact) */
116118
}
117119

@@ -121,6 +123,19 @@
121123
flex-shrink: 0;
122124
}
123125

126+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed {
127+
min-width: var(--tab-sizing-current-width, 50px);
128+
max-width: var(--tab-sizing-current-width, var(--tab-sizing-fixed-max-width, 160px));
129+
flex: 1 0 0; /* all tabs are evenly sized and grow */
130+
}
131+
132+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.last-in-row {
133+
/* prevent last tab in a row from moving to next row when tab widths are
134+
* fixed in case rounding errors make the fixed tabs grow over the size
135+
* of the tabs container */
136+
min-width: calc(var(--tab-sizing-current-width, 50px) - 1px);
137+
}
138+
124139
.monaco-workbench .part.editor > .content .editor-group-container > .title > .tabs-and-actions-container.wrapping .tabs-container > .tab.sizing-fit.last-in-row:not(:last-child) {
125140
flex-grow: 1; /* grow the last tab in a row for a more homogeneous look except for last row (#113801) */
126141
}
@@ -134,20 +149,23 @@
134149

135150
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit.sticky-compact,
136151
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.sticky-compact,
152+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.sticky-compact,
137153
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit.sticky-shrink,
138-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.sticky-shrink {
154+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.sticky-shrink,
155+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.sticky-shrink {
139156

140-
/** Sticky compact/shrink tabs do not scroll in case of overflow and are always above unsticky tabs which scroll under */
157+
/** Sticky compact/shrink/fixed tabs do not scroll in case of overflow and are always above unsticky tabs which scroll under */
141158
position: sticky;
142159
z-index: 8;
143160

144-
/** Sticky compact/shrink tabs are even and never grow */
161+
/** Sticky compact/shrink/fixed tabs are even and never grow */
145162
flex-basis: 0;
146163
flex-grow: 0;
147164
}
148165

149166
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit.sticky-compact,
150-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.sticky-compact {
167+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.sticky-compact,
168+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.sticky-compact {
151169

152170
/** Sticky compact tabs have a fixed width of 38px */
153171
width: 38px;
@@ -156,7 +174,8 @@
156174
}
157175

158176
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit.sticky-shrink,
159-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.sticky-shrink {
177+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.sticky-shrink,
178+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.sticky-shrink {
160179

161180
/** Sticky shrink tabs have a fixed width of 80px */
162181
width: 80px;
@@ -166,22 +185,27 @@
166185

167186
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.disable-sticky-tabs > .tab.sizing-fit.sticky-compact,
168187
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.disable-sticky-tabs > .tab.sizing-shrink.sticky-compact,
188+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.disable-sticky-tabs > .tab.sizing-fixed.sticky-compact,
169189
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.disable-sticky-tabs > .tab.sizing-fit.sticky-shrink,
170-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.disable-sticky-tabs > .tab.sizing-shrink.sticky-shrink {
171-
position: static; /** disable sticky positions for sticky compact/shrink tabs if the available space is too little */
190+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.disable-sticky-tabs > .tab.sizing-shrink.sticky-shrink,
191+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.disable-sticky-tabs > .tab.sizing-fixed.sticky-shrink {
192+
position: static; /** disable sticky positions for sticky compact/shrink/fixed tabs if the available space is too little */
172193
}
173194

174195
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.tab-actions-left::after,
175-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.tab-actions-off::after {
196+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.tab-actions-off::after,
197+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.tab-actions-left::after,
198+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.tab-actions-off::after {
176199
content: '';
177200
display: flex;
178201
flex: 0;
179202
width: 5px; /* reserve space to hide tab fade when close button is left or off (fixes https://github.com/microsoft/vscode/issues/45728) */
180203
}
181204

182-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.tab-actions-left {
205+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.tab-actions-left,
206+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.tab-actions-left {
183207
min-width: 80px; /* make more room for close button when it shows to the left */
184-
padding-right: 5px; /* we need less room when sizing is shrink */
208+
padding-right: 5px; /* we need less room when sizing is shrink/fixed */
185209
}
186210

187211
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dragged {
@@ -244,11 +268,13 @@
244268
line-height: 35px; /* aligns icon and label vertically centered in the tab */
245269
}
246270

247-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink .tab-label {
271+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink .tab-label,
272+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed .tab-label {
248273
position: relative;
249274
}
250275

251-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .tab-label > .monaco-icon-label-container::after {
276+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .tab-label > .monaco-icon-label-container::after,
277+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed > .tab-label > .monaco-icon-label-container::after {
252278
content: ''; /* enables a linear gradient to overlay the end of the label when tabs overflow */
253279
position: absolute;
254280
right: 0;
@@ -261,12 +287,14 @@
261287
height: calc(100% - 2px);
262288
}
263289

264-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink:focus > .tab-label > .monaco-icon-label-container::after {
290+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink:focus > .tab-label > .monaco-icon-label-container::after,
291+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed:focus > .tab-label > .monaco-icon-label-container::after {
265292
opacity: 0; /* when tab has the focus this shade breaks the tab border (fixes https://github.com/microsoft/vscode/issues/57819) */
266293
}
267294

268-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .tab-label.tab-label-has-badge::after {
269-
padding-right: 5px; /* with tab sizing shrink and badges, we want a right-padding because the close button is hidden */
295+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .tab-label.tab-label-has-badge::after,
296+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed > .tab-label.tab-label-has-badge::after {
297+
padding-right: 5px; /* with tab sizing shrink/fixed and badges, we want a right-padding because the close button is hidden */
270298
}
271299

272300
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sticky-compact:not(.has-icon) .monaco-icon-label {
@@ -278,13 +306,16 @@
278306
overflow: visible; /* fixes https://github.com/microsoft/vscode/issues/20182 */
279307
}
280308

281-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-container {
309+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-container,
310+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed > .monaco-icon-label > .monaco-icon-label-container {
282311
text-overflow: clip;
283312
flex: none;
284313
}
285314

286315
.monaco-workbench.hc-black .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-container,
287-
.monaco-workbench.hc-light .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-container {
316+
.monaco-workbench.hc-light .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-container,
317+
.monaco-workbench.hc-black .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed > .monaco-icon-label > .monaco-icon-label-container,
318+
.monaco-workbench.hc-light .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed > .monaco-icon-label > .monaco-icon-label-container {
288319
text-overflow: ellipsis;
289320
}
290321

@@ -300,15 +331,20 @@
300331
width: 28px;
301332
}
302333

303-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-shrink > .tab-actions {
334+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-shrink > .tab-actions,
335+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-fixed > .tab-actions {
304336
flex: 0;
305-
overflow: hidden; /* let the tab actions be pushed out of view when sizing is set to shrink to make more room */
337+
overflow: hidden; /* let the tab actions be pushed out of view when sizing is set to shrink/fixed to make more room */
306338
}
307339

308340
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty.tab-actions-right.sizing-shrink > .tab-actions,
309341
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sticky.tab-actions-right.sizing-shrink > .tab-actions,
310342
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-shrink:hover > .tab-actions,
311-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-shrink > .tab-actions:focus-within {
343+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-shrink > .tab-actions:focus-within,
344+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty.tab-actions-right.sizing-fixed > .tab-actions,
345+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sticky.tab-actions-right.sizing-fixed > .tab-actions,
346+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-fixed:hover > .tab-actions,
347+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-fixed > .tab-actions:focus-within {
312348
overflow: visible; /* ...but still show the tab actions on hover, focus and when dirty or sticky */
313349
}
314350

@@ -366,8 +402,9 @@
366402
padding-right: 10px; /* give a little bit more room if tab actions is off */
367403
}
368404

369-
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.tab-actions-off:not(.sticky-compact) {
370-
padding-right: 5px; /* we need less room when sizing is shrink (unless tab is sticky-compact) */
405+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.tab-actions-off:not(.sticky-compact),
406+
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.tab-actions-off:not(.sticky-compact) {
407+
padding-right: 5px; /* we need less room when sizing is shrink/fixed (unless tab is sticky-compact) */
371408
}
372409

373410
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-off.dirty-border-top > .tab-actions {

src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ export class NoTabsTitleControl extends TitleControl {
143143
}
144144
}
145145

146+
beforeCloseEditor(): void {
147+
// Nothing to do before closing an editor
148+
}
149+
146150
closeEditor(editor: EditorInput, index: number | undefined): void {
147151
this.ifActiveEditorChanged(() => this.redraw());
148152
}

0 commit comments

Comments
 (0)