Skip to content

Commit

Permalink
Merge branch 'main' into rebornix/lengthy-chameleon
Browse files Browse the repository at this point in the history
  • Loading branch information
rebornix authored Feb 14, 2023
2 parents 05b4fdd + a69701a commit a319754
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 14 deletions.
31 changes: 30 additions & 1 deletion src/vs/workbench/browser/parts/activitybar/activitybarActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

import 'vs/css!./media/activityaction';
import { localize } from 'vs/nls';
import { EventType, addDisposableListener, EventHelper } from 'vs/base/browser/dom';
import { EventType, addDisposableListener, EventHelper, append, $, clearNode, hide, show } from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { Action, IAction, Separator, SubmenuAction, toAction } from 'vs/base/common/actions';
import { Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IMenuService, MenuId, IMenu, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions';
Expand Down Expand Up @@ -344,6 +345,9 @@ export interface IProfileActivity extends IActivity {

export class GlobalActivityActionViewItem extends MenuActivityActionViewItem {

private profileBadge: HTMLElement | undefined;
private profileBadgeContent: HTMLElement | undefined;

constructor(
action: ActivityAction,
contextMenuActionsProvider: () => IAction[],
Expand All @@ -360,6 +364,31 @@ export class GlobalActivityActionViewItem extends MenuActivityActionViewItem {
@IKeybindingService keybindingService: IKeybindingService,
) {
super(MenuId.GlobalActivity, action, contextMenuActionsProvider, true, colors, activityHoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService);
this._register(Event.any(this.userDataProfileService.onDidUpdateCurrentProfile, this.userDataProfileService.onDidChangeCurrentProfile)(() => this.updateProfileBadge()));
}

override render(container: HTMLElement): void {
super.render(container);

this.profileBadge = append(container, $('.profile-badge'));
this.profileBadgeContent = append(this.profileBadge, $('.profile-badge-content'));
this.updateProfileBadge();
}

protected updateProfileBadge(): void {
if (!this.profileBadge || !this.profileBadgeContent) {
return;
}

clearNode(this.profileBadgeContent);
hide(this.profileBadge);

if (this.userDataProfileService.currentProfile.isDefault) {
return;
}

this.profileBadgeContent.textContent = this.userDataProfileService.currentProfile.name.substring(0, 2).toUpperCase();
show(this.profileBadge);
}

protected override computeTitle(): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@
outline: none;
}

.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .profile-badge,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .active-item-indicator,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge {
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
margin: auto;
Expand All @@ -141,6 +141,15 @@
height: 100%;
}

.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .active-item-indicator,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge {
z-index: 2;
}

.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .profile-badge {
z-index: 1;
}

.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .active-item-indicator {
pointer-events: none;
}
Expand All @@ -163,6 +172,24 @@
text-align: center;
}

.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .profile-badge .profile-badge-content {
position: absolute;
font-weight: 600;
font-size: 11px;
line-height: 10px;
top: 28px;
right: 24px;
padding: 1px;
border-radius: 3px;
background-color: var(--vscode-activityBar-background);
color: var(--vscode-activityBar-inactiveForeground);
}

.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:active .profile-badge-content,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .profile-badge-content,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .profile-badge-content {
color: var(--vscode-activityBar-foreground);
}

.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge .codicon.badge-content {
font-size: 12px;
Expand All @@ -178,6 +205,7 @@

/* Right aligned */

.monaco-workbench .activitybar.right>.content :not(.monaco-menu)>.monaco-action-bar .profile-badge,
.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .badge {
left: auto;
right: 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
height: 100%;
}

.explorer-item-hover {
/* -- Must set important as hover overrides the cursor -- */
cursor: pointer !important;
padding-left: 6px;
height: 22px;
font-size: 13px;
}

.explorer-folders-view .monaco-list-row {
padding-left: 4px; /* align top level twistie with `Explorer` title label */
}
Expand Down
70 changes: 66 additions & 4 deletions src/vs/workbench/contrib/files/browser/views/explorerViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { ITreeCompressionDelegate } from 'vs/base/browser/ui/tree/asyncDataTree'
import { ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree';
import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
import { ILabelService } from 'vs/platform/label/common/label';
import { isNumber } from 'vs/base/common/types';
import { isNumber, isStringArray } from 'vs/base/common/types';
import { IEditableData } from 'vs/workbench/common/views';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
Expand All @@ -62,6 +62,9 @@ import { ResourceSet } from 'vs/base/common/map';
import { TernarySearchTree } from 'vs/base/common/ternarySearchTree';
import { defaultInputBoxStyles } from 'vs/platform/theme/browser/defaultStyles';
import { timeout } from 'vs/base/common/async';
import { IHoverDelegate, IHoverDelegateOptions, IHoverWidget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';

export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {

Expand Down Expand Up @@ -275,6 +278,64 @@ export class FilesRenderer implements ICompressibleTreeRenderer<ExplorerItem, Fu
private _onDidChangeActiveDescendant = new EventMultiplexer<void>();
readonly onDidChangeActiveDescendant = this._onDidChangeActiveDescendant.event;

private readonly hoverDelegate = new class implements IHoverDelegate {

readonly placement = 'element';

get delay() {
return this.configurationService.getValue<number>('workbench.hover.delay');
}

constructor(
private readonly configurationService: IConfigurationService,
private readonly hoverService: IHoverService
) { }

showHover(options: IHoverDelegateOptions, focus?: boolean): IHoverWidget | undefined {
let element: HTMLElement;
if (options.target instanceof HTMLElement) {
element = options.target;
} else {
element = options.target.targetElements[0];
}

const row = element.closest('.monaco-tl-row') as HTMLElement | undefined;

const child = element.querySelector('div.monaco-icon-label-container') as Element | undefined;
const childOfChild = child?.querySelector('span.monaco-icon-name-container') as HTMLElement | undefined;
let overflowed = false;
if (childOfChild && child) {
const width = child.clientWidth;
const childWidth = childOfChild.offsetWidth;
// Check if element is overflowing its parent container
overflowed = width <= childWidth;
}

const hasDecoration = element.classList.toString().includes('monaco-decoration-iconBadge');
// If it's overflowing or has a decoration show the tooltip
overflowed = overflowed || hasDecoration;

const indentGuideElement = row?.querySelector('.monaco-tl-indent') as HTMLElement | undefined;
if (!indentGuideElement) {
return;
}

return overflowed ? this.hoverService.showHover({
...options,
target: indentGuideElement,
compact: true,
additionalClasses: ['explorer-item-hover'],
skipFadeInAnimation: true,
showPointer: false,
onClick: (e) => {
this.hoverService.hideHover();
element.dispatchEvent(new MouseEvent(e.type, { ...e, bubbles: true }));
},
hoverPosition: HoverPosition.RIGHT,
}, focus) : undefined;
}
}(this.configurationService, this.hoverService);

constructor(
container: HTMLElement,
private labels: ResourceLabels,
Expand All @@ -285,7 +346,8 @@ export class FilesRenderer implements ICompressibleTreeRenderer<ExplorerItem, Fu
@IExplorerService private readonly explorerService: IExplorerService,
@ILabelService private readonly labelService: ILabelService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IContextMenuService private readonly contextMenuService: IContextMenuService
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IHoverService private readonly hoverService: IHoverService
) {
this.config = this.configurationService.getValue<IFilesConfiguration>();

Expand Down Expand Up @@ -317,8 +379,7 @@ export class FilesRenderer implements ICompressibleTreeRenderer<ExplorerItem, Fu

renderTemplate(container: HTMLElement): IFileTemplateData {
const templateDisposables = new DisposableStore();

const label = templateDisposables.add(this.labels.create(container, { supportHighlights: true }));
const label = templateDisposables.add(this.labels.create(container, { supportHighlights: true, hoverDelegate: this.hoverDelegate }));
templateDisposables.add(label.onDidRender(() => {
try {
if (templateData.currentContext) {
Expand Down Expand Up @@ -417,6 +478,7 @@ export class FilesRenderer implements ICompressibleTreeRenderer<ExplorerItem, Fu
const realignNestedChildren = stat.nestedParent && themeIsUnhappyWithNesting;

templateData.label.setResource({ resource: stat.resource, name: label }, {
title: isStringArray(label) ? label[0] : label,
fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE,
extraClasses: realignNestedChildren ? [...extraClasses, 'align-nest-icon-with-parent-icon'] : extraClasses,
fileDecorations: this.config.explorer.decorations,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
'github-issues.authNow',
'workbench.extensions.search',
'workbench.action.openSettings',
'notebook.selectKernel',
'_notebook.selectKernel',
// TODO@rebornix explore open output channel with name command
'jupyter.viewOutput'
],
Expand Down
6 changes: 5 additions & 1 deletion src/vs/workbench/services/hover/browser/hover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IDisposable } from 'vs/base/common/lifecycle';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';

export const IHoverService = createDecorator<IHoverService>('hoverService');

Expand Down Expand Up @@ -129,6 +128,11 @@ export interface IHoverOptions {
trapFocus?: boolean;

/**
* A callback which will be executed when the hover is clicked
*/
onClick?(e: MouseEvent): void;

/*
* The container to pass to {@link IContextViewProvider.showContextView} which renders the hover
* in. This is particularly useful for more natural tab focusing behavior, where the hover is
* created as the next tab index after the element being hovered and/or to workaround the
Expand Down
5 changes: 5 additions & 0 deletions src/vs/workbench/services/hover/browser/hoverService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ export class HoverService implements IHoverService {
options.container
);
hover.onRequestLayout(() => provider.layout());
if (options.onClick) {
hoverDisposables.add(addDisposableListener(hover.domNode, EventType.CLICK, e => {
options.onClick!(e);
}));
}
if ('targetElements' in options.target) {
for (const element of options.target.targetElements) {
hoverDisposables.add(addDisposableListener(element, EventType.CLICK, () => this.hideHover()));
Expand Down
17 changes: 11 additions & 6 deletions src/vs/workbench/services/textfile/browser/textFileService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,13 +591,18 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
// of untitled model if it is a valid path name and
// figure out the file extension from the mode if any.

let nameCandidate: string;
if (await this.pathService.hasValidBasename(joinPath(defaultFilePath, model.name), model.name)) {
const languageId = model.getLanguageId();
if (languageId && languageId !== PLAINTEXT_LANGUAGE_ID) {
suggestedFilename = this.suggestFilename(languageId, model.name);
} else {
suggestedFilename = model.name;
}
nameCandidate = model.name;
} else {
nameCandidate = basename(resource);
}

const languageId = model.getLanguageId();
if (languageId && languageId !== PLAINTEXT_LANGUAGE_ID) {
suggestedFilename = this.suggestFilename(languageId, nameCandidate);
} else {
suggestedFilename = nameCandidate;
}
}
}
Expand Down

0 comments on commit a319754

Please sign in to comment.