Skip to content

Commit 120a822

Browse files
authoredFeb 21, 2024··
Show decorations in the editor tabs (#13301) (#13371)
1 parent 4d7f225 commit 120a822

File tree

4 files changed

+81
-7
lines changed

4 files changed

+81
-7
lines changed
 

‎packages/core/src/browser/core-preferences.ts

+6
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ export const corePreferenceSchema: PreferenceSchema = {
200200
'description': nls.localizeByDefault('Controls whether an editor is revealed in any of the visible groups if opened. If disabled, an editor will prefer to open in the currently active editor group. If enabled, an already opened editor will be revealed instead of opened again in the currently active editor group. Note that there are some cases where this setting is ignored, such as when forcing an editor to open in a specific group or to the side of the currently active group.'),
201201
'default': false
202202
},
203+
'workbench.editor.decorations.badges': {
204+
'type': 'boolean',
205+
'description': nls.localizeByDefault('Controls whether editor file decorations should use badges.'),
206+
'default': true
207+
},
203208
'workbench.commandPalette.history': {
204209
type: 'number',
205210
default: 50,
@@ -295,6 +300,7 @@ export interface CoreConfiguration {
295300
'workbench.editor.mouseBackForwardToNavigate': boolean;
296301
'workbench.editor.closeOnFileDelete': boolean;
297302
'workbench.editor.revealIfOpen': boolean;
303+
'workbench.editor.decorations.badges': boolean;
298304
'workbench.colorTheme': string;
299305
'workbench.iconTheme': string;
300306
'workbench.silentNotifications': boolean;

‎packages/core/src/browser/shell/tab-bar-decorator.ts

+36-6
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
import debounce = require('lodash.debounce');
1818
import { Title, Widget } from '@phosphor/widgets';
1919
import { inject, injectable, named } from 'inversify';
20-
import { Event, Emitter, ContributionProvider } from '../../common';
21-
import { WidgetDecoration } from '../widget-decoration';
20+
import { ContributionProvider, Emitter, Event } from '../../common';
21+
import { ColorRegistry } from '../color-registry';
22+
import { Decoration, DecorationsService, DecorationsServiceImpl } from '../decorations-service';
2223
import { FrontendApplicationContribution } from '../frontend-application-contribution';
24+
import { Navigatable } from '../navigatable-types';
25+
import { WidgetDecoration } from '../widget-decoration';
2326

2427
export const TabBarDecorator = Symbol('TabBarDecorator');
2528

@@ -53,6 +56,12 @@ export class TabBarDecoratorService implements FrontendApplicationContribution {
5356
@inject(ContributionProvider) @named(TabBarDecorator)
5457
protected readonly contributions: ContributionProvider<TabBarDecorator>;
5558

59+
@inject(DecorationsService)
60+
protected readonly decorationsService: DecorationsServiceImpl;
61+
62+
@inject(ColorRegistry)
63+
protected readonly colors: ColorRegistry;
64+
5665
initialize(): void {
5766
this.contributions.getContributions().map(decorator => decorator.onDidChangeDecorations(this.fireDidChangeDecorations));
5867
}
@@ -66,11 +75,32 @@ export class TabBarDecoratorService implements FrontendApplicationContribution {
6675
*/
6776
getDecorations(title: Title<Widget>): WidgetDecoration.Data[] {
6877
const decorators = this.contributions.getContributions();
69-
let all: WidgetDecoration.Data[] = [];
78+
const decorations: WidgetDecoration.Data[] = [];
7079
for (const decorator of decorators) {
71-
const decorations = decorator.decorate(title);
72-
all = all.concat(decorations);
80+
decorations.push(...decorator.decorate(title));
7381
}
74-
return all;
82+
if (Navigatable.is(title.owner)) {
83+
const resourceUri = title.owner.getResourceUri();
84+
if (resourceUri) {
85+
const serviceDecorations = this.decorationsService.getDecoration(resourceUri, false);
86+
decorations.push(...serviceDecorations.map(d => this.fromDecoration(d)));
87+
}
88+
}
89+
return decorations;
90+
}
91+
92+
protected fromDecoration(decoration: Decoration): WidgetDecoration.Data {
93+
const colorVariable = decoration.colorId && this.colors.toCssVariableName(decoration.colorId);
94+
return {
95+
tailDecorations: [
96+
{
97+
data: decoration.letter ? decoration.letter : '',
98+
fontData: {
99+
color: colorVariable && `var(${colorVariable})`
100+
},
101+
tooltip: decoration.tooltip ? decoration.tooltip : ''
102+
}
103+
]
104+
};
75105
}
76106
}

‎packages/core/src/browser/shell/tab-bars.ts

+33-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import PerfectScrollbar from 'perfect-scrollbar';
1818
import { TabBar, Title, Widget } from '@phosphor/widgets';
1919
import { VirtualElement, h, VirtualDOM, ElementInlineStyle } from '@phosphor/virtualdom';
20-
import { Disposable, DisposableCollection, MenuPath, notEmpty, SelectionService, CommandService, nls } from '../../common';
20+
import { Disposable, DisposableCollection, MenuPath, notEmpty, SelectionService, CommandService, nls, ArrayUtils } from '../../common';
2121
import { ContextMenuRenderer } from '../context-menu-renderer';
2222
import { Signal, Slot } from '@phosphor/signaling';
2323
import { Message, MessageLoop } from '@phosphor/messaging';
@@ -188,6 +188,7 @@ export class TabBarRenderer extends TabBar.Renderer {
188188
{ className: 'theia-tab-icon-label' },
189189
this.renderIcon(data, isInSidePanel),
190190
this.renderLabel(data, isInSidePanel),
191+
this.renderTailDecorations(data, isInSidePanel),
191192
this.renderBadge(data, isInSidePanel),
192193
this.renderLock(data, isInSidePanel)
193194
),
@@ -289,6 +290,37 @@ export class TabBarRenderer extends TabBar.Renderer {
289290
return h.div({ className: 'p-TabBar-tabLabel', style }, data.title.label);
290291
}
291292

293+
protected renderTailDecorations(renderData: SideBarRenderData, isInSidePanel?: boolean): VirtualElement[] {
294+
if (!this.corePreferences?.get('workbench.editor.decorations.badges')) {
295+
return [];
296+
}
297+
const tailDecorations = ArrayUtils.coalesce(this.getDecorationData(renderData.title, 'tailDecorations')).flat();
298+
if (tailDecorations === undefined || tailDecorations.length === 0) {
299+
return [];
300+
}
301+
let dotDecoration: WidgetDecoration.TailDecoration.AnyPartial | undefined;
302+
const otherDecorations: WidgetDecoration.TailDecoration.AnyPartial[] = [];
303+
tailDecorations.reverse().forEach(decoration => {
304+
const partial = decoration as WidgetDecoration.TailDecoration.AnyPartial;
305+
if (WidgetDecoration.TailDecoration.isDotDecoration(partial)) {
306+
dotDecoration ||= partial;
307+
} else if (partial.data || partial.icon || partial.iconClass) {
308+
otherDecorations.push(partial);
309+
}
310+
});
311+
const decorationsToRender = dotDecoration ? [dotDecoration, ...otherDecorations] : otherDecorations;
312+
return decorationsToRender.map((decoration, index) => {
313+
const { tooltip, data, fontData, color, icon, iconClass } = decoration;
314+
const iconToRender = icon ?? iconClass;
315+
const className = ['p-TabBar-tail', 'flex'].join(' ');
316+
const style = fontData ? fontData : color ? { color } : undefined;
317+
const content = (data ? data : iconToRender
318+
? h.span({ className: this.getIconClass(iconToRender, iconToRender === 'circle' ? [WidgetDecoration.Styles.DECORATOR_SIZE_CLASS] : []) })
319+
: '') + (index !== decorationsToRender.length - 1 ? ',' : '');
320+
return h.span({ key: ('tailDecoration_' + index), className, style, title: tooltip ?? content }, content);
321+
});
322+
}
323+
292324
renderBadge(data: SideBarRenderData, isInSidePanel?: boolean): VirtualElement {
293325
const totalBadge = this.getDecorationData(data.title, 'badge').reduce((sum, badge) => sum! + badge!, 0);
294326
if (!totalBadge) {

‎packages/core/src/browser/style/tabs.css

+6
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@
123123
white-space: nowrap;
124124
}
125125

126+
.p-TabBar-tail {
127+
padding-left: 5px;
128+
text-align: center;
129+
justify-content: center;
130+
}
131+
126132
.p-TabBar.theia-app-centers .p-TabBar-tabLabelWrapper {
127133
display: flex;
128134
}

0 commit comments

Comments
 (0)
Please sign in to comment.