Merge from vscode 6fded8a497cd0142de3a1c607649a5423a091a25

This commit is contained in:
ADS Merger
2020-04-04 04:30:52 +00:00
parent 00cc0074f7
commit 35f1a014d5
184 changed files with 3043 additions and 2285 deletions

View File

@@ -504,6 +504,37 @@ export class ResetViewLocationsAction extends Action {
registry.registerWorkbenchAction(SyncActionDescriptor.create(ResetViewLocationsAction, ResetViewLocationsAction.ID, ResetViewLocationsAction.LABEL), 'View: Reset View Locations', viewCategory);
// --- Toggle View with Command
export abstract class ToggleViewAction extends Action {
constructor(
id: string,
label: string,
private readonly viewId: string,
protected viewsService: IViewsService,
protected viewDescriptorService: IViewDescriptorService,
protected contextKeyService: IContextKeyService,
private layoutService: IWorkbenchLayoutService,
cssClass?: string
) {
super(id, label, cssClass);
}
async run(): Promise<void> {
const focusedViewId = FocusedViewContext.getValue(this.contextKeyService);
if (focusedViewId === this.viewId) {
if (this.viewDescriptorService.getViewLocation(this.viewId) === ViewContainerLocation.Sidebar) {
this.layoutService.setSideBarHidden(true);
} else {
this.layoutService.setPanelHidden(true);
}
} else {
this.viewsService.openView(this.viewId, true);
}
}
}
// --- Move View with Command
export class MoveFocusedViewAction extends Action {
static readonly ID = 'workbench.action.moveFocusedView';
@@ -541,6 +572,7 @@ export class MoveFocusedViewAction extends Action {
const quickPick = this.quickInputService.createQuickPick();
quickPick.placeholder = nls.localize('moveFocusedView.selectDestination', "Select a Destination for the View");
quickPick.title = nls.localize('moveFocusedView.title', "View: Move {0}", viewDescriptor.name);
const items: Array<IQuickPickItem | IQuickPickSeparator> = [];
@@ -549,10 +581,16 @@ export class MoveFocusedViewAction extends Action {
label: nls.localize('sidebar', "Side Bar")
});
items.push({
id: '_.sidebar.newcontainer',
label: nls.localize('moveFocusedView.newContainerInSidebar', "New Container in Side Bar")
});
const currentContainer = this.viewDescriptorService.getViewContainer(focusedViewId)!;
const currentLocation = this.viewDescriptorService.getViewLocation(focusedViewId)!;
const isViewSolo = this.viewDescriptorService.getViewDescriptors(currentContainer).allViewDescriptors.length === 1;
if (!(isViewSolo && currentLocation === ViewContainerLocation.Sidebar)) {
items.push({
id: '_.sidebar.newcontainer',
label: nls.localize('moveFocusedView.newContainerInSidebar', "New Container in Side Bar")
});
}
const pinnedViewlets = this.activityBarService.getPinnedViewletIds();
items.push(...pinnedViewlets
@@ -574,10 +612,13 @@ export class MoveFocusedViewAction extends Action {
type: 'separator',
label: nls.localize('panel', "Panel")
});
items.push({
id: '_.panel.newcontainer',
label: nls.localize('moveFocusedView.newContainerInPanel', "New Container in Panel"),
});
if (!(isViewSolo && currentLocation === ViewContainerLocation.Panel)) {
items.push({
id: '_.panel.newcontainer',
label: nls.localize('moveFocusedView.newContainerInPanel', "New Container in Panel"),
});
}
const pinnedPanels = this.panelService.getPinnedPanels();
items.push(...pinnedPanels

View File

@@ -127,7 +127,7 @@ abstract class BaseOpenRecentAction extends Action {
const pick = await this.quickInputService.pick(picks, {
contextKey: inRecentFilesPickerContextKey,
activeItem: [...workspacePicks, ...filePicks][autoFocusSecondEntry ? 1 : 0],
placeHolder: isMacintosh ? nls.localize('openRecentPlaceHolderMac', "Select to open (hold Cmd-key to force new window or Alt-key for same window)") : nls.localize('openRecentPlaceHolder', "Select to open (hold Ctrl-key to force new window or Alt-key for same window)"),
placeHolder: isMacintosh ? nls.localize('openRecentPlaceholderMac', "Select to open (hold Cmd-key to force new window or Alt-key for same window)") : nls.localize('openRecentPlaceholder', "Select to open (hold Ctrl-key to force new window or Alt-key for same window)"),
matchOnDescription: true,
onKeyMods: mods => keyMods = mods,
quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined,
@@ -196,6 +196,7 @@ abstract class BaseOpenRecentAction extends Action {
return {
iconClasses,
label: name,
ariaLabel: isDirty ? nls.localize('recentDirtyAriaLabel', "{0}, dirty workspace", name) : name,
description: parentPath,
buttons: isDirty ? [this.dirtyRecentlyOpened] : [this.removeFromRecentlyOpened],
openable,

View File

@@ -509,8 +509,10 @@ export function containsDragType(event: DragEvent, ...dragTypesToFind: string[])
return false;
}
export type Before2D = { verticallyBefore: boolean; horizontallyBefore: boolean; };
export interface ICompositeDragAndDrop {
drop(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent, before?: boolean): void;
drop(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent, before?: Before2D): void;
onDragOver(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent): boolean;
onDragEnter(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent): boolean;
}

View File

@@ -6,11 +6,7 @@
import { Registry } from 'vs/platform/registry/common/platform';
import { IPanel } from 'vs/workbench/common/panel';
import { Composite, CompositeDescriptor, CompositeRegistry } from 'vs/workbench/browser/composite';
import { Action } from 'vs/base/common/actions';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { IConstructorSignature0, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { isAncestor } from 'vs/base/browser/dom';
import { assertIsDefined } from 'vs/base/common/types';
import { PaneComposite } from 'vs/workbench/browser/panecomposite';
@@ -85,44 +81,6 @@ export class PanelRegistry extends CompositeRegistry<Panel> {
}
}
/**
* A reusable action to toggle a panel with a specific id depending on focus.
*/
export abstract class TogglePanelAction extends Action {
constructor(
id: string,
label: string,
private readonly panelId: string,
protected panelService: IPanelService,
private layoutService: IWorkbenchLayoutService,
cssClass?: string
) {
super(id, label, cssClass);
}
async run(): Promise<void> {
if (this.isPanelFocused()) {
this.layoutService.setPanelHidden(true);
} else {
await this.panelService.openPanel(this.panelId, true);
}
}
private isPanelActive(): boolean {
const activePanel = this.panelService.getActivePanel();
return activePanel?.getId() === this.panelId;
}
private isPanelFocused(): boolean {
const activeElement = document.activeElement;
const panelPart = this.layoutService.getContainer(Parts.PANEL_PART);
return !!(this.isPanelActive() && activeElement && panelPart && isAncestor(activeElement, panelPart));
}
}
export const Extensions = {
Panels: 'workbench.contributions.panels'
};

View File

@@ -42,6 +42,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { getUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync';
import { IProductService } from 'vs/platform/product/common/productService';
import { Before2D } from 'vs/workbench/browser/dnd';
interface IPlaceholderViewlet {
id: string;
@@ -152,7 +153,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
hidePart: () => this.layoutService.setSideBarHidden(true),
dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Sidebar,
(id: string, focus?: boolean) => this.viewletService.openViewlet(id, focus),
(from: string, to: string, before?: boolean) => this.compositeBar.move(from, to, before)
(from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.verticallyBefore)
),
compositeSize: 50,
colors: (theme: IColorTheme) => this.getActivitybarItemColors(theme),

View File

@@ -23,7 +23,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
import { IComposite } from 'vs/workbench/common/composite';
import { CompositeDragAndDropData, CompositeDragAndDropObserver, IDraggedCompositeData, ICompositeDragAndDrop } from 'vs/workbench/browser/dnd';
import { CompositeDragAndDropData, CompositeDragAndDropObserver, IDraggedCompositeData, ICompositeDragAndDrop, Before2D } from 'vs/workbench/browser/dnd';
export interface ICompositeBarItem {
id: string;
@@ -39,9 +39,9 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
private viewDescriptorService: IViewDescriptorService,
private targetContainerLocation: ViewContainerLocation,
private openComposite: (id: string, focus?: boolean) => Promise<IPaneComposite | undefined>,
private moveComposite: (from: string, to: string, before?: boolean) => void,
private moveComposite: (from: string, to: string, before?: Before2D) => void,
) { }
drop(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent, before?: boolean): void {
drop(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent, before?: Before2D): void {
const dragData = data.getData();
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
@@ -255,7 +255,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
},
onDrop: (e: IDraggedCompositeData) => {
const pinnedItems = this.getPinnedComposites();
this.options.dndHandler.drop(e.dragAndDropData, pinnedItems[pinnedItems.length - 1].id, e.eventData, false);
this.options.dndHandler.drop(e.dragAndDropData, pinnedItems[pinnedItems.length - 1].id, e.eventData, { horizontallyBefore: false, verticallyBefore: false });
toggleClass(parent, 'dragged-over', false);
}
}));

View File

@@ -18,7 +18,7 @@ import { DelayedDragHandler } from 'vs/base/browser/dnd';
import { IActivity } from 'vs/workbench/common/activity';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { Emitter } from 'vs/base/common/event';
import { LocalSelectionTransfer, DraggedCompositeIdentifier, DraggedViewIdentifier, CompositeDragAndDropObserver, ICompositeDragAndDrop } from 'vs/workbench/browser/dnd';
import { LocalSelectionTransfer, DraggedCompositeIdentifier, DraggedViewIdentifier, CompositeDragAndDropObserver, ICompositeDragAndDrop, Before2D } from 'vs/workbench/browser/dnd';
import { Color } from 'vs/base/common/color';
export interface ICompositeActivity {
@@ -516,7 +516,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
this.showContextMenu(container);
}));
let insertDropBefore: boolean | undefined = undefined;
let insertDropBefore: Before2D | undefined = undefined;
// Allow to drag
this._register(CompositeDragAndDropObserver.INSTANCE.registerDraggable(this.container, () => { return { type: 'composite', id: this.activity.id }; }, {
onDragOver: e => {
@@ -534,7 +534,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
onDrop: e => {
dom.EventHelper.stop(e.eventData, true);
this.dndHandler.drop(e.dragAndDropData, this.activity.id, e.eventData, !!insertDropBefore);
this.dndHandler.drop(e.dragAndDropData, this.activity.id, e.eventData, insertDropBefore);
insertDropBefore = this.updateFromDragging(container, false, e.eventData);
},
onDragStart: e => {
@@ -563,7 +563,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
this.updateStyles();
}
private updateFromDragging(element: HTMLElement, showFeedback: boolean, event: DragEvent): boolean | undefined {
private updateFromDragging(element: HTMLElement, showFeedback: boolean, event: DragEvent): Before2D | undefined {
const rect = element.getBoundingClientRect();
const posX = event.clientX;
const posY = event.clientY;
@@ -598,7 +598,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
return undefined;
}
return top || left;
return { verticallyBefore: top, horizontallyBefore: left };
}
private showContextMenu(container: HTMLElement): void {

View File

@@ -8,22 +8,24 @@ import { localize } from 'vs/nls';
import { IQuickPickSeparator, quickPickItemScorerAccessor, IQuickPickItemWithResource, IQuickPick } from 'vs/platform/quickinput/common/quickInput';
import { PickerQuickAccessProvider, IPickerQuickAccessItem, TriggerAction } from 'vs/platform/quickinput/browser/pickerQuickAccess';
import { IEditorGroupsService, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { EditorsOrder, IEditorIdentifier, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
import { EditorsOrder, IEditorIdentifier, toResource, SideBySideEditor, GroupIdentifier } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { prepareQuery, scoreItem, compareItemsByScore, ScorerCache } from 'vs/base/common/fuzzyScorer';
import { prepareQuery, scoreItemFuzzy, compareItemsByFuzzyScore, FuzzyScorerCache } from 'vs/base/common/fuzzyScorer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IDisposable } from 'vs/base/common/lifecycle';
interface IEditorQuickPickItem extends IQuickPickItemWithResource, IEditorIdentifier, IPickerQuickAccessItem { }
interface IEditorQuickPickItem extends IQuickPickItemWithResource, IPickerQuickAccessItem {
groupId: GroupIdentifier;
}
export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessProvider<IEditorQuickPickItem> {
private readonly pickState = new class {
scorerCache: ScorerCache = Object.create(null);
scorerCache: FuzzyScorerCache = Object.create(null);
isQuickNavigating: boolean | undefined = undefined;
reset(isQuickNavigating: boolean): void {
@@ -45,7 +47,15 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
@IModelService private readonly modelService: IModelService,
@IModeService private readonly modeService: IModeService
) {
super(prefix, { canAcceptInBackground: true });
super(prefix,
{
canAcceptInBackground: true,
noResultsPick: {
label: localize('noViewResults', "No matching editors"),
groupId: -1
}
}
);
}
provide(picker: IQuickPick<IEditorQuickPickItem>, token: CancellationToken): IDisposable {
@@ -67,7 +77,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
}
// Score on label and description
const itemScore = scoreItem(entry, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
const itemScore = scoreItemFuzzy(entry, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
if (!itemScore.score) {
return false;
}
@@ -86,7 +96,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
return groups.indexOf(entryA.groupId) - groups.indexOf(entryB.groupId); // older groups first
}
return compareItemsByScore(entryA, entryB, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
return compareItemsByFuzzyScore(entryA, entryB, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
});
}
@@ -113,16 +123,35 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
}
private doGetEditorPickItems(): Array<IEditorQuickPickItem> {
const editors = this.doGetEditors();
const mapGroupIdToGroupAriaLabel = new Map<GroupIdentifier, string>();
for (const { groupId } of editors) {
if (!mapGroupIdToGroupAriaLabel.has(groupId)) {
const group = this.editorGroupService.getGroup(groupId);
if (group) {
mapGroupIdToGroupAriaLabel.set(groupId, group.ariaLabel);
}
}
}
return this.doGetEditors().map(({ editor, groupId }): IEditorQuickPickItem => {
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
const isDirty = editor.isDirty() && !editor.isSaving();
return {
editor,
groupId,
resource,
label: editor.getName(),
ariaLabel: localize('entryAriaLabel', "{0}, editors picker", editor.getName()),
ariaLabel: (() => {
if (mapGroupIdToGroupAriaLabel.size > 1) {
return isDirty ?
localize('entryAriaLabelWithGroupDirty', "{0}, dirty, {1}", editor.getName(), mapGroupIdToGroupAriaLabel.get(groupId)) :
localize('entryAriaLabelWithGroup', "{0}, {1}", editor.getName(), mapGroupIdToGroupAriaLabel.get(groupId));
}
return isDirty ? localize('entryAriaLabelDirty', "{0}, dirty", editor.getName()) : editor.getName();
})(),
description: editor.getDescription(),
iconClasses: getIconClasses(this.modelService, this.modeService, resource),
italic: !this.editorGroupService.getGroup(groupId)?.isPinned(editor),

View File

@@ -38,6 +38,7 @@ import { MenuId } from 'vs/platform/actions/common/actions';
import { ViewMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { Before2D } from 'vs/workbench/browser/dnd';
interface ICachedPanel {
id: string;
@@ -147,8 +148,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
getDefaultCompositeId: () => this.panelRegistry.getDefaultPanelId(),
hidePart: () => this.layoutService.setPanelHidden(true),
dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Panel,
(id: string, focus?: boolean) => <unknown>this.openPanel(id, focus) as Promise<IPaneComposite | undefined>, // {{SQL CARBON EDIT}} strict-null-checks
(from: string, to: string, before?: boolean) => this.compositeBar.move(from, to, before)
(id: string, focus?: boolean) => <unknown>this.openPanel(id, focus) as Promise<IPaneComposite | undefined>, // {{SQL CARBON EDIT}} strict-null-checks
(from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.horizontallyBefore)
),
compositeSize: 0,
overflowActionSize: 44,

View File

@@ -428,7 +428,7 @@ export class CustomMenubarControl extends MenubarControl {
return new Action('update.checking', nls.localize('checkingForUpdates', "Checking for Updates..."), undefined, false);
case StateType.AvailableForDownload:
return new Action('update.downloadNow', nls.localize({ key: 'download now', comment: ['&& denotes a mnemonic'] }, "D&&ownload Now"), undefined, true, () =>
return new Action('update.downloadNow', nls.localize({ key: 'download now', comment: ['&& denotes a mnemonic'] }, "D&&ownload Update"), undefined, true, () =>
this.updateService.downloadUpdate());
case StateType.Downloading:

View File

@@ -6,6 +6,9 @@
.monaco-pane-view .split-view-view:first-of-type > .pane > .pane-header {
border-top: none !important; /* less clutter: do not show any border for first views in a pane */
}
.monaco-pane-view .split-view-view:first-of-type > .pane {
border-left: none !important; /* less clutter: do not show any border for first views in a pane */
}
.monaco-pane-view .pane > .pane-header {
position: relative;
@@ -24,10 +27,6 @@
-webkit-margin-after: 0;
}
.monaco-pane-view .pane > .pane-header h3.title:first-child {
margin-left: 7px;
}
.monaco-pane-view .pane .monaco-progress-container {
position: absolute;
left: 0;

View File

@@ -52,9 +52,9 @@
.monaco-workbench .pane > .pane-body > .welcome-view {
width: 100%;
height: 100%;
padding: 0 20px 0 20px;
position: absolute;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.monaco-workbench .pane > .pane-body:not(.welcome) > .welcome-view,
@@ -69,6 +69,15 @@
display: block;
}
.monaco-workbench .pane > .pane-body .welcome-view-content {
padding: 0 20px 0 20px;
box-sizing: border-box;
}
.monaco-workbench .pane > .pane-body .welcome-view-content > *:last-child {
margin-bottom: 1em;
}
.customview-tree .monaco-list-row .monaco-tl-contents.align-icon-with-twisty::before {
display: none;
}

View File

@@ -8,7 +8,7 @@ import * as nls from 'vs/nls';
import { Event, Emitter } from 'vs/base/common/event';
import { ColorIdentifier, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { attachStyler, IColorMapping, attachButtonStyler, attachLinkStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler';
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, SIDE_BAR_SECTION_HEADER_BORDER, PANEL_BACKGROUND, SIDE_BAR_BACKGROUND, EDITOR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme';
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, SIDE_BAR_SECTION_HEADER_BORDER, PANEL_BACKGROUND, SIDE_BAR_BACKGROUND, EDITOR_DRAG_AND_DROP_BACKGROUND, PANEL_BORDER } from 'vs/workbench/common/theme';
import { append, $, trackFocus, toggleClass, EventType, isAncestor, Dimension, addDisposableListener, removeClass, addClass } from 'vs/base/browser/dom';
import { IDisposable, combinedDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { firstIndex } from 'vs/base/common/arrays';
@@ -47,12 +47,15 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { CompositeProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator';
import { IProgressIndicator } from 'vs/platform/progress/common/progress';
import { RunOnceScheduler } from 'vs/base/common/async';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
export interface IPaneColors extends IColorMapping {
dropBackground?: ColorIdentifier;
headerForeground?: ColorIdentifier;
headerBackground?: ColorIdentifier;
headerBorder?: ColorIdentifier;
leftBorder?: ColorIdentifier;
}
export interface IViewPaneOptions extends IPaneOptions {
@@ -309,9 +312,20 @@ export abstract class ViewPane extends Pane implements IView {
this._onDidChangeTitleArea.fire();
}
private scrollableElement!: DomScrollableElement;
protected renderBody(container: HTMLElement): void {
this.bodyContainer = container;
this.viewWelcomeContainer = append(container, $('.welcome-view', { tabIndex: 0 }));
const viewWelcomeContainer = append(container, $('.welcome-view'));
this.viewWelcomeContainer = $('.welcome-view-content', { tabIndex: 0 });
this.scrollableElement = this._register(new DomScrollableElement(this.viewWelcomeContainer, {
alwaysConsumeMouseWheel: true,
horizontal: ScrollbarVisibility.Hidden,
vertical: ScrollbarVisibility.Visible,
}));
append(viewWelcomeContainer, this.scrollableElement.getDomNode());
const onViewWelcomeChange = Event.any(this.viewWelcomeController.onDidChange, this.onDidChangeViewWelcomeState);
this._register(onViewWelcomeChange(this.updateViewWelcome, this));
@@ -319,7 +333,9 @@ export abstract class ViewPane extends Pane implements IView {
}
protected layoutBody(height: number, width: number): void {
// noop
this.viewWelcomeContainer.style.height = `${height}px`;
this.viewWelcomeContainer.style.width = `${width}px`;
this.scrollableElement.scanDomNode();
}
getProgressIndicator() {
@@ -410,6 +426,7 @@ export abstract class ViewPane extends Pane implements IView {
if (!this.shouldShowWelcome()) {
removeClass(this.bodyContainer, 'welcome');
this.viewWelcomeContainer.innerHTML = '';
this.scrollableElement.scanDomNode();
return;
}
@@ -418,6 +435,7 @@ export abstract class ViewPane extends Pane implements IView {
if (contents.length === 0) {
removeClass(this.bodyContainer, 'welcome');
this.viewWelcomeContainer.innerHTML = '';
this.scrollableElement.scanDomNode();
return;
}
@@ -437,47 +455,52 @@ export abstract class ViewPane extends Pane implements IView {
continue;
}
const p = append(this.viewWelcomeContainer, $('p'));
const linkedText = parseLinkedText(line);
for (const node of linkedText.nodes) {
if (typeof node === 'string') {
append(p, document.createTextNode(node));
} else if (linkedText.nodes.length === 1) {
const button = new Button(p, { title: node.title });
button.label = node.label;
button.onDidClick(_ => {
this.telemetryService.publicLog2<{ viewId: string, uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.id, uri: node.href });
this.openerService.open(node.href);
}, null, disposables);
disposables.add(button);
disposables.add(attachButtonStyler(button, this.themeService));
if (linkedText.nodes.length === 1 && typeof linkedText.nodes[0] !== 'string') {
const node = linkedText.nodes[0];
const button = new Button(this.viewWelcomeContainer, { title: node.title });
button.label = node.label;
button.onDidClick(_ => {
this.telemetryService.publicLog2<{ viewId: string, uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.id, uri: node.href });
this.openerService.open(node.href);
}, null, disposables);
disposables.add(button);
disposables.add(attachButtonStyler(button, this.themeService));
if (preconditions) {
const precondition = preconditions[buttonIndex];
if (preconditions) {
const precondition = preconditions[buttonIndex];
if (precondition) {
const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);
updateEnablement();
if (precondition) {
const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);
updateEnablement();
const keys = new Set();
precondition.keys().forEach(key => keys.add(key));
const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));
onDidChangeContext(updateEnablement, null, disposables);
}
const keys = new Set();
precondition.keys().forEach(key => keys.add(key));
const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));
onDidChangeContext(updateEnablement, null, disposables);
}
}
buttonIndex++;
} else {
const link = this.instantiationService.createInstance(Link, node);
append(p, link.el);
disposables.add(link);
disposables.add(attachLinkStyler(link, this.themeService));
buttonIndex++;
} else {
const p = append(this.viewWelcomeContainer, $('p'));
for (const node of linkedText.nodes) {
if (typeof node === 'string') {
append(p, document.createTextNode(node));
} else {
const link = this.instantiationService.createInstance(Link, node);
append(p, link.el);
disposables.add(link);
disposables.add(attachLinkStyler(link, this.themeService));
}
}
}
}
}
this.scrollableElement.scanDomNode();
this.viewWelcomeDisposable = disposables;
}
@@ -523,7 +546,7 @@ class ViewPaneDropOverlay extends Themable {
constructor(
private paneElement: HTMLElement,
private orientation: Orientation,
private orientation: Orientation | undefined,
protected themeService: IThemeService
) {
super(themeService);
@@ -540,6 +563,7 @@ class ViewPaneDropOverlay extends Themable {
// Container
this.container = document.createElement('div');
this.container.id = ViewPaneDropOverlay.OVERLAY_ID;
this.container.style.top = '0px';
// Parent
this.paneElement.appendChild(this.container);
@@ -575,6 +599,7 @@ class ViewPaneDropOverlay extends Themable {
this.overlay.style.borderColor = activeContrastBorderColor || '';
this.overlay.style.borderStyle = 'solid' || '';
this.overlay.style.borderWidth = '0px';
}
private registerListeners(): void {
@@ -629,7 +654,7 @@ class ViewPaneDropOverlay extends Themable {
} else if (mousePosY >= splitHeightThreshold) {
dropDirection = DropDirection.DOWN;
}
} else {
} else if (this.orientation === Orientation.HORIZONTAL) {
if (mousePosX < splitWidthThreshold) {
dropDirection = DropDirection.LEFT;
} else if (mousePosX >= splitWidthThreshold) {
@@ -655,7 +680,12 @@ class ViewPaneDropOverlay extends Themable {
this.doPositionOverlay({ top: '0', left: '0', width: '100%', height: '100%' });
}
this.doUpdateOverlayBorder(dropDirection);
if ((this.orientation === Orientation.VERTICAL && paneHeight <= 25) ||
(this.orientation === Orientation.HORIZONTAL && paneWidth <= 25)) {
this.doUpdateOverlayBorder(dropDirection);
} else {
this.doUpdateOverlayBorder(undefined);
}
// Make sure the overlay is visible now
this.overlay.style.opacity = '1';
@@ -788,6 +818,71 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
this._register(this.paneview.onDidDrop(({ from, to }) => this.movePane(from as ViewPane, to as ViewPane)));
this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, (e: MouseEvent) => this.showContextMenu(new StandardMouseEvent(e))));
let overlay: ViewPaneDropOverlay | undefined;
this._register(CompositeDragAndDropObserver.INSTANCE.registerTarget(parent, {
onDragEnter: (e) => {
if (!overlay && this.panes.length === 0) {
const dropData = e.dragAndDropData.getData();
if (dropData.type === 'view') {
const oldViewContainer = this.viewDescriptorService.getViewContainer(dropData.id);
const viewDescriptor = this.viewDescriptorService.getViewDescriptor(dropData.id);
if (oldViewContainer !== this.viewContainer && (!viewDescriptor || !viewDescriptor.canMoveView)) {
return;
}
overlay = new ViewPaneDropOverlay(parent, undefined, this.themeService);
}
if (dropData.type === 'composite' && dropData.id !== this.viewContainer.id) {
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
const container = viewContainerRegistry.get(dropData.id)!;
const viewsToMove = this.viewDescriptorService.getViewDescriptors(container).allViewDescriptors;
if (viewsToMove.length === 1 && viewsToMove[0].canMoveView) {
overlay = new ViewPaneDropOverlay(parent, undefined, this.themeService);
}
}
}
},
onDragLeave: (e) => {
overlay?.dispose();
overlay = undefined;
},
onDrop: (e) => {
if (overlay) {
const dropData = e.dragAndDropData.getData();
if (dropData.type === 'composite' && dropData.id !== this.viewContainer.id) {
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
const container = viewContainerRegistry.get(dropData.id)!;
const viewsToMove = this.viewDescriptorService.getViewDescriptors(container).allViewDescriptors;
if (viewsToMove.length === 1 && viewsToMove[0].canMoveView) {
dropData.type = 'view';
dropData.id = viewsToMove[0].id;
}
}
if (dropData.type === 'view') {
const oldViewContainer = this.viewDescriptorService.getViewContainer(dropData.id);
const viewDescriptor = this.viewDescriptorService.getViewDescriptor(dropData.id);
if (oldViewContainer !== this.viewContainer && viewDescriptor && viewDescriptor.canMoveView) {
this.viewDescriptorService.moveViewsToContainer([viewDescriptor], this.viewContainer);
}
}
}
overlay?.dispose();
overlay = undefined;
}
}));
this._register(this.onDidSashChange(() => this.saveViewSizes()));
this.viewsModel.onDidAdd(added => this.onDidAddViewDescriptors(added));
this.viewsModel.onDidRemove(removed => this.onDidRemoveViewDescriptors(removed));
@@ -1143,6 +1238,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
headerForeground: SIDE_BAR_SECTION_HEADER_FOREGROUND,
headerBackground: SIDE_BAR_SECTION_HEADER_BACKGROUND,
headerBorder: SIDE_BAR_SECTION_HEADER_BORDER,
leftBorder: PANEL_BORDER,
dropBackground: SIDE_BAR_DRAG_AND_DROP_BACKGROUND
}, pane);
const disposable = combinedDisposable(onDidFocus, onDidChangeTitleArea, paneStyler, onDidChange, onDidChangeVisibility);