Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow tabs to wrap to multi-line #106448

Merged
merged 54 commits into from
Jan 4, 2021
Merged

Allow tabs to wrap to multi-line #106448

merged 54 commits into from
Jan 4, 2021

Conversation

jmannanc
Copy link
Contributor

This PR fixes #70413

M5b7NlCmUZ

Copy link
Member

@bpasero bpasero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sneakyfish5 kudos, this is a very elegant solution given it only requires CSS changes 👍

Some feedback after a quick review:

  • can we expose the setting from IEditorPartConfiguration? This should make it much easier to read the setting and react to changes (e.g. from
    this._register(this.accessor.onDidEditorPartOptionsChange(e => {
    )
  • the color introduced for the border needs to be themable (i.e. cannot be hardcoded in the CSS) and needs some testing together with the existing tab border colors that we have, I am not sure it will work in all cases
  • when tabs wrap they do not align nicely below the editor action bar (see screenshot below), can we possibly improve this?
  • there seems to be a bug when trying to drop a tab after the last tab, the drop feedback spans multiple rows (see video below)

image

recording (1)

@bpasero bpasero added this to the On Deck milestone Sep 11, 2020
@jmannanc
Copy link
Contributor Author

jmannanc commented Sep 11, 2020

Most of the CSS work was done by people in the original issue; I just pieced it together into a setting, so huge props to them 😃

can we expose the setting from IEditorPartConfiguration?

Done

the color introduced for the border needs to be themable (i.e. cannot be hardcoded in the CSS) and needs some testing together with the existing tab border colors that we have, I am not sure it will work in all cases

Done, I used TAB_BORDER and applied it to the bottom-border of tabs, let me know if that wasn't the correct theme part to use.

when tabs wrap they do not align nicely below the editor action bar (see screenshot below), can we possibly improve this?
there seems to be a bug when trying to drop a tab after the last tab, the drop feedback spans multiple rows (see video below)

I think a neat solution for both of these problems is provided by @fraigo in #70413 (comment), let me know what you think. Here's a visual representation of it included with all the other changes:

fICfbYyV3w

Otherwise, setting a max-width while using flex-grow might be another option?

@jmannanc jmannanc force-pushed the wrap-tabs branch 2 times, most recently from d9b6152 to 8139024 Compare September 14, 2020 02:26
@bpasero
Copy link
Member

bpasero commented Sep 14, 2020

@sneakyfish5

I think a neat solution for both of these problems is provided by @fraigo in #70413 (comment), let me know what you think. Here's a visual representation of it included with all the other changes:

This looks very similar to tabSizing: shrink where tabs shrink to a fixed size when too many are opened. What I do not like about the presented solution is that tabs now consume the entire width even when available space is there to show them normally. Ideally only tabs at the far right end would align vertically by growing or shrinking, right? Not sure how to get that done in pure CSS though... maybe there is a flex property that can help?

@fraigo
Copy link

fraigo commented Sep 14, 2020

@bpasero @sneakyfish5 One solution to make the last row use the space better is adding a 'hidden' flex space after the last tab (in this case, adding space at the end of the tab container. I think 33% is a good value, could be changed to any other for the try the best fit.

.monaco-workbench .part.editor > .content .editor-group-container > .title.tabs> .tabs-and-actions-container.multi-line-tabs-container > .monaco-scrollable-element > .tabs-container::after {
	content: "";
	flex: 1 0 33%;
}

multi_tabls_last

@jmannanc
Copy link
Contributor Author

After some digging as well I couldn't figure out how to make the tabs stay the same size and align properly at the very far end, aside from setting a max-width to an arbitrary percentage, which is a pretty hacky fix. I like the solution that @fraigo is presenting. When testing it out flex: 1 0 0; worked better for me and made a smoother transition to the next line when opening new tabs, would there be any problem with that?

@fraigo
Copy link

fraigo commented Sep 15, 2020

yes @sneakyfish5, using flex:1 0 0 works fine (even using flex: 1 0 auto should work in this case because there is no content to shrink), using the minimum spanning space.

@jmannanc
Copy link
Contributor Author

Awesome, recorded a little snippet here:

Mq6p1kONjL

@bpasero is that better?

@bpasero
Copy link
Member

bpasero commented Sep 15, 2020

@sneakyfish5 can you add this solution to this PR for me to play with? Easier then to give some feedback. I will also comment on the tab border then, thanks 👍

@jmannanc
Copy link
Contributor Author

Will do 👍

@bpasero
Copy link
Member

bpasero commented Sep 16, 2020

@sneakyfish5 this works great when many tabs are opened and it wraps but is there a way to not have excessively large tabs when you only have few opened:

image

?

@bpasero
Copy link
Member

bpasero commented Sep 16, 2020

I pushed a few polish changes to your branch and thought about the use of border: I think conceptually it makes a lot of sense to use tab.border for this because according to the docs: Border to separate tabs from each other so it fits.

However, I think the logic of drawing this border should merge with the existing border we already have for active tabs which also draws a border below tabs:

if (activeTabBorderColorBottom) {
addClass(tabContainer, 'tab-border-bottom');
tabContainer.style.setProperty('--tab-border-bottom-color', activeTabBorderColorBottom.toString());
} else {
removeClass(tabContainer, 'tab-border-bottom');
tabContainer.style.removeProperty('--tab-border-bottom-color');
}

This ensures we are using the same logic for rendering a border and more importantly allows to still have a different border color for the active tab compared to others.

@jmannanc
Copy link
Contributor Author

this works great when many tabs are opened and it wraps but is there a way to not have excessively large tabs when you only have few opened

That's the current issue I'm facing that I'm not sure how to solve. I've tried setting a max-width, but I've realized it doesn't work on smaller window sizes. If anyone has any better ideas, please chime in as I'm definitely not the best at CSS.

However, I think the logic of drawing this border should merge with the existing border we already have for active tabs which also draws a border below tabs

Done, it now only draws a bottom-border for inactive tabs when multi-line tabs are enabled. Is that what you meant?

The commits got a little messy there (sorry about that), but I've fixed merge conflicts and changed it to use classList.toggle instead.

@bpasero
Copy link
Member

bpasero commented Sep 16, 2020

@sneakyfish5 one thing we could maybe try is to do the flex trick conditionally depending on wether the tabs wrap or not? E.g. when you open only a few tabs they would appear normally and only when they wrap we start the trick?

Code wise we know exactly how much space we have and how much space tabs consume around here:

if (this.group.stickyCount > 0 && availableTabsContainerWidth < TabsTitleControl.TAB_SIZES.fit) {

So we could toggle a similar class depending on how much space tabs consume in the tab container?

@jmannanc
Copy link
Contributor Author

That's definitely possible, I've made it so that the multi-line tabs class only added if the "all tabs width" is greater than the "visible tabs width", and is removed if they are equal and the container height is equal to EDITOR_TITLE_HEIGHT.

FRIxM5PYVj

I agree this probably isn't the most optimal situation and that it would be preferable to have the tabs be somewhat the same size and also expand to fill the container at the end of the row, but I'm not sure how to accomplish that.

@bpasero bpasero self-requested a review September 17, 2020 06:21
@@ -501,6 +502,10 @@ class DropOverlay extends Themable {

private getOverlayOffsetHeight(): number {
if (!this.groupView.isEmpty && this.accessor.partOptions.showTabs) {
const tablist = document.querySelector(DropOverlay.TABS_SELECTOR) as HTMLElement;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not work properly once you have more than one editor group opened because then you will have more than one div.tabs-container.

I suggest an alternate solution where the accessor provides a method to ask for the height of the editor title area. The accessor in this case is the EditorPart which can delegate this to the group in question and then the group can forward this to the title control. And I would only use the offsetHeight property if mutli-line tabs are enabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, please let me know if I've done this incorrectly.

src/vs/workbench/browser/parts/editor/tabsTitleControl.ts Outdated Show resolved Hide resolved
@@ -1174,6 +1188,10 @@ export class TabsTitleControl extends TitleControl {
tabContainer.style.backgroundColor = this.getColor(isGroupActive ? TAB_INACTIVE_BACKGROUND : TAB_UNFOCUSED_INACTIVE_BACKGROUND) || '';
tabContainer.style.boxShadow = '';

// bottom border when wrapping multi-line
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion was to reuse the tab-border-bottom helper for this case too and not introduce yet another border. Currently the tab-border-bottom is reserved for active tabs because the border was only used for active tabs, but to ensure we get a consistent look, we should be using the same thing for the separator as well. Otherwise we end up with an active border that is not on the exact same line as the separator border.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, I misunderstood what you suggested earlier but hopefully it's correct now?

@bpasero
Copy link
Member

bpasero commented Dec 27, 2020

Actually with a53fe3c found a nice solution via CSS variables that does not require to patch any tab element directly. This makes sure we only have a margin-right for the last tab when wrapping is enabled.

I think this PR is close to be done, I would appreciate some testing so that we are certain this works as intended.

@bpasero bpasero modified the milestones: On Deck, January 2021 Dec 27, 2020
@cullenjohnson
Copy link

This is the PR I have been waiting for for years. Is there any way I can help get this merged faster? :)

@jmannanc
Copy link
Contributor Author

Hey, sorry again I've been very busy recently. Thank you so much @bpasero for pushing all those fixes.

@cullenjohnson maybe you can help with the testing outlined here, or just in general do any sort of testing that you can think of? If not no worries, I'll be able to get some testing done within the next day or so as well, but of course all help is appreciated.

@swinder0161
Copy link
Contributor

swinder0161 commented Dec 30, 2020 via email

@jmannanc
Copy link
Contributor Author

jmannanc commented Jan 1, 2021

Sorry for the delay again, had a lot of issues with node-gyp when building but was finally able to get it working and do the tests. I did a run through of all things outlined in #106448 (comment) as well as:

  • Anything I could think of related to pinned tabs
  • tabCloseButton setting
  • titleScrollbarSizing setting
  • Scroll to switch tabs
  • Theming

I also tested a few more things that I can't quite remember now, however they all worked, and everything looked good in regards to the editor height and layout. If there are any more tests that need to be completed, please let me know.

@bpasero
Copy link
Member

bpasero commented Jan 2, 2021

Thanks a lot @sneakyfish5 I plan to merge this soon to get it into insiders during January for more coverage.

@bpasero bpasero marked this pull request as ready for review January 3, 2021 09:36
@bpasero bpasero merged commit baf15f1 into microsoft:master Jan 4, 2021
@bpasero
Copy link
Member

bpasero commented Jan 4, 2021

Thanks @sneakyfish5 for pushing this forward 🥂

@ghost
Copy link

ghost commented Jan 4, 2021

This issue seems to be merged now - Am I right?
When is the next official release of VSCode?

@bpasero
Copy link
Member

bpasero commented Jan 4, 2021

@Tschebbe if you don't want to wait until your next stable release in early February, simply switch to VSCode insiders to get this as early as tomorrow: https://code.visualstudio.com/insiders/

@jmannanc jmannanc deleted the wrap-tabs branch January 5, 2021 00:41
@jmannanc
Copy link
Contributor Author

jmannanc commented Jan 5, 2021

Thank you as well @bpasero for your continuous effort and assistance in pushing this PR forward!

@DynDux
Copy link

DynDux commented Jan 6, 2021

I think I found a pure css solution for the problem with last tab spanning the whole width!
Just add the following style when tabSizing = fit:

.tabs-container::after{ content: ''; flex-grow: 20; }

This will create an additional tab pseudo-element, that grows 20 times larger than the other tabs. It could be an even higher number, but I think 20 should be sufficient.
The margin-right on the last-child ist still needed though.

@bpasero
Copy link
Member

bpasero commented Jan 6, 2021

@DynDux @sneakyfish5 great, I suggest we take this idea to a new PR and test it out there, what do you think?

@DynDux
Copy link

DynDux commented Jan 6, 2021

Totally ok for me! Just thought it belongs to this PR because this is how it should have been resolved in first place. ;-)
Please do whatever the right workflow is. Thank you so much!

@bpasero
Copy link
Member

bpasero commented Jan 6, 2021

I have added your suggested solution to #113801.

@qs-labs
Copy link

qs-labs commented Feb 4, 2021

Great work to those involved! Pumped to have this feature 👏 🎉 👏

@microsoft microsoft locked and limited conversation to collaborators Feb 9, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow tabs to wrap to multi-line
9 participants