Update to VS Code 1.52.1
This commit is contained in:
@@ -10,15 +10,14 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
|
||||
import { Action, IAction, Separator, SubmenuAction } from 'vs/base/common/actions';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { SyncActionDescriptor, IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IMenuService, MenuId, IMenu, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { CATEGORIES, Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { IActivity } from 'vs/workbench/common/activity';
|
||||
import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
|
||||
@@ -26,44 +25,31 @@ import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/bro
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { isMacintosh, isWeb } from 'vs/base/common/platform';
|
||||
import { getCurrentAuthenticationSessionInfo, IAuthenticationService } from 'vs/workbench/services/authentication/browser/authenticationService';
|
||||
import { AuthenticationSession } from 'vs/editor/common/modes';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { AnchorAlignment, AnchorAxisAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { getTitleBarStyle } from 'vs/platform/windows/common/windows';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export class ViewContainerActivityAction extends ActivityAction {
|
||||
|
||||
private static readonly preventDoubleClickDelay = 300;
|
||||
|
||||
private readonly viewletService: IViewletService;
|
||||
private readonly layoutService: IWorkbenchLayoutService;
|
||||
private readonly telemetryService: ITelemetryService;
|
||||
private readonly configurationService: IConfigurationService;
|
||||
|
||||
private lastRun: number;
|
||||
private lastRun = 0;
|
||||
|
||||
constructor(
|
||||
activity: IActivity,
|
||||
@IViewletService viewletService: IViewletService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IConfigurationService configurationService: IConfigurationService
|
||||
@IViewletService private readonly viewletService: IViewletService,
|
||||
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super(activity);
|
||||
|
||||
this.lastRun = 0;
|
||||
this.viewletService = viewletService;
|
||||
this.layoutService = layoutService;
|
||||
this.telemetryService = telemetryService;
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
|
||||
updateActivity(activity: IActivity): void {
|
||||
@@ -105,6 +91,7 @@ export class ViewContainerActivityAction extends ActivityAction {
|
||||
|
||||
this.logAction('show');
|
||||
await this.viewletService.openViewlet(this.activity.id, true);
|
||||
|
||||
return this.activate();
|
||||
}
|
||||
|
||||
@@ -117,21 +104,18 @@ export class ViewContainerActivityAction extends ActivityAction {
|
||||
}
|
||||
}
|
||||
|
||||
export const ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts';
|
||||
class MenuActivityActionViewItem extends ActivityActionViewItem {
|
||||
|
||||
export class AccountsActionViewItem extends ActivityActionViewItem {
|
||||
constructor(
|
||||
private readonly menuId: MenuId,
|
||||
action: ActivityAction,
|
||||
colors: (theme: IColorTheme) => ICompositeBarColors,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextMenuService protected contextMenuService: IContextMenuService,
|
||||
@IMenuService protected menuService: IMenuService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IMenuService protected readonly menuService: IMenuService,
|
||||
@IContextMenuService protected readonly contextMenuService: IContextMenuService,
|
||||
@IContextKeyService protected readonly contextKeyService: IContextKeyService,
|
||||
@IConfigurationService protected readonly configurationService: IConfigurationService,
|
||||
@IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
super(action, { draggable: false, colors, icon: true }, themeService);
|
||||
}
|
||||
@@ -161,12 +145,103 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
|
||||
}));
|
||||
}
|
||||
|
||||
private async getActions(accountsMenu: IMenu) {
|
||||
protected async showContextMenu(e?: MouseEvent): Promise<void> {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const menu = disposables.add(this.menuService.createMenu(this.menuId, this.contextKeyService));
|
||||
const actions = await this.resolveActions(menu, disposables);
|
||||
|
||||
const isUsingCustomMenu = isWeb || (getTitleBarStyle(this.configurationService) !== 'native' && !isMacintosh); // see #40262
|
||||
const position = this.configurationService.getValue('workbench.sideBar.location');
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => isUsingCustomMenu ? this.container : e || this.container,
|
||||
anchorAlignment: isUsingCustomMenu ? (position === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT) : undefined,
|
||||
anchorAxisAlignment: isUsingCustomMenu ? AnchorAxisAlignment.HORIZONTAL : AnchorAxisAlignment.VERTICAL,
|
||||
getActions: () => actions,
|
||||
onHide: () => disposables.dispose()
|
||||
});
|
||||
}
|
||||
|
||||
protected async resolveActions(menu: IMenu, disposables: DisposableStore): Promise<IAction[]> {
|
||||
const actions: IAction[] = [];
|
||||
|
||||
disposables.add(createAndFillInActionBarActions(menu, undefined, { primary: [], secondary: actions }));
|
||||
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
|
||||
export class HomeActivityActionViewItem extends MenuActivityActionViewItem {
|
||||
|
||||
static readonly HOME_BAR_VISIBILITY_PREFERENCE = 'workbench.activity.showHomeIndicator';
|
||||
|
||||
constructor(
|
||||
private readonly goHomeHref: string,
|
||||
action: ActivityAction,
|
||||
colors: (theme: IColorTheme) => ICompositeBarColors,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@IStorageService private readonly storageService: IStorageService
|
||||
) {
|
||||
super(MenuId.MenubarHomeMenu, action, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService);
|
||||
}
|
||||
|
||||
protected async resolveActions(homeMenu: IMenu, disposables: DisposableStore): Promise<IAction[]> {
|
||||
const actions = [];
|
||||
|
||||
// Go Home
|
||||
actions.push(disposables.add(new Action('goHome', nls.localize('goHome', "Go Home"), undefined, true, async () => window.location.href = this.goHomeHref)));
|
||||
actions.push(disposables.add(new Separator()));
|
||||
|
||||
// Contributed
|
||||
const contributedActions = await super.resolveActions(homeMenu, disposables);
|
||||
actions.push(...contributedActions);
|
||||
|
||||
// Hide
|
||||
if (contributedActions.length > 0) {
|
||||
actions.push(disposables.add(new Separator()));
|
||||
}
|
||||
actions.push(disposables.add(new Action('hide', nls.localize('hide', "Hide"), undefined, true, async () => {
|
||||
this.storageService.store(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, false, StorageScope.GLOBAL, StorageTarget.USER);
|
||||
})));
|
||||
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
|
||||
export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
|
||||
|
||||
static readonly ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts';
|
||||
|
||||
constructor(
|
||||
action: ActivityAction,
|
||||
colors: (theme: IColorTheme) => ICompositeBarColors,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
) {
|
||||
super(MenuId.AccountsContext, action, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService);
|
||||
}
|
||||
|
||||
protected async resolveActions(accountsMenu: IMenu, disposables: DisposableStore): Promise<IAction[]> {
|
||||
await super.resolveActions(accountsMenu, disposables);
|
||||
|
||||
const otherCommands = accountsMenu.getActions();
|
||||
const providers = this.authenticationService.getProviderIds();
|
||||
const allSessions = providers.map(async id => {
|
||||
const allSessions = providers.map(async providerId => {
|
||||
try {
|
||||
const sessions = await this.authenticationService.getSessions(id);
|
||||
const sessions = await this.authenticationService.getSessions(providerId);
|
||||
|
||||
const groupedSessions: { [label: string]: AuthenticationSession[] } = {};
|
||||
sessions.forEach(session => {
|
||||
@@ -177,14 +252,9 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
providerId: id,
|
||||
sessions: groupedSessions
|
||||
};
|
||||
return { providerId, sessions: groupedSessions };
|
||||
} catch {
|
||||
return {
|
||||
providerId: id
|
||||
};
|
||||
return { providerId };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -196,132 +266,67 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
|
||||
|
||||
if (sessionInfo.sessions) {
|
||||
Object.keys(sessionInfo.sessions).forEach(accountName => {
|
||||
const hasEmbedderAccountSession = sessionInfo.sessions[accountName].some(session => session.id === (authenticationSession?.id));
|
||||
const manageExtensionsAction = new Action(`configureSessions${accountName}`, nls.localize('manageTrustedExtensions', "Manage Trusted Extensions"), '', true, _ => {
|
||||
const manageExtensionsAction = disposables.add(new Action(`configureSessions${accountName}`, nls.localize('manageTrustedExtensions', "Manage Trusted Extensions"), '', true, () => {
|
||||
return this.authenticationService.manageTrustedExtensionsForAccount(sessionInfo.providerId, accountName);
|
||||
});
|
||||
const signOutAction = new Action('signOut', nls.localize('signOut', "Sign Out"), '', true, _ => {
|
||||
return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName);
|
||||
});
|
||||
}));
|
||||
|
||||
const actions = [manageExtensionsAction];
|
||||
const signOutAction = disposables.add(new Action('signOut', nls.localize('signOut', "Sign Out"), '', true, () => {
|
||||
return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName);
|
||||
}));
|
||||
|
||||
const providerSubMenuActions = [manageExtensionsAction];
|
||||
|
||||
const hasEmbedderAccountSession = sessionInfo.sessions[accountName].some(session => session.id === (authenticationSession?.id));
|
||||
if (!hasEmbedderAccountSession || authenticationSession?.canSignOut) {
|
||||
actions.push(signOutAction);
|
||||
providerSubMenuActions.push(signOutAction);
|
||||
}
|
||||
|
||||
const menu = new SubmenuAction('activitybar.submenu', `${accountName} (${providerDisplayName})`, actions);
|
||||
menus.push(menu);
|
||||
const providerSubMenu = disposables.add(new SubmenuAction('activitybar.submenu', `${accountName} (${providerDisplayName})`, providerSubMenuActions));
|
||||
menus.push(providerSubMenu);
|
||||
});
|
||||
} else {
|
||||
const menu = new Action('providerUnavailable', nls.localize('authProviderUnavailable', '{0} is currently unavailable', providerDisplayName));
|
||||
menus.push(menu);
|
||||
const providerUnavailableAction = disposables.add(new Action('providerUnavailable', nls.localize('authProviderUnavailable', '{0} is currently unavailable', providerDisplayName)));
|
||||
menus.push(providerUnavailableAction);
|
||||
}
|
||||
});
|
||||
|
||||
if (menus.length && otherCommands.length) {
|
||||
menus.push(new Separator());
|
||||
menus.push(disposables.add(new Separator()));
|
||||
}
|
||||
|
||||
otherCommands.forEach((group, i) => {
|
||||
const actions = group[1];
|
||||
menus = menus.concat(actions);
|
||||
if (i !== otherCommands.length - 1) {
|
||||
menus.push(new Separator());
|
||||
menus.push(disposables.add(new Separator()));
|
||||
}
|
||||
});
|
||||
|
||||
if (menus.length) {
|
||||
menus.push(new Separator());
|
||||
menus.push(disposables.add(new Separator()));
|
||||
}
|
||||
|
||||
menus.push(new Action('hide', nls.localize('hide', "Hide"), undefined, true, _ => {
|
||||
this.storageService.store(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, false, StorageScope.GLOBAL);
|
||||
return Promise.resolve();
|
||||
}));
|
||||
menus.push(disposables.add(new Action('hide', nls.localize('hide', "Hide"), undefined, true, async () => {
|
||||
this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, false, StorageScope.GLOBAL, StorageTarget.USER);
|
||||
})));
|
||||
|
||||
return menus;
|
||||
}
|
||||
|
||||
private async showContextMenu(e?: MouseEvent): Promise<void> {
|
||||
const accountsActions: IAction[] = [];
|
||||
const accountsMenu = this.menuService.createMenu(MenuId.AccountsContext, this.contextKeyService);
|
||||
const actionsDisposable = createAndFillInActionBarActions(accountsMenu, undefined, { primary: [], secondary: accountsActions });
|
||||
const native = getTitleBarStyle(this.configurationService, this.environmentService) === 'native';
|
||||
const position = this.configurationService.getValue('workbench.sideBar.location');
|
||||
|
||||
const containerPosition = DOM.getDomNodePagePosition(this.container);
|
||||
const location = { x: containerPosition.left + (position === 'left' ? containerPosition.width : 0), y: containerPosition.top };
|
||||
const actions = await this.getActions(accountsMenu);
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => !native ? location : e || this.container,
|
||||
anchorAlignment: !native ? (position === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT) : undefined,
|
||||
getActions: () => actions,
|
||||
onHide: () => {
|
||||
accountsMenu.dispose();
|
||||
dispose(actionsDisposable);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class GlobalActivityActionViewItem extends ActivityActionViewItem {
|
||||
export class GlobalActivityActionViewItem extends MenuActivityActionViewItem {
|
||||
|
||||
constructor(
|
||||
action: ActivityAction,
|
||||
colors: (theme: IColorTheme) => ICompositeBarColors,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IMenuService private readonly menuService: IMenuService,
|
||||
@IContextMenuService protected readonly contextMenuService: IContextMenuService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
super(action, { draggable: false, colors, icon: true }, themeService);
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
|
||||
// Context menus are triggered on mouse down so that an item can be picked
|
||||
// and executed with releasing the mouse over it
|
||||
|
||||
this._register(DOM.addDisposableListener(this.container, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => {
|
||||
DOM.EventHelper.stop(e, true);
|
||||
this.showContextMenu(e);
|
||||
}));
|
||||
|
||||
this._register(DOM.addDisposableListener(this.container, DOM.EventType.KEY_UP, (e: KeyboardEvent) => {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
|
||||
DOM.EventHelper.stop(e, true);
|
||||
this.showContextMenu();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(DOM.addDisposableListener(this.container, TouchEventType.Tap, (e: GestureEvent) => {
|
||||
DOM.EventHelper.stop(e, true);
|
||||
this.showContextMenu();
|
||||
}));
|
||||
}
|
||||
|
||||
private showContextMenu(e?: MouseEvent): void {
|
||||
const globalActivityActions: IAction[] = [];
|
||||
const globalActivityMenu = this.menuService.createMenu(MenuId.GlobalActivity, this.contextKeyService);
|
||||
const actionsDisposable = createAndFillInActionBarActions(globalActivityMenu, undefined, { primary: [], secondary: globalActivityActions });
|
||||
const native = getTitleBarStyle(this.configurationService, this.environmentService) === 'native';
|
||||
const position = this.configurationService.getValue('workbench.sideBar.location');
|
||||
|
||||
const containerPosition = DOM.getDomNodePagePosition(this.container);
|
||||
const location = { x: containerPosition.left + (position === 'left' ? containerPosition.width : 0), y: containerPosition.top + containerPosition.height };
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => !native ? location : e || this.container,
|
||||
anchorAlignment: !native ? (position === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT) : undefined,
|
||||
getActions: () => globalActivityActions,
|
||||
onHide: () => {
|
||||
globalActivityMenu.dispose();
|
||||
dispose(actionsDisposable);
|
||||
}
|
||||
});
|
||||
super(MenuId.GlobalActivity, action, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,106 +343,62 @@ export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinne
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchSideBarViewAction extends Action {
|
||||
class SwitchSideBarViewAction extends Action2 {
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
name: string,
|
||||
@IViewletService private readonly viewletService: IViewletService,
|
||||
@IActivityBarService private readonly activityBarService: IActivityBarService
|
||||
desc: Readonly<IAction2Options>,
|
||||
private readonly offset: number
|
||||
) {
|
||||
super(id, name);
|
||||
super(desc);
|
||||
}
|
||||
|
||||
async run(offset: number): Promise<void> {
|
||||
const visibleViewletIds = this.activityBarService.getVisibleViewContainerIds();
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const activityBarService = accessor.get(IActivityBarService);
|
||||
const viewletService = accessor.get(IViewletService);
|
||||
|
||||
const activeViewlet = this.viewletService.getActiveViewlet();
|
||||
const visibleViewletIds = activityBarService.getVisibleViewContainerIds();
|
||||
|
||||
const activeViewlet = viewletService.getActiveViewlet();
|
||||
if (!activeViewlet) {
|
||||
return;
|
||||
}
|
||||
let targetViewletId: string | undefined;
|
||||
for (let i = 0; i < visibleViewletIds.length; i++) {
|
||||
if (visibleViewletIds[i] === activeViewlet.getId()) {
|
||||
targetViewletId = visibleViewletIds[(i + visibleViewletIds.length + offset) % visibleViewletIds.length];
|
||||
targetViewletId = visibleViewletIds[(i + visibleViewletIds.length + this.offset) % visibleViewletIds.length];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await this.viewletService.openViewlet(targetViewletId, true);
|
||||
await viewletService.openViewlet(targetViewletId, true);
|
||||
}
|
||||
}
|
||||
|
||||
export class PreviousSideBarViewAction extends SwitchSideBarViewAction {
|
||||
|
||||
static readonly ID = 'workbench.action.previousSideBarView';
|
||||
static readonly LABEL = nls.localize('previousSideBarView', 'Previous Side Bar View');
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
name: string,
|
||||
@IViewletService viewletService: IViewletService,
|
||||
@IActivityBarService activityBarService: IActivityBarService
|
||||
) {
|
||||
super(id, name, viewletService, activityBarService);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return super.run(-1);
|
||||
}
|
||||
}
|
||||
|
||||
export class NextSideBarViewAction extends SwitchSideBarViewAction {
|
||||
|
||||
static readonly ID = 'workbench.action.nextSideBarView';
|
||||
static readonly LABEL = nls.localize('nextSideBarView', 'Next Side Bar View');
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
name: string,
|
||||
@IViewletService viewletService: IViewletService,
|
||||
@IActivityBarService activityBarService: IActivityBarService
|
||||
) {
|
||||
super(id, name, viewletService, activityBarService);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return super.run(1);
|
||||
}
|
||||
}
|
||||
|
||||
export class HomeAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly href: string,
|
||||
name: string,
|
||||
icon: Codicon
|
||||
) {
|
||||
super('workbench.action.home', name, icon.classNames);
|
||||
}
|
||||
|
||||
async run(event: MouseEvent): Promise<void> {
|
||||
let openInNewWindow = false;
|
||||
if (isMacintosh) {
|
||||
openInNewWindow = event.metaKey;
|
||||
} else {
|
||||
openInNewWindow = event.ctrlKey;
|
||||
}
|
||||
|
||||
if (openInNewWindow) {
|
||||
DOM.windowOpenNoOpener(this.href);
|
||||
} else {
|
||||
window.location.href = this.href;
|
||||
registerAction2(
|
||||
class PreviousSideBarViewAction extends SwitchSideBarViewAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'workbench.action.previousSideBarView',
|
||||
title: { value: nls.localize('previousSideBarView', "Previous Side Bar View"), original: 'Previous Side Bar View' },
|
||||
category: CATEGORIES.View,
|
||||
f1: true
|
||||
}, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export class HomeActionViewItem extends ActionViewItem {
|
||||
|
||||
constructor(action: IAction) {
|
||||
super(undefined, action, { icon: true, label: false, useEventAsContext: true });
|
||||
registerAction2(
|
||||
class NextSideBarViewAction extends SwitchSideBarViewAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'workbench.action.nextSideBarView',
|
||||
title: { value: nls.localize('nextSideBarView', "Next Side Bar View"), original: 'Next Side Bar View' },
|
||||
category: CATEGORIES.View,
|
||||
f1: true
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {
|
||||
const activityBarBackgroundColor = theme.getColor(ACTIVITY_BAR_BACKGROUND);
|
||||
@@ -510,6 +471,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||
left: 9px;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:before,
|
||||
@@ -549,7 +511,3 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(PreviousSideBarViewAction), 'View: Previous Side Bar View', CATEGORIES.View.value);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(NextSideBarViewAction), 'View: Next Side Bar View', CATEGORIES.View.value);
|
||||
|
||||
@@ -8,24 +8,24 @@ import * as nls from 'vs/nls';
|
||||
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { GLOBAL_ACTIVITY_ID, IActivity, ACCOUNTS_ACTIVITY_ID } from 'vs/workbench/common/activity';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActionViewItem, HomeAction, HomeActionViewItem, ACCOUNTS_VISIBILITY_PREFERENCE_KEY } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
|
||||
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActivityActionViewItem, HomeActivityActionViewItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
|
||||
import { IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDisposable, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ToggleActivityBarVisibilityAction, ToggleMenuBarAction, ToggleSidebarPositionAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeService';
|
||||
import { IThemeService, IColorTheme, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BORDER } from 'vs/workbench/common/theme';
|
||||
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { CompositeBar, ICompositeBarItem, CompositeDragAndDrop } from 'vs/workbench/browser/parts/compositeBar';
|
||||
import { Dimension, createCSSRule, asCSSUrl, addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { IViewDescriptorService, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewContainerModel, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views';
|
||||
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { isUndefinedOrNull, assertIsDefined, isString } from 'vs/base/common/types';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -34,7 +34,6 @@ import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menuba
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { getMenuBarVisibility } from 'vs/platform/windows/common/windows';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { Before2D } from 'vs/workbench/browser/dnd';
|
||||
import { Codicon, iconRegistry } from 'vs/base/common/codicons';
|
||||
import { Action, Separator } from 'vs/base/common/actions';
|
||||
@@ -43,41 +42,45 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
|
||||
interface IPlaceholderViewContainer {
|
||||
id: string;
|
||||
name?: string;
|
||||
iconUrl?: UriComponents;
|
||||
iconCSS?: string;
|
||||
views?: { when?: string }[];
|
||||
readonly id: string;
|
||||
readonly name?: string;
|
||||
readonly iconUrl?: UriComponents;
|
||||
readonly themeIcon?: ThemeIcon;
|
||||
readonly views?: { when?: string }[];
|
||||
}
|
||||
|
||||
interface IPinnedViewContainer {
|
||||
id: string;
|
||||
pinned: boolean;
|
||||
order?: number;
|
||||
visible: boolean;
|
||||
readonly id: string;
|
||||
readonly pinned: boolean;
|
||||
readonly order?: number;
|
||||
readonly visible: boolean;
|
||||
}
|
||||
|
||||
interface ICachedViewContainer {
|
||||
id: string;
|
||||
readonly id: string;
|
||||
name?: string;
|
||||
icon?: URI | string;
|
||||
pinned: boolean;
|
||||
order?: number;
|
||||
icon?: URI | ThemeIcon;
|
||||
readonly pinned: boolean;
|
||||
readonly order?: number;
|
||||
visible: boolean;
|
||||
views?: { when?: string }[];
|
||||
}
|
||||
|
||||
const settingsViewBarIcon = registerIcon('settings-view-bar-icon', Codicon.settingsGear, nls.localize('settingsViewBarIcon', 'Settings icon in the view bar.'));
|
||||
const accountsViewBarIcon = registerIcon('accounts-view-bar-icon', Codicon.account, nls.localize('accountsViewBarIcon', 'Accounts icon in the view bar.'));
|
||||
|
||||
export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private static readonly ACTION_HEIGHT = 48;
|
||||
static readonly PINNED_VIEW_CONTAINERS = 'workbench.activity.pinnedViewlets2';
|
||||
private static readonly PINNED_VIEW_CONTAINERS = 'workbench.activity.pinnedViewlets2';
|
||||
private static readonly PLACEHOLDER_VIEW_CONTAINERS = 'workbench.activity.placeholderViewlets';
|
||||
private static readonly HOME_BAR_VISIBILITY_PREFERENCE = 'workbench.activity.showHomeIndicator';
|
||||
private static readonly ACTION_HEIGHT = 48;
|
||||
private static readonly ACCOUNTS_ACTION_INDEX = 0;
|
||||
|
||||
//#region IView
|
||||
|
||||
readonly minimumWidth: number = 48;
|
||||
@@ -100,17 +103,17 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
private globalActivityAction: ActivityAction | undefined;
|
||||
private globalActivityActionBar: ActionBar | undefined;
|
||||
private readonly globalActivity: ICompositeActivity[] = [];
|
||||
private globalActivitiesContainer: HTMLElement | undefined;
|
||||
private readonly globalActivity: ICompositeActivity[] = [];
|
||||
|
||||
private accountsActivityAction: ActivityAction | undefined;
|
||||
|
||||
private accountsActivity: ICompositeActivity[] = [];
|
||||
private readonly accountsActivity: ICompositeActivity[] = [];
|
||||
|
||||
private readonly compositeActions = new Map<string, { activityAction: ViewContainerActivityAction, pinnedAction: ToggleCompositePinnedAction }>();
|
||||
private readonly viewContainerDisposables = new Map<string, IDisposable>();
|
||||
|
||||
private readonly keyboardNavigationDisposables = new DisposableStore();
|
||||
private readonly keyboardNavigationDisposables = this._register(new DisposableStore());
|
||||
|
||||
private readonly location = ViewContainerLocation.Sidebar;
|
||||
|
||||
@@ -125,27 +128,36 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
|
||||
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: ActivitybarPart.PINNED_VIEW_CONTAINERS, version: 1 });
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, version: 1 });
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: ACCOUNTS_VISIBILITY_PREFERENCE_KEY, version: 1 });
|
||||
|
||||
this.migrateFromOldCachedViewContainersValue();
|
||||
|
||||
for (const cachedViewContainer of this.cachedViewContainers) {
|
||||
if (environmentService.remoteAuthority // In remote window, hide activity bar entries until registered.
|
||||
|| this.shouldBeHidden(cachedViewContainer.id, cachedViewContainer)
|
||||
if (
|
||||
environmentService.remoteAuthority || // In remote window, hide activity bar entries until registered
|
||||
this.shouldBeHidden(cachedViewContainer.id, cachedViewContainer)
|
||||
) {
|
||||
cachedViewContainer.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.compositeBar = this.createCompositeBar();
|
||||
|
||||
this.onDidRegisterViewContainers(this.getViewContainers());
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private createCompositeBar() {
|
||||
const cachedItems = this.cachedViewContainers
|
||||
.map(v => ({ id: v.id, name: v.name, visible: v.visible, order: v.order, pinned: v.pinned }));
|
||||
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, {
|
||||
.map(container => ({
|
||||
id: container.id,
|
||||
name: container.name,
|
||||
visible: container.visible,
|
||||
order: container.order,
|
||||
pinned: container.pinned
|
||||
}));
|
||||
|
||||
return this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, {
|
||||
icon: true,
|
||||
orientation: ActionsOrientation.VERTICAL,
|
||||
preventLoopNavigation: true,
|
||||
@@ -154,8 +166,9 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
getCompositePinnedAction: (compositeId: string) => this.getCompositeActions(compositeId).pinnedAction,
|
||||
getOnCompositeClickAction: (compositeId: string) => new Action(compositeId, '', '', true, () => this.viewsService.isViewContainerVisible(compositeId) ? Promise.resolve(this.viewsService.closeViewContainer(compositeId)) : this.viewsService.openViewContainer(compositeId)),
|
||||
getContextMenuActions: () => {
|
||||
const menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService);
|
||||
const actions = [];
|
||||
|
||||
// Home
|
||||
if (this.homeBarContainer) {
|
||||
actions.push(new Action(
|
||||
'toggleHomeBarAction',
|
||||
@@ -166,22 +179,26 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
));
|
||||
}
|
||||
|
||||
// Menu
|
||||
const menuBarVisibility = getMenuBarVisibility(this.configurationService);
|
||||
if (menuBarVisibility === 'compact' || (menuBarVisibility === 'hidden' && isWeb)) {
|
||||
actions.push(this.instantiationService.createInstance(ToggleMenuBarAction, ToggleMenuBarAction.ID, menuBarVisibility === 'compact' ? nls.localize('hideMenu', "Hide Menu") : nls.localize('showMenu', "Show Menu")));
|
||||
}
|
||||
|
||||
const toggleAccountsVisibilityAction = new Action(
|
||||
// Accounts
|
||||
actions.push(new Action(
|
||||
'toggleAccountsVisibility',
|
||||
this.accountsVisibilityPreference ? nls.localize('hideAccounts', "Hide Accounts") : nls.localize('showAccounts', "Show Accounts"),
|
||||
undefined,
|
||||
true,
|
||||
async () => { this.accountsVisibilityPreference = !this.accountsVisibilityPreference; }
|
||||
);
|
||||
|
||||
actions.push(toggleAccountsVisibilityAction);
|
||||
));
|
||||
actions.push(new Separator());
|
||||
|
||||
// Toggle Sidebar
|
||||
actions.push(this.instantiationService.createInstance(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.getLabel(this.layoutService)));
|
||||
|
||||
// Toggle Activity Bar
|
||||
actions.push(new Action(
|
||||
ToggleActivityBarVisibilityAction.ID,
|
||||
nls.localize('hideActivitBar', "Hide Activity Bar"),
|
||||
@@ -204,19 +221,12 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
colors: (theme: IColorTheme) => this.getActivitybarItemColors(theme),
|
||||
overflowActionSize: ActivitybarPart.ACTION_HEIGHT
|
||||
}));
|
||||
|
||||
this.onDidRegisterViewContainers(this.getViewContainers());
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
focusActivityBar(): void {
|
||||
this.compositeBar.focus();
|
||||
}
|
||||
|
||||
private getContextMenuActionsForComposite(compositeId: string): Action[] {
|
||||
const viewContainer = this.viewDescriptorService.getViewContainerById(compositeId)!;
|
||||
|
||||
const actions = [];
|
||||
|
||||
const viewContainer = this.viewDescriptorService.getViewContainerById(compositeId)!;
|
||||
const defaultLocation = this.viewDescriptorService.getDefaultViewContainerLocation(viewContainer)!;
|
||||
if (defaultLocation !== this.viewDescriptorService.getViewContainerLocation(viewContainer)) {
|
||||
actions.push(new Action('resetLocationAction', nls.localize('resetLocation', "Reset Location"), undefined, true, async () => {
|
||||
@@ -253,13 +263,13 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
disposables.clear();
|
||||
this.onDidRegisterExtensions();
|
||||
this.compositeBar.onDidChange(() => this.saveCachedViewContainers(), this, disposables);
|
||||
this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables);
|
||||
this.storageService.onDidChangeValue(e => this.onDidStorageValueChange(e), this, disposables);
|
||||
}));
|
||||
|
||||
// Register for configuration changes
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('window.menuBarVisibility')) {
|
||||
if (getMenuBarVisibility(this.configurationService, this.environmentService) === 'compact') {
|
||||
if (getMenuBarVisibility(this.configurationService) === 'compact') {
|
||||
this.installMenubar();
|
||||
} else {
|
||||
this.uninstallMenubar();
|
||||
@@ -277,6 +287,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
if (from === this.location) {
|
||||
this.onDidDeregisterViewContainer(container);
|
||||
}
|
||||
|
||||
if (to === this.location) {
|
||||
this.onDidRegisterViewContainers([container]);
|
||||
}
|
||||
@@ -306,6 +317,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
private onDidViewContainerVisible(id: string): void {
|
||||
const viewContainer = this.getViewContainer(id);
|
||||
if (viewContainer) {
|
||||
|
||||
// Update the composite bar by adding
|
||||
this.compositeBar.addComposite(viewContainer);
|
||||
this.compositeBar.activateComposite(viewContainer.id);
|
||||
@@ -313,7 +325,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
if (viewContainer.hideIfEmpty) {
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
if (viewContainerModel.activeViewDescriptors.length === 0) {
|
||||
this.hideComposite(viewContainer.id); // Update the composite bar by hiding
|
||||
// Update the composite bar by hiding
|
||||
this.hideComposite(viewContainer.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,6 +352,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
if (typeof priority !== 'number') {
|
||||
priority = 0;
|
||||
}
|
||||
|
||||
const activity: ICompositeActivity = { badge, clazz, priority };
|
||||
const activityCache = activityId === GLOBAL_ACTIVITY_ID ? this.globalActivity : this.accountsActivity;
|
||||
|
||||
@@ -387,16 +401,18 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
private getCumulativeNumberBadge(activityCache: ICompositeActivity[], priority: number): NumberBadge {
|
||||
const numberActivities = activityCache.filter(activity => activity.badge instanceof NumberBadge && activity.priority === priority);
|
||||
let number = numberActivities.reduce((result, activity) => { return result + (<NumberBadge>activity.badge).number; }, 0);
|
||||
let descriptorFn = (): string => {
|
||||
const number = numberActivities.reduce((result, activity) => { return result + (<NumberBadge>activity.badge).number; }, 0);
|
||||
const descriptorFn = (): string => {
|
||||
return numberActivities.reduce((result, activity, index) => {
|
||||
result = result + (<NumberBadge>activity.badge).getDescription();
|
||||
if (index < numberActivities.length - 1) {
|
||||
result = result + '\n';
|
||||
result = `${result}\n`;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, '');
|
||||
};
|
||||
|
||||
return new NumberBadge(number, descriptorFn);
|
||||
}
|
||||
|
||||
@@ -414,11 +430,19 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
|
||||
private installMenubar() {
|
||||
if (this.menuBar) {
|
||||
return; // prevent menu bar from installing twice #110720
|
||||
}
|
||||
|
||||
this.menuBarContainer = document.createElement('div');
|
||||
this.menuBarContainer.classList.add('menubar');
|
||||
|
||||
const content = assertIsDefined(this.content);
|
||||
content.prepend(this.menuBarContainer);
|
||||
if (this.homeBarContainer) {
|
||||
content.insertBefore(this.menuBarContainer, this.homeBarContainer.nextSibling);
|
||||
} else {
|
||||
content.prepend(this.menuBarContainer);
|
||||
}
|
||||
|
||||
// Menubar: install a custom menu bar depending on configuration
|
||||
this.menuBar = this._register(this.instantiationService.createInstance(CustomMenubarControl));
|
||||
@@ -442,12 +466,12 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
codicon = Codicon.code;
|
||||
}
|
||||
|
||||
this.createHomeBar(homeIndicator.href, homeIndicator.title, codicon);
|
||||
this.createHomeBar(homeIndicator.href, codicon);
|
||||
this.onDidChangeHomeBarVisibility();
|
||||
}
|
||||
|
||||
// Install menubar if compact
|
||||
if (getMenuBarVisibility(this.configurationService, this.environmentService) === 'compact') {
|
||||
if (getMenuBarVisibility(this.configurationService) === 'compact') {
|
||||
this.installMenubar();
|
||||
}
|
||||
|
||||
@@ -456,11 +480,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
// Global action bar
|
||||
this.globalActivitiesContainer = document.createElement('div');
|
||||
this.globalActivitiesContainer.classList.add('global-activity');
|
||||
this.content.appendChild(this.globalActivitiesContainer);
|
||||
|
||||
this.createGlobalActivityActionBar(this.globalActivitiesContainer);
|
||||
|
||||
// Keyboard Navigation
|
||||
this.registerKeyboardNavigationListeners();
|
||||
|
||||
return this.content;
|
||||
@@ -528,23 +552,19 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private createHomeBar(href: string, title: string, icon: Codicon): void {
|
||||
private createHomeBar(href: string, icon: Codicon): void {
|
||||
this.homeBarContainer = document.createElement('div');
|
||||
this.homeBarContainer.setAttribute('aria-label', nls.localize('homeIndicator', "Home"));
|
||||
this.homeBarContainer.setAttribute('role', 'toolbar');
|
||||
this.homeBarContainer.classList.add('home-bar');
|
||||
|
||||
this.homeBar = this._register(new ActionBar(this.homeBarContainer, {
|
||||
actionViewItemProvider: action => this.instantiationService.createInstance(HomeActivityActionViewItem, href, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme)),
|
||||
orientation: ActionsOrientation.VERTICAL,
|
||||
animated: false,
|
||||
ariaLabel: nls.localize('home', "Home"),
|
||||
actionViewItemProvider: action => new HomeActionViewItem(action),
|
||||
allowContextMenu: true,
|
||||
animated: false,
|
||||
preventLoopNavigation: true,
|
||||
ignoreOrientationForPreviousAndNextKey: true
|
||||
}));
|
||||
@@ -552,35 +572,15 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
const homeBarIconBadge = document.createElement('div');
|
||||
homeBarIconBadge.classList.add('home-bar-icon-badge');
|
||||
this.homeBarContainer.appendChild(homeBarIconBadge);
|
||||
this.homeBar.push(this._register(this.instantiationService.createInstance(HomeAction, href, title, icon)));
|
||||
|
||||
this.homeBar.push(this._register(new ActivityAction({
|
||||
id: 'workbench.actions.home',
|
||||
name: nls.localize('home', "Home"),
|
||||
cssClass: icon.classNames
|
||||
})));
|
||||
|
||||
const content = assertIsDefined(this.content);
|
||||
content.prepend(this.homeBarContainer);
|
||||
}
|
||||
|
||||
updateStyles(): void {
|
||||
super.updateStyles();
|
||||
|
||||
const container = assertIsDefined(this.getContainer());
|
||||
const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || '';
|
||||
container.style.backgroundColor = background;
|
||||
|
||||
const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || '';
|
||||
container.classList.toggle('bordered', !!borderColor);
|
||||
container.style.borderColor = borderColor ? borderColor : '';
|
||||
}
|
||||
|
||||
private getActivitybarItemColors(theme: IColorTheme): ICompositeBarColors {
|
||||
return {
|
||||
activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND),
|
||||
inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND),
|
||||
activeBorderColor: theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER),
|
||||
activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND),
|
||||
badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND),
|
||||
badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND),
|
||||
dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER),
|
||||
activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined,
|
||||
};
|
||||
content.appendChild(this.homeBarContainer);
|
||||
}
|
||||
|
||||
private createGlobalActivityActionBar(container: HTMLElement): void {
|
||||
@@ -591,7 +591,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
|
||||
if (action.id === 'workbench.actions.accounts') {
|
||||
return this.instantiationService.createInstance(AccountsActionViewItem, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme));
|
||||
return this.instantiationService.createInstance(AccountsActivityActionViewItem, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme));
|
||||
}
|
||||
|
||||
throw new Error(`No view item for action '${action.id}'`);
|
||||
@@ -603,18 +603,18 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
ignoreOrientationForPreviousAndNextKey: true
|
||||
}));
|
||||
|
||||
this.globalActivityAction = new ActivityAction({
|
||||
this.globalActivityAction = this._register(new ActivityAction({
|
||||
id: 'workbench.actions.manage',
|
||||
name: nls.localize('manage', "Manage"),
|
||||
cssClass: Codicon.settingsGear.classNames
|
||||
});
|
||||
cssClass: ThemeIcon.asClassName(settingsViewBarIcon)
|
||||
}));
|
||||
|
||||
if (this.accountsVisibilityPreference) {
|
||||
this.accountsActivityAction = new ActivityAction({
|
||||
this.accountsActivityAction = this._register(new ActivityAction({
|
||||
id: 'workbench.actions.accounts',
|
||||
name: nls.localize('accounts', "Accounts"),
|
||||
cssClass: Codicon.account.classNames
|
||||
});
|
||||
cssClass: ThemeIcon.asClassName(accountsViewBarIcon)
|
||||
}));
|
||||
|
||||
this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX });
|
||||
}
|
||||
@@ -628,11 +628,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
this.globalActivityActionBar.pull(ActivitybarPart.ACCOUNTS_ACTION_INDEX);
|
||||
this.accountsActivityAction = undefined;
|
||||
} else {
|
||||
this.accountsActivityAction = new ActivityAction({
|
||||
this.accountsActivityAction = this._register(new ActivityAction({
|
||||
id: 'workbench.actions.accounts',
|
||||
name: nls.localize('accounts', "Accounts"),
|
||||
cssClass: Codicon.account.classNames
|
||||
});
|
||||
}));
|
||||
this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX });
|
||||
}
|
||||
}
|
||||
@@ -723,7 +723,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
return ActivitybarPart.toActivity(id, name, icon, focusCommand?.id || id);
|
||||
}
|
||||
|
||||
private static toActivity(id: string, name: string, icon: URI | string | undefined, keybindingId: string | undefined): IActivity {
|
||||
private static toActivity(id: string, name: string, icon: URI | ThemeIcon | undefined, keybindingId: string | undefined): IActivity {
|
||||
let cssClass: string | undefined = undefined;
|
||||
let iconUrl: URI | undefined = undefined;
|
||||
if (URI.isUri(icon)) {
|
||||
@@ -736,9 +736,10 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;
|
||||
-webkit-mask-size: 24px;
|
||||
`);
|
||||
} else if (isString(icon)) {
|
||||
cssClass = icon;
|
||||
} else if (ThemeIcon.isThemeIcon(icon)) {
|
||||
cssClass = ThemeIcon.asClassName(icon);
|
||||
}
|
||||
|
||||
return { id, name, cssClass, iconUrl, keybindingId };
|
||||
}
|
||||
|
||||
@@ -810,6 +811,35 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
.map(v => v.id);
|
||||
}
|
||||
|
||||
focusActivityBar(): void {
|
||||
this.compositeBar.focus();
|
||||
}
|
||||
|
||||
updateStyles(): void {
|
||||
super.updateStyles();
|
||||
|
||||
const container = assertIsDefined(this.getContainer());
|
||||
const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || '';
|
||||
container.style.backgroundColor = background;
|
||||
|
||||
const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || '';
|
||||
container.classList.toggle('bordered', !!borderColor);
|
||||
container.style.borderColor = borderColor ? borderColor : '';
|
||||
}
|
||||
|
||||
private getActivitybarItemColors(theme: IColorTheme): ICompositeBarColors {
|
||||
return {
|
||||
activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND),
|
||||
inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND),
|
||||
activeBorderColor: theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER),
|
||||
activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND),
|
||||
badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND),
|
||||
badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND),
|
||||
dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER),
|
||||
activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
layout(width: number, height: number): void {
|
||||
if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) {
|
||||
return;
|
||||
@@ -834,6 +864,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
private getViewContainer(id: string): ViewContainer | undefined {
|
||||
const viewContainer = this.viewDescriptorService.getViewContainerById(id);
|
||||
|
||||
return viewContainer && this.viewDescriptorService.getViewContainerLocation(viewContainer) === this.location ? viewContainer : undefined;
|
||||
}
|
||||
|
||||
@@ -841,7 +872,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
return this.viewDescriptorService.getViewContainersByLocation(this.location);
|
||||
}
|
||||
|
||||
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
|
||||
private onDidStorageValueChange(e: IStorageValueChangeEvent): void {
|
||||
if (e.key === ActivitybarPart.PINNED_VIEW_CONTAINERS && e.scope === StorageScope.GLOBAL
|
||||
&& this.pinnedViewContainersValue !== this.getStoredPinnedViewContainersValue() /* This checks if current window changed the value or not */) {
|
||||
this._pinnedViewContainersValue = undefined;
|
||||
@@ -870,11 +901,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
this.compositeBar.setCompositeBarItems(newCompositeItems);
|
||||
}
|
||||
|
||||
if (e.key === ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE && e.scope === StorageScope.GLOBAL) {
|
||||
if (e.key === HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE && e.scope === StorageScope.GLOBAL) {
|
||||
this.onDidChangeHomeBarVisibility();
|
||||
}
|
||||
|
||||
if (e.key === ACCOUNTS_VISIBILITY_PREFERENCE_KEY && e.scope === StorageScope.GLOBAL) {
|
||||
if (e.key === AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY && e.scope === StorageScope.GLOBAL) {
|
||||
this.toggleAccountsActivity();
|
||||
}
|
||||
}
|
||||
@@ -917,12 +948,13 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
const cachedViewContainer = this._cachedViewContainers.filter(cached => cached.id === placeholderViewContainer.id)[0];
|
||||
if (cachedViewContainer) {
|
||||
cachedViewContainer.name = placeholderViewContainer.name;
|
||||
cachedViewContainer.icon = placeholderViewContainer.iconCSS ? placeholderViewContainer.iconCSS :
|
||||
cachedViewContainer.icon = placeholderViewContainer.themeIcon ? ThemeIcon.revive(placeholderViewContainer.themeIcon) :
|
||||
placeholderViewContainer.iconUrl ? URI.revive(placeholderViewContainer.iconUrl) : undefined;
|
||||
cachedViewContainer.views = placeholderViewContainer.views;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this._cachedViewContainers;
|
||||
}
|
||||
|
||||
@@ -933,10 +965,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
visible,
|
||||
order
|
||||
})));
|
||||
|
||||
this.setPlaceholderViewContainers(cachedViewContainers.map(({ id, icon, name, views }) => (<IPlaceholderViewContainer>{
|
||||
id,
|
||||
iconUrl: URI.isUri(icon) ? icon : undefined,
|
||||
iconCSS: isString(icon) ? icon : undefined,
|
||||
themeIcon: ThemeIcon.isThemeIcon(icon) ? icon : undefined,
|
||||
name,
|
||||
views
|
||||
})));
|
||||
@@ -971,7 +1004,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
|
||||
private setStoredPinnedViewContainersValue(value: string): void {
|
||||
this.storageService.store(ActivitybarPart.PINNED_VIEW_CONTAINERS, value, StorageScope.GLOBAL);
|
||||
this.storageService.store(ActivitybarPart.PINNED_VIEW_CONTAINERS, value, StorageScope.GLOBAL, StorageTarget.USER);
|
||||
}
|
||||
|
||||
private getPlaceholderViewContainers(): IPlaceholderViewContainer[] {
|
||||
@@ -1003,37 +1036,23 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
|
||||
private setStoredPlaceholderViewContainersValue(value: string): void {
|
||||
this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.GLOBAL);
|
||||
this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
}
|
||||
|
||||
private get homeBarVisibilityPreference(): boolean {
|
||||
return this.storageService.getBoolean(ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, StorageScope.GLOBAL, true);
|
||||
return this.storageService.getBoolean(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, StorageScope.GLOBAL, true);
|
||||
}
|
||||
|
||||
private set homeBarVisibilityPreference(value: boolean) {
|
||||
this.storageService.store(ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, value, StorageScope.GLOBAL);
|
||||
this.storageService.store(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, value, StorageScope.GLOBAL, StorageTarget.USER);
|
||||
}
|
||||
|
||||
private get accountsVisibilityPreference(): boolean {
|
||||
return this.storageService.getBoolean(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.GLOBAL, true);
|
||||
return this.storageService.getBoolean(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.GLOBAL, true);
|
||||
}
|
||||
|
||||
private set accountsVisibilityPreference(value: boolean) {
|
||||
this.storageService.store(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, value, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
private migrateFromOldCachedViewContainersValue(): void {
|
||||
const value = this.storageService.get('workbench.activity.pinnedViewlets', StorageScope.GLOBAL);
|
||||
if (value !== undefined) {
|
||||
const storedStates: Array<string | ICachedViewContainer> = JSON.parse(value);
|
||||
const cachedViewContainers = storedStates.map(c => {
|
||||
const serialized: ICachedViewContainer = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, name: undefined, icon: undefined, views: undefined } : c;
|
||||
serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible;
|
||||
return serialized;
|
||||
});
|
||||
this.storeCachedViewContainersState(cachedViewContainers);
|
||||
this.storageService.remove('workbench.activity.pinnedViewlets', StorageScope.GLOBAL);
|
||||
}
|
||||
this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, value, StorageScope.GLOBAL, StorageTarget.USER);
|
||||
}
|
||||
|
||||
toJSON(): object {
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content > .home-bar > .monaco-action-bar .action-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content .composite-bar > .monaco-action-bar .action-item::before,
|
||||
.monaco-workbench .activitybar > .content .composite-bar > .monaco-action-bar .action-item::after {
|
||||
position: absolute;
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
<<<<<<< HEAD
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -59,6 +60,8 @@
|
||||
/* NOTE@coder: Hide since it doesn't seem to do anything when used with
|
||||
code-server except open the VS Code repository. */
|
||||
display: none !important;
|
||||
=======
|
||||
>>>>>>> e4a830e9b7ca039c7c70697786d29f5b6679d775
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content > .home-bar > .home-bar-icon-badge {
|
||||
@@ -92,10 +95,6 @@
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content > .composite-bar-excess {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Menu Bar */
|
||||
|
||||
.monaco-workbench .activitybar .menubar {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Composite, CompositeRegistry } from 'vs/workbench/browser/composite';
|
||||
import { IComposite } from 'vs/workbench/common/composite';
|
||||
import { CompositeProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
@@ -199,7 +199,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
// Store in preferences
|
||||
const id = this.activeComposite.getId();
|
||||
if (id !== this.defaultCompositeId) {
|
||||
this.storageService.store(this.activeCompositeSettingsKey, id, StorageScope.WORKSPACE);
|
||||
this.storageService.store(this.activeCompositeSettingsKey, id, StorageScope.WORKSPACE, StorageTarget.USER);
|
||||
} else {
|
||||
this.storageService.remove(this.activeCompositeSettingsKey, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IDialogHandler, IDialogResult, IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { IDialogsModel, IDialogViewItem } from 'vs/workbench/common/dialogs';
|
||||
import { BrowserDialogHandler } from 'vs/workbench/browser/parts/dialogs/dialogHandler';
|
||||
import { DialogService } from 'vs/workbench/services/dialogs/common/dialogService';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export class DialogHandlerContribution extends Disposable implements IWorkbenchContribution {
|
||||
private impl: IDialogHandler;
|
||||
|
||||
private model: IDialogsModel;
|
||||
private currentDialog: IDialogViewItem | undefined;
|
||||
|
||||
constructor(
|
||||
@IDialogService private dialogService: IDialogService,
|
||||
@ILogService logService: ILogService,
|
||||
@ILayoutService layoutService: ILayoutService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IProductService productService: IProductService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.impl = new BrowserDialogHandler(logService, layoutService, themeService, keybindingService, productService, clipboardService);
|
||||
|
||||
this.model = (this.dialogService as DialogService).model;
|
||||
|
||||
this._register(this.model.onDidShowDialog(() => {
|
||||
if (!this.currentDialog) {
|
||||
this.processDialogs();
|
||||
}
|
||||
}));
|
||||
|
||||
this.processDialogs();
|
||||
}
|
||||
|
||||
private async processDialogs(): Promise<void> {
|
||||
while (this.model.dialogs.length) {
|
||||
this.currentDialog = this.model.dialogs[0];
|
||||
|
||||
let result: IDialogResult | undefined = undefined;
|
||||
if (this.currentDialog.args.confirmArgs) {
|
||||
const args = this.currentDialog.args.confirmArgs;
|
||||
result = await this.impl.confirm(args.confirmation);
|
||||
} else if (this.currentDialog.args.inputArgs) {
|
||||
const args = this.currentDialog.args.inputArgs;
|
||||
result = await this.impl.input(args.severity, args.message, args.buttons, args.inputs, args.options);
|
||||
} else if (this.currentDialog.args.showArgs) {
|
||||
const args = this.currentDialog.args.showArgs;
|
||||
result = await this.impl.show(args.severity, args.message, args.buttons, args.options);
|
||||
} else {
|
||||
await this.impl.about();
|
||||
}
|
||||
|
||||
this.currentDialog.close(result);
|
||||
this.currentDialog = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchRegistry.registerWorkbenchContribution(DialogHandlerContribution, LifecyclePhase.Starting);
|
||||
@@ -0,0 +1,144 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { IDialogOptions, IConfirmation, IConfirmationResult, DialogType, IShowResult, IInputResult, ICheckbox, IInput, IDialogHandler } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { Dialog, IDialogResult } from 'vs/base/browser/ui/dialog/dialog';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { EventHelper } from 'vs/base/browser/dom';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { fromNow } from 'vs/base/common/date';
|
||||
|
||||
export class BrowserDialogHandler implements IDialogHandler {
|
||||
|
||||
private static readonly ALLOWABLE_COMMANDS = [
|
||||
'copy',
|
||||
'cut',
|
||||
'editor.action.selectAll',
|
||||
'editor.action.clipboardCopyAction',
|
||||
'editor.action.clipboardCutAction',
|
||||
'editor.action.clipboardPasteAction'
|
||||
];
|
||||
|
||||
constructor(
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@ILayoutService private readonly layoutService: ILayoutService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IClipboardService private readonly clipboardService: IClipboardService
|
||||
) { }
|
||||
|
||||
async confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
|
||||
this.logService.trace('DialogService#confirm', confirmation.message);
|
||||
|
||||
const buttons: string[] = [];
|
||||
if (confirmation.primaryButton) {
|
||||
buttons.push(confirmation.primaryButton);
|
||||
} else {
|
||||
buttons.push(nls.localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes"));
|
||||
}
|
||||
|
||||
if (confirmation.secondaryButton) {
|
||||
buttons.push(confirmation.secondaryButton);
|
||||
} else if (typeof confirmation.secondaryButton === 'undefined') {
|
||||
buttons.push(nls.localize('cancelButton', "Cancel"));
|
||||
}
|
||||
|
||||
const result = await this.doShow(confirmation.type, confirmation.message, buttons, confirmation.detail, 1, confirmation.checkbox);
|
||||
|
||||
return { confirmed: result.button === 0, checkboxChecked: result.checkboxChecked };
|
||||
}
|
||||
|
||||
private getDialogType(severity: Severity): DialogType {
|
||||
return (severity === Severity.Info) ? 'question' : (severity === Severity.Error) ? 'error' : (severity === Severity.Warning) ? 'warning' : 'none';
|
||||
}
|
||||
|
||||
async show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise<IShowResult> {
|
||||
this.logService.trace('DialogService#show', message);
|
||||
|
||||
const result = await this.doShow(this.getDialogType(severity), message, buttons, options?.detail, options?.cancelId, options?.checkbox);
|
||||
|
||||
return {
|
||||
choice: result.button,
|
||||
checkboxChecked: result.checkboxChecked
|
||||
};
|
||||
}
|
||||
|
||||
private async doShow(type: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending' | undefined, message: string, buttons: string[], detail?: string, cancelId?: number, checkbox?: ICheckbox, inputs?: IInput[]): Promise<IDialogResult> {
|
||||
const dialogDisposables = new DisposableStore();
|
||||
const dialog = new Dialog(
|
||||
this.layoutService.container,
|
||||
message,
|
||||
buttons,
|
||||
{
|
||||
detail,
|
||||
cancelId,
|
||||
type,
|
||||
keyEventProcessor: (event: StandardKeyboardEvent) => {
|
||||
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
|
||||
if (resolved && resolved.commandId) {
|
||||
if (BrowserDialogHandler.ALLOWABLE_COMMANDS.indexOf(resolved.commandId) === -1) {
|
||||
EventHelper.stop(event, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
checkboxLabel: checkbox?.label,
|
||||
checkboxChecked: checkbox?.checked,
|
||||
inputs
|
||||
});
|
||||
|
||||
dialogDisposables.add(dialog);
|
||||
dialogDisposables.add(attachDialogStyler(dialog, this.themeService));
|
||||
|
||||
const result = await dialog.show();
|
||||
dialogDisposables.dispose();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async input(severity: Severity, message: string, buttons: string[], inputs: IInput[], options?: IDialogOptions): Promise<IInputResult> {
|
||||
this.logService.trace('DialogService#input', message);
|
||||
|
||||
const result = await this.doShow(this.getDialogType(severity), message, buttons, options?.detail, options?.cancelId, options?.checkbox, inputs);
|
||||
|
||||
return {
|
||||
choice: result.button,
|
||||
checkboxChecked: result.checkboxChecked,
|
||||
values: result.values
|
||||
};
|
||||
}
|
||||
|
||||
async about(): Promise<void> {
|
||||
const detailString = (useAgo: boolean): string => {
|
||||
return nls.localize('aboutDetail',
|
||||
"code-server: v{4}\n VS Code: v{0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
|
||||
this.productService.version || 'Unknown',
|
||||
this.productService.commit || 'Unknown',
|
||||
this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown',
|
||||
navigator.userAgent,
|
||||
this.productService.codeServerVersion || 'Unknown',
|
||||
);
|
||||
};
|
||||
|
||||
const detail = detailString(true);
|
||||
const detailToCopy = detailString(false);
|
||||
|
||||
|
||||
const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail, cancelId: 1 });
|
||||
|
||||
if (choice === 0) {
|
||||
this.clipboardService.writeText(detailToCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import { dispose, IDisposable, Disposable, DisposableStore } from 'vs/base/commo
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { assertIsDefined, assertAllDefined } from 'vs/base/common/types';
|
||||
import { BinarySize } from 'vs/platform/files/common/files';
|
||||
import { ByteSize } from 'vs/platform/files/common/files';
|
||||
|
||||
export interface IOpenCallbacks {
|
||||
openInternal: (input: EditorInput, options: EditorOptions | undefined) => Promise<void>;
|
||||
@@ -182,7 +182,7 @@ interface ResourceViewerDelegate {
|
||||
|
||||
class ResourceViewer {
|
||||
|
||||
private static readonly MAX_OPEN_INTERNAL_SIZE = BinarySize.MB * 200; // max size until we offer an action to open internally
|
||||
private static readonly MAX_OPEN_INTERNAL_SIZE = ByteSize.MB * 200; // max size until we offer an action to open internally
|
||||
|
||||
static show(
|
||||
descriptor: IResourceDescriptor,
|
||||
@@ -211,7 +211,7 @@ class FileTooLargeFileView {
|
||||
scrollbar: DomScrollableElement,
|
||||
delegate: ResourceViewerDelegate
|
||||
) {
|
||||
const size = BinarySize.formatSize(descriptorSize);
|
||||
const size = ByteSize.formatSize(descriptorSize);
|
||||
delegate.metadataClb(size);
|
||||
|
||||
clearNode(container);
|
||||
@@ -233,7 +233,7 @@ class FileSeemsBinaryFileView {
|
||||
scrollbar: DomScrollableElement,
|
||||
delegate: ResourceViewerDelegate
|
||||
) {
|
||||
delegate.metadataClb(typeof descriptor.size === 'number' ? BinarySize.formatSize(descriptor.size) : '');
|
||||
delegate.metadataClb(typeof descriptor.size === 'number' ? ByteSize.formatSize(descriptor.size) : '');
|
||||
|
||||
clearNode(container);
|
||||
|
||||
|
||||
@@ -491,7 +491,7 @@ export class BreadcrumbsControl {
|
||||
if (element instanceof FileElement) {
|
||||
if (element.kind === FileKind.FILE) {
|
||||
// open file in any editor
|
||||
this._editorService.openEditor({ resource: element.uri, options: { pinned: pinned } }, group);
|
||||
this._editorService.openEditor({ resource: element.uri, options: { pinned } }, group);
|
||||
} else {
|
||||
// show next picker
|
||||
let items = this._widget.getItems();
|
||||
@@ -508,7 +508,8 @@ export class BreadcrumbsControl {
|
||||
resource: model.uri,
|
||||
options: {
|
||||
selection: Range.collapseToStart(element.symbol.selectionRange),
|
||||
selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport
|
||||
selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport,
|
||||
pinned
|
||||
}
|
||||
}, withUndefinedAsNull(this._getActiveCodeEditor()), group === SIDE_GROUP);
|
||||
}
|
||||
@@ -753,13 +754,14 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
// open symbol in editor
|
||||
return editors.openEditor({
|
||||
resource: outlineElement.uri,
|
||||
options: { selection: Range.collapseToStart(element.symbol.selectionRange) }
|
||||
options: { selection: Range.collapseToStart(element.symbol.selectionRange), pinned: true }
|
||||
}, SIDE_GROUP);
|
||||
|
||||
} else if (element && URI.isUri(element.resource)) {
|
||||
// open file in editor
|
||||
return editors.openEditor({
|
||||
resource: element.resource,
|
||||
options: { pinned: true }
|
||||
}, SIDE_GROUP);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -99,7 +99,7 @@ export abstract class BreadcrumbsPicker {
|
||||
this._treeContainer = document.createElement('div');
|
||||
this._treeContainer.style.background = color ? color.toString() : '';
|
||||
this._treeContainer.style.paddingTop = '2px';
|
||||
this._treeContainer.style.boxShadow = `0px 5px 8px ${this._themeService.getColorTheme().getColor(widgetShadow)}`;
|
||||
this._treeContainer.style.boxShadow = `0 0 8px 2px ${this._themeService.getColorTheme().getColor(widgetShadow)}`;
|
||||
this._domNode.appendChild(this._treeContainer);
|
||||
|
||||
this._layoutInfo = { maxHeight, width, arrowSize, arrowOffset, inputHeight: 0 };
|
||||
@@ -436,7 +436,6 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker {
|
||||
}
|
||||
|
||||
protected _getTargetFromEvent(element: any): any | undefined {
|
||||
// todo@joh
|
||||
if (element && !IWorkspaceFolder.isIWorkspaceFolder(element) && !(element as IFileStat).isDirectory) {
|
||||
return new FileElement((element as IFileStat).resource, FileKind.FILE);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/pl
|
||||
import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess, AllEditorsByAppearanceQuickAccess, AllEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess';
|
||||
import { IPathService } from 'vs/workbench/services/path/common/pathService';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
|
||||
// Register String Editor
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
@@ -238,27 +240,27 @@ export abstract class AbstractSideBySideEditorInputFactory implements IEditorInp
|
||||
const secondaryInput = secondaryInputFactory.deserialize(instantiationService, deserialized.secondarySerialized);
|
||||
|
||||
if (primaryInput && secondaryInput) {
|
||||
return this.createEditorInput(deserialized.name, deserialized.description, secondaryInput, primaryInput);
|
||||
return this.createEditorInput(instantiationService, deserialized.name, deserialized.description, secondaryInput, primaryInput);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected abstract createEditorInput(name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput;
|
||||
protected abstract createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput;
|
||||
}
|
||||
|
||||
class SideBySideEditorInputFactory extends AbstractSideBySideEditorInputFactory {
|
||||
|
||||
protected createEditorInput(name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
return new SideBySideEditorInput(name, description, secondaryInput, primaryInput);
|
||||
}
|
||||
}
|
||||
|
||||
class DiffEditorInputFactory extends AbstractSideBySideEditorInputFactory {
|
||||
|
||||
protected createEditorInput(name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
return new DiffEditorInput(name, description, secondaryInput, primaryInput);
|
||||
protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
return instantiationService.createInstance(DiffEditorInput, name, description, secondaryInput, primaryInput, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,6 +464,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.SHOW_EDITORS_IN_GROUP, title: nls.localize('showOpenedEditors', "Show Opened Editors") }, group: '3_open', order: 10 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '5_close', order: 10 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.TOGGLE_KEEP_EDITORS_COMMAND_ID, title: nls.localize('toggleKeepEditors', "Keep Editors Open"), toggled: ContextKeyExpr.not('config.workbench.editor.enablePreview') }, group: '7_settings', order: 10 });
|
||||
|
||||
interface IEditorToolItem { id: string; title: string; icon?: { dark?: URI; light?: URI; } | ThemeIcon; }
|
||||
|
||||
@@ -494,14 +497,14 @@ appendEditorToolItem(
|
||||
{
|
||||
id: SplitEditorAction.ID,
|
||||
title: nls.localize('splitEditorRight', "Split Editor Right"),
|
||||
icon: { id: 'codicon/split-horizontal' }
|
||||
icon: Codicon.splitHorizontal
|
||||
},
|
||||
ContextKeyExpr.not('splitEditorsVertically'),
|
||||
100000, // towards the end
|
||||
{
|
||||
id: editorCommands.SPLIT_EDITOR_DOWN,
|
||||
title: nls.localize('splitEditorDown', "Split Editor Down"),
|
||||
icon: { id: 'codicon/split-vertical' }
|
||||
icon: Codicon.splitVertical
|
||||
}
|
||||
);
|
||||
|
||||
@@ -509,14 +512,14 @@ appendEditorToolItem(
|
||||
{
|
||||
id: SplitEditorAction.ID,
|
||||
title: nls.localize('splitEditorDown', "Split Editor Down"),
|
||||
icon: { id: 'codicon/split-vertical' }
|
||||
icon: Codicon.splitVertical
|
||||
},
|
||||
ContextKeyExpr.has('splitEditorsVertically'),
|
||||
100000, // towards the end
|
||||
{
|
||||
id: editorCommands.SPLIT_EDITOR_RIGHT,
|
||||
title: nls.localize('splitEditorRight', "Split Editor Right"),
|
||||
icon: { id: 'codicon/split-horizontal' }
|
||||
icon: Codicon.splitHorizontal
|
||||
}
|
||||
);
|
||||
|
||||
@@ -525,14 +528,14 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
|
||||
title: nls.localize('close', "Close"),
|
||||
icon: { id: 'codicon/close' }
|
||||
icon: Codicon.close
|
||||
},
|
||||
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext.toNegated(), ActiveEditorStickyContext.toNegated()),
|
||||
1000000, // towards the far end
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
|
||||
title: nls.localize('closeAll', "Close All"),
|
||||
icon: { id: 'codicon/close-all' }
|
||||
icon: Codicon.closeAll
|
||||
}
|
||||
);
|
||||
|
||||
@@ -541,14 +544,14 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
|
||||
title: nls.localize('close', "Close"),
|
||||
icon: { id: 'codicon/close-dirty' }
|
||||
icon: Codicon.closeDirty
|
||||
},
|
||||
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext, ActiveEditorStickyContext.toNegated()),
|
||||
1000000, // towards the far end
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
|
||||
title: nls.localize('closeAll', "Close All"),
|
||||
icon: { id: 'codicon/close-all' }
|
||||
icon: Codicon.closeAll
|
||||
}
|
||||
);
|
||||
|
||||
@@ -557,14 +560,14 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.UNPIN_EDITOR_COMMAND_ID,
|
||||
title: nls.localize('unpin', "Unpin"),
|
||||
icon: { id: 'codicon/pinned' }
|
||||
icon: Codicon.pinned
|
||||
},
|
||||
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext.toNegated(), ActiveEditorStickyContext),
|
||||
1000000, // towards the far end
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
|
||||
title: nls.localize('close', "Close"),
|
||||
icon: { id: 'codicon/close' }
|
||||
icon: Codicon.close
|
||||
}
|
||||
);
|
||||
|
||||
@@ -573,23 +576,28 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.UNPIN_EDITOR_COMMAND_ID,
|
||||
title: nls.localize('unpin', "Unpin"),
|
||||
icon: { id: 'codicon/pinned-dirty' }
|
||||
icon: Codicon.pinnedDirty
|
||||
},
|
||||
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext, ActiveEditorStickyContext),
|
||||
1000000, // towards the far end
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
|
||||
title: nls.localize('close', "Close"),
|
||||
icon: { id: 'codicon/close' }
|
||||
icon: Codicon.close
|
||||
}
|
||||
);
|
||||
|
||||
const previousChangeIcon = registerIcon('diff-editor-previous-change', Codicon.arrowUp, nls.localize('previousChangeIcon', 'Icon for the previous change action in the diff editor.'));
|
||||
const nextChangeIcon = registerIcon('diff-editor-next-change', Codicon.arrowDown, nls.localize('nextChangeIcon', 'Icon for the next change action in the diff editor.'));
|
||||
const toggleWhitespace = registerIcon('diff-editor-toggle-whitespace', Codicon.whitespace, nls.localize('toggleWhitespace', 'Icon for the toggle whitespace action in the diff editor.'));
|
||||
|
||||
|
||||
// Diff Editor Title Menu: Previous Change
|
||||
appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.GOTO_PREVIOUS_CHANGE,
|
||||
title: nls.localize('navigate.prev.label', "Previous Change"),
|
||||
icon: { id: 'codicon/arrow-up' }
|
||||
icon: previousChangeIcon
|
||||
},
|
||||
TextCompareEditorActiveContext,
|
||||
10
|
||||
@@ -600,7 +608,7 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.GOTO_NEXT_CHANGE,
|
||||
title: nls.localize('navigate.next.label', "Next Change"),
|
||||
icon: { id: 'codicon/arrow-down' }
|
||||
icon: nextChangeIcon
|
||||
},
|
||||
TextCompareEditorActiveContext,
|
||||
11
|
||||
@@ -611,7 +619,7 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
|
||||
title: nls.localize('ignoreTrimWhitespace.label', "Ignore Leading/Trailing Whitespace Differences"),
|
||||
icon: { id: 'codicon/whitespace' }
|
||||
icon: toggleWhitespace
|
||||
},
|
||||
ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', true)),
|
||||
20
|
||||
@@ -622,7 +630,7 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
|
||||
title: nls.localize('showTrimWhitespace.label', "Show Leading/Trailing Whitespace Differences"),
|
||||
icon: { id: 'codicon/whitespace~disabled' }
|
||||
icon: ThemeIcon.modify(toggleWhitespace, 'disabled')
|
||||
},
|
||||
ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', false)),
|
||||
20
|
||||
|
||||
@@ -38,7 +38,8 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
|
||||
openSideBySideDirection: 'right',
|
||||
closeEmptyGroups: true,
|
||||
labelFormat: 'default',
|
||||
splitSizing: 'distribute'
|
||||
splitSizing: 'distribute',
|
||||
splitOnDragAndDrop: true
|
||||
};
|
||||
|
||||
export function impactsEditorPartOptions(event: IConfigurationChangeEvent): boolean {
|
||||
@@ -64,12 +65,12 @@ export interface IEditorOpeningEvent extends IEditorIdentifier {
|
||||
/**
|
||||
* The options used when opening the editor.
|
||||
*/
|
||||
options?: IEditorOptions;
|
||||
readonly options?: IEditorOptions;
|
||||
|
||||
/**
|
||||
* Context indicates how the editor open event is initialized.
|
||||
*/
|
||||
context?: OpenEditorContext;
|
||||
readonly context?: OpenEditorContext;
|
||||
|
||||
/**
|
||||
* Allows to prevent the opening of an editor by providing a callback
|
||||
|
||||
@@ -7,22 +7,26 @@ import * as nls from 'vs/nls';
|
||||
import { isObject, isString, isUndefined, isNumber, withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder } from 'vs/workbench/common/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder, viewColumnToEditorGroup, EditorGroupColumn } from 'vs/workbench/common/editor';
|
||||
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor';
|
||||
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IListService } from 'vs/platform/list/browser/listService';
|
||||
import { IListService, IOpenEvent } from 'vs/platform/list/browser/listService';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { distinct, coalesce } from 'vs/base/common/arrays';
|
||||
import { IEditorGroupsService, IEditorGroup, GroupDirection, GroupLocation, GroupsOrder, preferredSideBySideGroupDirection, EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith';
|
||||
|
||||
export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors';
|
||||
export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup';
|
||||
@@ -36,6 +40,7 @@ export const CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeOt
|
||||
export const MOVE_ACTIVE_EDITOR_COMMAND_ID = 'moveActiveEditor';
|
||||
export const LAYOUT_EDITOR_GROUPS_COMMAND_ID = 'layoutEditorGroups';
|
||||
export const KEEP_EDITOR_COMMAND_ID = 'workbench.action.keepEditor';
|
||||
export const TOGGLE_KEEP_EDITORS_COMMAND_ID = 'workbench.action.toggleKeepEditors';
|
||||
export const SHOW_EDITORS_IN_GROUP = 'workbench.action.showEditorsInGroup';
|
||||
|
||||
export const PIN_EDITOR_COMMAND_ID = 'workbench.action.pinEditor';
|
||||
@@ -44,6 +49,9 @@ export const UNPIN_EDITOR_COMMAND_ID = 'workbench.action.unpinEditor';
|
||||
export const TOGGLE_DIFF_SIDE_BY_SIDE = 'toggle.diff.renderSideBySide';
|
||||
export const GOTO_NEXT_CHANGE = 'workbench.action.compareEditor.nextChange';
|
||||
export const GOTO_PREVIOUS_CHANGE = 'workbench.action.compareEditor.previousChange';
|
||||
export const DIFF_FOCUS_PRIMARY_SIDE = 'workbench.action.compareEditor.focusPrimarySide';
|
||||
export const DIFF_FOCUS_SECONDARY_SIDE = 'workbench.action.compareEditor.focusSecondarySide';
|
||||
export const DIFF_FOCUS_OTHER_SIDE = 'workbench.action.compareEditor.focusOtherSide';
|
||||
export const TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE = 'toggle.diff.ignoreTrimWhitespace';
|
||||
|
||||
export const SPLIT_EDITOR_UP = 'workbench.action.splitEditorUp';
|
||||
@@ -58,6 +66,10 @@ export const FOCUS_BELOW_GROUP_WITHOUT_WRAP_COMMAND_ID = 'workbench.action.focus
|
||||
|
||||
export const OPEN_EDITOR_AT_INDEX_COMMAND_ID = 'workbench.action.openEditorAtIndex';
|
||||
|
||||
export const API_OPEN_EDITOR_COMMAND_ID = '_workbench.open';
|
||||
export const API_OPEN_DIFF_EDITOR_COMMAND_ID = '_workbench.diff';
|
||||
export const API_OPEN_WITH_EDITOR_COMMAND_ID = '_workbench.openWith';
|
||||
|
||||
export interface ActiveEditorMoveArguments {
|
||||
to: 'first' | 'last' | 'left' | 'right' | 'up' | 'down' | 'center' | 'position' | 'previous' | 'next';
|
||||
by: 'tab' | 'group';
|
||||
@@ -227,13 +239,45 @@ function moveActiveEditorToGroup(args: ActiveEditorMoveArguments, control: IVisi
|
||||
}
|
||||
|
||||
function registerEditorGroupsLayoutCommand(): void {
|
||||
CommandsRegistry.registerCommand(LAYOUT_EDITOR_GROUPS_COMMAND_ID, (accessor: ServicesAccessor, args: EditorGroupLayout) => {
|
||||
if (!args || typeof args !== 'object') {
|
||||
|
||||
function applyEditorLayout(accessor: ServicesAccessor, layout: EditorGroupLayout): void {
|
||||
if (!layout || typeof layout !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
const editorGroupService = accessor.get(IEditorGroupsService);
|
||||
editorGroupService.applyLayout(args);
|
||||
editorGroupService.applyLayout(layout);
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand(LAYOUT_EDITOR_GROUPS_COMMAND_ID, (accessor: ServicesAccessor, args: EditorGroupLayout) => {
|
||||
applyEditorLayout(accessor, args);
|
||||
});
|
||||
|
||||
// API Command
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'vscode.setEditorLayout',
|
||||
handler: (accessor: ServicesAccessor, args: EditorGroupLayout) => applyEditorLayout(accessor, args),
|
||||
description: {
|
||||
description: 'Set Editor Layout',
|
||||
args: [{
|
||||
name: 'args',
|
||||
schema: {
|
||||
'type': 'object',
|
||||
'required': ['groups'],
|
||||
'properties': {
|
||||
'orientation': {
|
||||
'type': 'number',
|
||||
'default': 0,
|
||||
'enum': [0, 1]
|
||||
},
|
||||
'groups': {
|
||||
'$ref': '#/definitions/editorGroupsSchema',
|
||||
'default': [{}, {}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -265,30 +309,68 @@ function registerDiffEditorCommands(): void {
|
||||
handler: accessor => navigateInDiffEditor(accessor, false)
|
||||
});
|
||||
|
||||
function navigateInDiffEditor(accessor: ServicesAccessor, next: boolean): void {
|
||||
function getActiveTextDiffEditor(accessor: ServicesAccessor): TextDiffEditor | undefined {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const candidates = [editorService.activeEditorPane, ...editorService.visibleEditorPanes].filter(editor => editor instanceof TextDiffEditor);
|
||||
|
||||
if (candidates.length > 0) {
|
||||
const navigator = (<TextDiffEditor>candidates[0]).getDiffNavigator();
|
||||
for (const editor of [editorService.activeEditorPane, ...editorService.visibleEditorPanes]) {
|
||||
if (editor instanceof TextDiffEditor) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function navigateInDiffEditor(accessor: ServicesAccessor, next: boolean): void {
|
||||
const activeTextDiffEditor = getActiveTextDiffEditor(accessor);
|
||||
|
||||
if (activeTextDiffEditor) {
|
||||
const navigator = activeTextDiffEditor.getDiffNavigator();
|
||||
if (navigator) {
|
||||
next ? navigator.next() : navigator.previous();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum FocusTextDiffEditorMode {
|
||||
Original,
|
||||
Modified,
|
||||
Toggle
|
||||
}
|
||||
|
||||
function focusInDiffEditor(accessor: ServicesAccessor, mode: FocusTextDiffEditorMode): void {
|
||||
const activeTextDiffEditor = getActiveTextDiffEditor(accessor);
|
||||
|
||||
if (activeTextDiffEditor) {
|
||||
switch (mode) {
|
||||
case FocusTextDiffEditorMode.Original:
|
||||
activeTextDiffEditor.getControl()?.getOriginalEditor().focus();
|
||||
break;
|
||||
case FocusTextDiffEditorMode.Modified:
|
||||
activeTextDiffEditor.getControl()?.getModifiedEditor().focus();
|
||||
break;
|
||||
case FocusTextDiffEditorMode.Toggle:
|
||||
if (activeTextDiffEditor.getControl()?.getModifiedEditor().hasWidgetFocus()) {
|
||||
return focusInDiffEditor(accessor, FocusTextDiffEditorMode.Original);
|
||||
} else {
|
||||
return focusInDiffEditor(accessor, FocusTextDiffEditorMode.Modified);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggleDiffSideBySide(accessor: ServicesAccessor): void {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
|
||||
const newValue = !configurationService.getValue<boolean>('diffEditor.renderSideBySide');
|
||||
configurationService.updateValue('diffEditor.renderSideBySide', newValue, ConfigurationTarget.USER);
|
||||
configurationService.updateValue('diffEditor.renderSideBySide', newValue);
|
||||
}
|
||||
|
||||
function toggleDiffIgnoreTrimWhitespace(accessor: ServicesAccessor): void {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
|
||||
const newValue = !configurationService.getValue<boolean>('diffEditor.ignoreTrimWhitespace');
|
||||
configurationService.updateValue('diffEditor.ignoreTrimWhitespace', newValue, ConfigurationTarget.USER);
|
||||
configurationService.updateValue('diffEditor.ignoreTrimWhitespace', newValue);
|
||||
}
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
@@ -299,6 +381,30 @@ function registerDiffEditorCommands(): void {
|
||||
handler: accessor => toggleDiffSideBySide(accessor)
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: DIFF_FOCUS_PRIMARY_SIDE,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: undefined,
|
||||
primary: undefined,
|
||||
handler: accessor => focusInDiffEditor(accessor, FocusTextDiffEditorMode.Modified)
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: DIFF_FOCUS_SECONDARY_SIDE,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: undefined,
|
||||
primary: undefined,
|
||||
handler: accessor => focusInDiffEditor(accessor, FocusTextDiffEditorMode.Original)
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: DIFF_FOCUS_OTHER_SIDE,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: undefined,
|
||||
primary: undefined,
|
||||
handler: accessor => focusInDiffEditor(accessor, FocusTextDiffEditorMode.Toggle)
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: TOGGLE_DIFF_SIDE_BY_SIDE,
|
||||
@@ -320,6 +426,88 @@ function registerDiffEditorCommands(): void {
|
||||
});
|
||||
}
|
||||
|
||||
function registerOpenEditorAPICommands(): void {
|
||||
|
||||
function mixinContext(context: IOpenEvent<unknown> | undefined, options: ITextEditorOptions | undefined, column: EditorGroupColumn | undefined): [ITextEditorOptions | undefined, EditorGroupColumn | undefined] {
|
||||
if (!context) {
|
||||
return [options, column];
|
||||
}
|
||||
|
||||
return [
|
||||
{ ...context.editorOptions, ...(options ?? Object.create(null)) },
|
||||
context.sideBySide ? SIDE_GROUP : column
|
||||
];
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand(API_OPEN_EDITOR_COMMAND_ID, async function (accessor: ServicesAccessor, resourceArg: UriComponents, columnAndOptions?: [EditorGroupColumn?, ITextEditorOptions?], label?: string, context?: IOpenEvent<unknown>) {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const editorGroupService = accessor.get(IEditorGroupsService);
|
||||
const openerService = accessor.get(IOpenerService);
|
||||
|
||||
const resource = URI.revive(resourceArg);
|
||||
const [columnArg, optionsArg] = columnAndOptions ?? [];
|
||||
|
||||
// use editor options or editor view column as a hint to use the editor service for opening
|
||||
if (optionsArg || typeof columnArg === 'number') {
|
||||
const [options, column] = mixinContext(context, optionsArg, columnArg);
|
||||
|
||||
await editorService.openEditor({ resource, options, label }, viewColumnToEditorGroup(editorGroupService, column));
|
||||
}
|
||||
|
||||
// do not allow to execute commands from here
|
||||
else if (resource.scheme === 'command') {
|
||||
return;
|
||||
}
|
||||
|
||||
// finally, delegate to opener service
|
||||
else {
|
||||
await openerService.open(resource, { openToSide: context?.sideBySide, editorOptions: context?.editorOptions });
|
||||
}
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand(API_OPEN_DIFF_EDITOR_COMMAND_ID, async function (accessor: ServicesAccessor, leftResource: UriComponents, rightResource: UriComponents, label?: string, columnAndOptions?: [EditorGroupColumn?, ITextEditorOptions?], context?: IOpenEvent<unknown>) {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const editorGroupService = accessor.get(IEditorGroupsService);
|
||||
|
||||
const [columnArg, optionsArg] = columnAndOptions ?? [];
|
||||
const [options, column] = mixinContext(context, optionsArg, columnArg);
|
||||
|
||||
await editorService.openEditor({
|
||||
leftResource: URI.revive(leftResource),
|
||||
rightResource: URI.revive(rightResource),
|
||||
label,
|
||||
options
|
||||
}, viewColumnToEditorGroup(editorGroupService, column));
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand(API_OPEN_WITH_EDITOR_COMMAND_ID, (accessor: ServicesAccessor, resource: UriComponents, id: string, columnAndOptions?: [EditorGroupColumn?, ITextEditorOptions?]) => {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const editorGroupsService = accessor.get(IEditorGroupsService);
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
|
||||
const [columnArg, optionsArg] = columnAndOptions ?? [];
|
||||
let group: IEditorGroup | undefined = undefined;
|
||||
|
||||
if (columnArg === SIDE_GROUP) {
|
||||
const direction = preferredSideBySideGroupDirection(configurationService);
|
||||
|
||||
let neighbourGroup = editorGroupsService.findGroup({ direction });
|
||||
if (!neighbourGroup) {
|
||||
neighbourGroup = editorGroupsService.addGroup(editorGroupsService.activeGroup, direction);
|
||||
}
|
||||
group = neighbourGroup;
|
||||
} else {
|
||||
group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, columnArg)) ?? editorGroupsService.activeGroup;
|
||||
}
|
||||
|
||||
const textOptions: ITextEditorOptions = optionsArg ? { ...optionsArg, override: false } : { override: false };
|
||||
|
||||
const input = editorService.createEditorInput({ resource: URI.revive(resource) });
|
||||
return openEditorWith(input, id, textOptions, group, editorService, configurationService, quickInputService);
|
||||
});
|
||||
}
|
||||
|
||||
function registerOpenEditorAtIndexCommands(): void {
|
||||
const openEditorAtIndex: ICommandHandler = (accessor: ServicesAccessor, editorIndex: number): void => {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
@@ -710,6 +898,31 @@ function registerOtherEditorCommands(): void {
|
||||
}
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: TOGGLE_KEEP_EDITORS_COMMAND_ID,
|
||||
handler: accessor => {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
const notificationService = accessor.get(INotificationService);
|
||||
const openerService = accessor.get(IOpenerService);
|
||||
|
||||
// Update setting
|
||||
const currentSetting = configurationService.getValue<boolean>('workbench.editor.enablePreview');
|
||||
const newSetting = currentSetting === true ? false : true;
|
||||
configurationService.updateValue('workbench.editor.enablePreview', newSetting);
|
||||
|
||||
// Inform user
|
||||
notificationService.prompt(
|
||||
Severity.Info,
|
||||
newSetting ?
|
||||
nls.localize('enablePreview', "Preview editors have been enabled in settings.") :
|
||||
nls.localize('disablePreview', "Preview editors have been disabled in settings."),
|
||||
[{
|
||||
label: nls.localize('learnMode', "Learn More"), run: () => openerService.open('https://go.microsoft.com/fwlink/?linkid=2147473')
|
||||
}]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: PIN_EDITOR_COMMAND_ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
@@ -877,6 +1090,7 @@ export function setup(): void {
|
||||
registerActiveEditorMoveCommand();
|
||||
registerEditorGroupsLayoutCommand();
|
||||
registerDiffEditorCommands();
|
||||
registerOpenEditorAPICommands();
|
||||
registerOpenEditorAtIndexCommands();
|
||||
registerCloseEditorCommands();
|
||||
registerOtherEditorCommands();
|
||||
|
||||
@@ -12,7 +12,7 @@ import { IThemeService, Themable } from 'vs/platform/theme/common/themeService';
|
||||
import { activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IEditorIdentifier, EditorInput, EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { isMacintosh, isWeb } from 'vs/base/common/platform';
|
||||
import { GroupDirection, MergeGroupMode, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { GroupDirection, IEditorGroupsService, MergeGroupMode, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
@@ -25,6 +25,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { assertIsDefined, assertAllDefined } from 'vs/base/common/types';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ByteSize } from 'vs/platform/files/common/files';
|
||||
|
||||
interface IDropOperation {
|
||||
splitDirection?: GroupDirection;
|
||||
@@ -34,7 +35,7 @@ class DropOverlay extends Themable {
|
||||
|
||||
private static readonly OVERLAY_ID = 'monaco-workbench-editor-drop-overlay';
|
||||
|
||||
private static readonly MAX_FILE_UPLOAD_SIZE = 100 * 1024 * 1024; // 100mb
|
||||
private static readonly MAX_FILE_UPLOAD_SIZE = 100 * ByteSize.MB;
|
||||
|
||||
private container: HTMLElement | undefined;
|
||||
private overlay: HTMLElement | undefined;
|
||||
@@ -54,7 +55,8 @@ class DropOverlay extends Themable {
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IFileDialogService private readonly fileDialogService: IFileDialogService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
|
||||
) {
|
||||
super(themeService);
|
||||
|
||||
@@ -143,8 +145,14 @@ class DropOverlay extends Themable {
|
||||
}
|
||||
}
|
||||
|
||||
// Position overlay
|
||||
this.positionOverlay(e.offsetX, e.offsetY, isDraggingGroup);
|
||||
// Position overlay and conditionally enable or disable
|
||||
// editor group splitting support based on setting and
|
||||
// keymodifiers used.
|
||||
let splitOnDragAndDrop = !!this.editorGroupService.partOptions.splitOnDragAndDrop;
|
||||
if (this.isToggleSplitOperation(e)) {
|
||||
splitOnDragAndDrop = !splitOnDragAndDrop;
|
||||
}
|
||||
this.positionOverlay(e.offsetX, e.offsetY, isDraggingGroup, splitOnDragAndDrop);
|
||||
|
||||
// Make sure to stop any running cleanup scheduler to remove the overlay
|
||||
if (this.cleanupOverlayScheduler.isScheduled()) {
|
||||
@@ -319,7 +327,7 @@ class DropOverlay extends Themable {
|
||||
// Try to come up with a good file path for the untitled
|
||||
// editor by asking the file dialog service for the default
|
||||
let proposedFilePath: URI | undefined = undefined;
|
||||
const defaultFilePath = this.fileDialogService.defaultFilePath();
|
||||
const defaultFilePath = await this.fileDialogService.defaultFilePath();
|
||||
if (defaultFilePath) {
|
||||
proposedFilePath = joinPath(defaultFilePath, name);
|
||||
}
|
||||
@@ -362,24 +370,33 @@ class DropOverlay extends Themable {
|
||||
return (e.ctrlKey && !isMacintosh) || (e.altKey && isMacintosh);
|
||||
}
|
||||
|
||||
private positionOverlay(mousePosX: number, mousePosY: number, isDraggingGroup: boolean): void {
|
||||
private isToggleSplitOperation(e: DragEvent): boolean {
|
||||
return (e.altKey && !isMacintosh) || (e.shiftKey && isMacintosh);
|
||||
}
|
||||
|
||||
private positionOverlay(mousePosX: number, mousePosY: number, isDraggingGroup: boolean, enableSplitting: boolean): void {
|
||||
const preferSplitVertically = this.accessor.partOptions.openSideBySideDirection === 'right';
|
||||
|
||||
const editorControlWidth = this.groupView.element.clientWidth;
|
||||
const editorControlHeight = this.groupView.element.clientHeight - this.getOverlayOffsetHeight();
|
||||
|
||||
let edgeWidthThresholdFactor: number;
|
||||
if (isDraggingGroup) {
|
||||
edgeWidthThresholdFactor = preferSplitVertically ? 0.3 : 0.1; // give larger threshold when dragging group depending on preferred split direction
|
||||
} else {
|
||||
edgeWidthThresholdFactor = 0.1; // 10% threshold to split if dragging editors
|
||||
}
|
||||
|
||||
let edgeHeightThresholdFactor: number;
|
||||
if (isDraggingGroup) {
|
||||
edgeHeightThresholdFactor = preferSplitVertically ? 0.1 : 0.3; // give larger threshold when dragging group depending on preferred split direction
|
||||
if (enableSplitting) {
|
||||
if (isDraggingGroup) {
|
||||
edgeWidthThresholdFactor = preferSplitVertically ? 0.3 : 0.1; // give larger threshold when dragging group depending on preferred split direction
|
||||
} else {
|
||||
edgeWidthThresholdFactor = 0.1; // 10% threshold to split if dragging editors
|
||||
}
|
||||
|
||||
if (isDraggingGroup) {
|
||||
edgeHeightThresholdFactor = preferSplitVertically ? 0.1 : 0.3; // give larger threshold when dragging group depending on preferred split direction
|
||||
} else {
|
||||
edgeHeightThresholdFactor = 0.1; // 10% threshold to split if dragging editors
|
||||
}
|
||||
} else {
|
||||
edgeHeightThresholdFactor = 0.1; // 10% threshold to split if dragging editors
|
||||
edgeWidthThresholdFactor = 0;
|
||||
edgeHeightThresholdFactor = 0;
|
||||
}
|
||||
|
||||
const edgeWidthThreshold = editorControlWidth * edgeWidthThresholdFactor;
|
||||
|
||||
@@ -1742,28 +1742,17 @@ class EditorOpeningEvent implements IEditorOpeningEvent {
|
||||
private override: (() => Promise<IEditorPane | undefined>) | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
private _group: GroupIdentifier,
|
||||
private _editor: EditorInput,
|
||||
public readonly groupId: GroupIdentifier,
|
||||
public readonly editor: EditorInput,
|
||||
private _options: EditorOptions | undefined,
|
||||
private _context: OpenEditorContext | undefined
|
||||
public readonly context: OpenEditorContext | undefined
|
||||
) {
|
||||
}
|
||||
|
||||
get groupId(): GroupIdentifier {
|
||||
return this._group;
|
||||
}
|
||||
|
||||
get editor(): EditorInput {
|
||||
return this._editor;
|
||||
}
|
||||
|
||||
get options(): EditorOptions | undefined {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
get context(): OpenEditorContext | undefined {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
prevent(callback: () => Promise<IEditorPane | undefined>): void {
|
||||
this.override = callback;
|
||||
@@ -1775,9 +1764,9 @@ class EditorOpeningEvent implements IEditorOpeningEvent {
|
||||
}
|
||||
|
||||
export interface EditorReplacement {
|
||||
editor: EditorInput;
|
||||
replacement: EditorInput;
|
||||
options?: EditorOptions;
|
||||
readonly editor: EditorInput;
|
||||
readonly replacement: EditorInput;
|
||||
readonly options?: EditorOptions;
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector, environment) => {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IEditorGroup, IEditorGroupsService, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { LRUCache, Touch } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
@@ -156,7 +156,7 @@ export abstract class EditorPane extends Composite implements IEditorPane {
|
||||
|
||||
let editorMemento = EditorPane.EDITOR_MEMENTOS.get(mementoKey);
|
||||
if (!editorMemento) {
|
||||
editorMemento = new EditorMemento(this.getId(), key, this.getMemento(StorageScope.WORKSPACE), limit, editorGroupService);
|
||||
editorMemento = new EditorMemento(this.getId(), key, this.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE), limit, editorGroupService);
|
||||
EditorPane.EDITOR_MEMENTOS.set(mementoKey, editorMemento);
|
||||
}
|
||||
|
||||
@@ -220,18 +220,7 @@ export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
|
||||
// Automatically clear when editor input gets disposed if any
|
||||
if (resourceOrEditor instanceof EditorInput) {
|
||||
const editor = resourceOrEditor;
|
||||
|
||||
if (!this.editorDisposables) {
|
||||
this.editorDisposables = new Map<EditorInput, IDisposable>();
|
||||
}
|
||||
|
||||
if (!this.editorDisposables.has(editor)) {
|
||||
this.editorDisposables.set(editor, Event.once(resourceOrEditor.onDispose)(() => {
|
||||
this.clearEditorState(resource);
|
||||
this.editorDisposables?.delete(editor);
|
||||
}));
|
||||
}
|
||||
this.clearEditorStateOnDispose(resource, resourceOrEditor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +229,7 @@ export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
loadEditorState(group: IEditorGroup, resourceOrEditor: URI | EditorInput, fallbackToOtherGroupState?: boolean): T | undefined {
|
||||
const resource = this.doGetResource(resourceOrEditor);
|
||||
if (!resource || !group) {
|
||||
return undefined; // we are not in a good state to load any state for a resource
|
||||
return; // we are not in a good state to load any state for a resource
|
||||
}
|
||||
|
||||
const cache = this.doLoad();
|
||||
@@ -261,12 +250,16 @@ export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
clearEditorState(resource: URI, group?: IEditorGroup): void;
|
||||
clearEditorState(editor: EditorInput, group?: IEditorGroup): void;
|
||||
clearEditorState(resourceOrEditor: URI | EditorInput, group?: IEditorGroup): void {
|
||||
if (resourceOrEditor instanceof EditorInput) {
|
||||
this.editorDisposables?.delete(resourceOrEditor);
|
||||
}
|
||||
|
||||
const resource = this.doGetResource(resourceOrEditor);
|
||||
if (resource) {
|
||||
const cache = this.doLoad();
|
||||
@@ -286,6 +279,19 @@ export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
}
|
||||
}
|
||||
|
||||
clearEditorStateOnDispose(resource: URI, editor: EditorInput): void {
|
||||
if (!this.editorDisposables) {
|
||||
this.editorDisposables = new Map<EditorInput, IDisposable>();
|
||||
}
|
||||
|
||||
if (!this.editorDisposables.has(editor)) {
|
||||
this.editorDisposables.set(editor, Event.once(editor.onDispose)(() => {
|
||||
this.clearEditorState(resource);
|
||||
this.editorDisposables?.delete(editor);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
moveEditorState(source: URI, target: URI, comparer: IExtUri): void {
|
||||
const cache = this.doLoad();
|
||||
|
||||
@@ -342,7 +348,7 @@ export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
saveState(): void {
|
||||
const cache = this.doLoad();
|
||||
|
||||
// Cleanup once during shutdown
|
||||
// Cleanup once during session
|
||||
if (!this.cleanedUp) {
|
||||
this.cleanUp();
|
||||
this.cleanedUp = true;
|
||||
|
||||
@@ -19,7 +19,7 @@ import { IEditorGroupsAccessor, IEditorGroupView, getEditorPartOptions, impactsE
|
||||
import { EditorGroupView } from 'vs/workbench/browser/parts/editor/editorGroupView';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup';
|
||||
import { EditorDropTarget, IEditorDropTargetDelegate } from 'vs/workbench/browser/parts/editor/editorDropTarget';
|
||||
import { IEditorDropService } from 'vs/workbench/services/editor/browser/editorDropService';
|
||||
@@ -148,8 +148,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
|
||||
this.gridWidgetView = new GridWidgetView<IEditorGroupView>();
|
||||
|
||||
this.workspaceMemento = this.getMemento(StorageScope.WORKSPACE);
|
||||
this.globalMemento = this.getMemento(StorageScope.GLOBAL);
|
||||
this.workspaceMemento = this.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE);
|
||||
this.globalMemento = this.getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
|
||||
this._whenRestored = new Promise(resolve => (this.whenRestoredResolve = resolve));
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./media/editorstatus';
|
||||
import * as nls from 'vs/nls';
|
||||
import { runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
|
||||
import { format, compare } from 'vs/base/common/strings';
|
||||
import { format, compare, splitLines } from 'vs/base/common/strings';
|
||||
import { extname, basename, isEqual } from 'vs/base/common/resources';
|
||||
import { areFunctions, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -346,12 +346,12 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
||||
[{
|
||||
label: nls.localize('screenReaderDetectedExplanation.answerYes', "Yes"),
|
||||
run: () => {
|
||||
this.configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER);
|
||||
this.configurationService.updateValue('editor.accessibilitySupport', 'on');
|
||||
}
|
||||
}, {
|
||||
label: nls.localize('screenReaderDetectedExplanation.answerNo', "No"),
|
||||
run: () => {
|
||||
this.configurationService.updateValue('editor.accessibilitySupport', 'off', ConfigurationTarget.USER);
|
||||
this.configurationService.updateValue('editor.accessibilitySupport', 'off');
|
||||
}
|
||||
}],
|
||||
{ sticky: true }
|
||||
@@ -918,7 +918,7 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable {
|
||||
this.currentMarker = this.getMarker();
|
||||
if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) {
|
||||
if (this.currentMarker) {
|
||||
const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0];
|
||||
const line = splitLines(this.currentMarker.message)[0];
|
||||
const text = `${this.getType(this.currentMarker)} ${line}`;
|
||||
if (!this.statusBarEntryAccessor.value) {
|
||||
this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text: '', ariaLabel: '' }, 'statusbar.currentProblem', nls.localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT);
|
||||
@@ -1046,12 +1046,19 @@ export class ChangeModeAction extends Action {
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(actionId, actionLabel);
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
const activeEditorPane = this.editorService.activeEditorPane as unknown as { isNotebookEditor?: boolean } | undefined;
|
||||
if (activeEditorPane?.isNotebookEditor) {
|
||||
// it's inside notebook editor
|
||||
return this.commandService.executeCommand('notebook.cell.changeLanguage');
|
||||
}
|
||||
|
||||
const activeTextEditorControl = getCodeEditor(this.editorService.activeTextEditorControl);
|
||||
if (!activeTextEditorControl) {
|
||||
await this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]);
|
||||
@@ -1143,7 +1150,7 @@ export class ChangeModeAction extends Action {
|
||||
|
||||
// User decided to configure settings for current language
|
||||
if (pick === configureModeSettings) {
|
||||
this.preferencesService.openGlobalSettings(true, { editSetting: `[${withUndefinedAsNull(currentModeId)}]` });
|
||||
this.preferencesService.openGlobalSettings(true, { revealSetting: { key: `[${withUndefinedAsNull(currentModeId)}]`, edit: true } });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget {
|
||||
super();
|
||||
|
||||
this._domNode = $('.floating-click-widget');
|
||||
this._domNode.style.padding = '10px';
|
||||
this._domNode.style.cursor = 'pointer';
|
||||
|
||||
if (keyBindingAction) {
|
||||
const keybinding = keybindingService.lookupKeybinding(keyBindingAction);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { IEditorInput, IEditorInputFactoryRegistry, IEditorIdentifier, GroupIdentifier, Extensions, IEditorPartOptionsChangeEvent, EditorsOrder, EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IEditorGroupsService, IEditorGroup, GroupChangeKind, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
@@ -339,7 +339,7 @@ export class EditorsObserver extends Disposable {
|
||||
if (this.mostRecentEditorsMap.isEmpty()) {
|
||||
this.storageService.remove(EditorsObserver.STORAGE_KEY, StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.store(EditorsObserver.STORAGE_KEY, JSON.stringify(this.serialize()), StorageScope.WORKSPACE);
|
||||
this.storageService.store(EditorsObserver.STORAGE_KEY, JSON.stringify(this.serialize()), StorageScope.WORKSPACE, StorageTarget.MACHINE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
/* todo@joh move somewhere else */
|
||||
/* breadcrumbs-picker-style */
|
||||
|
||||
.monaco-workbench .monaco-breadcrumbs-picker .arrow {
|
||||
position: absolute;
|
||||
|
||||
@@ -589,8 +589,8 @@ export class TabsTitleControl extends TitleControl {
|
||||
|
||||
const tabActionRunner = new EditorCommandsContextActionRunner({ groupId: this.group.id, editorIndex: index });
|
||||
|
||||
const tabActionBar = new ActionBar(tabActionsContainer, { ariaLabel: localize('ariaLabelTabActions', "Tab actions"), actionRunner: tabActionRunner, });
|
||||
tabActionBar.onDidBeforeRun(e => {
|
||||
const tabActionBar = new ActionBar(tabActionsContainer, { ariaLabel: localize('ariaLabelTabActions', "Tab actions"), actionRunner: tabActionRunner });
|
||||
tabActionBar.onBeforeRun(e => {
|
||||
if (e.action.id === this.closeEditorAction.id) {
|
||||
this.blockRevealActiveTabOnce();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import { ScrollType, IDiffEditorViewState, IDiffEditorModel } from 'vs/editor/co
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
@@ -32,6 +31,7 @@ import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/edit
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { multibyteAwareBtoa } from 'vs/base/browser/dom';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
/**
|
||||
* The text editor that leverages the diff text editor for the editing experience.
|
||||
@@ -62,9 +62,28 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
|
||||
@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IEditorGroupsService editorGroupService: IEditorGroupsService
|
||||
@IEditorGroupsService editorGroupService: IEditorGroupsService,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
) {
|
||||
super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorService, editorGroupService);
|
||||
|
||||
// Listen to file system provider changes
|
||||
this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onDidFileSystemProviderChange(e.scheme)));
|
||||
this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onDidFileSystemProviderChange(e.scheme)));
|
||||
}
|
||||
|
||||
private onDidFileSystemProviderChange(scheme: string): void {
|
||||
const control = this.getControl();
|
||||
const input = this.input;
|
||||
|
||||
if (control && input instanceof DiffEditorInput) {
|
||||
if (input.originalInput.resource?.scheme === scheme || input.modifiedInput.resource?.scheme === scheme) {
|
||||
control.updateOptions({
|
||||
readOnly: input.modifiedInput.isReadonly(),
|
||||
originalEditable: !input.originalInput.isReadonly()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected onWillCloseEditorInGroup(editor: IEditorInput): void {
|
||||
@@ -175,7 +194,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
|
||||
const originalInput = input.originalInput;
|
||||
const modifiedInput = input.modifiedInput;
|
||||
|
||||
const binaryDiffInput = new DiffEditorInput(input.getName(), input.getDescription(), originalInput, modifiedInput, true);
|
||||
const binaryDiffInput = this.instantiationService.createInstance(DiffEditorInput, input.getName(), input.getDescription(), originalInput, modifiedInput, true);
|
||||
|
||||
// Forward binary flag to input if supported
|
||||
const fileEditorInputFactory = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).getFileEditorInputFactory();
|
||||
@@ -217,16 +236,17 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
|
||||
|
||||
// Handle diff editor specially by merging in diffEditor configuration
|
||||
if (isObject(configuration.diffEditor)) {
|
||||
// User settings defines `diffEditor.codeLens`, but there is also `editor.codeLens`.
|
||||
// Due to the mixin, the two settings cannot be distinguished anymore.
|
||||
//
|
||||
// So we map `diffEditor.codeLens` to `diffEditor.originalCodeLens` and `diffEditor.modifiedCodeLens`.
|
||||
const diffEditorConfiguration = <IDiffEditorOptions>objects.deepClone(configuration.diffEditor);
|
||||
diffEditorConfiguration.originalCodeLens = diffEditorConfiguration.codeLens;
|
||||
diffEditorConfiguration.modifiedCodeLens = diffEditorConfiguration.codeLens;
|
||||
|
||||
// User settings defines `diffEditor.codeLens`, but here we rename that to `diffEditor.diffCodeLens` to avoid collisions with `editor.codeLens`.
|
||||
diffEditorConfiguration.diffCodeLens = diffEditorConfiguration.codeLens;
|
||||
delete diffEditorConfiguration.codeLens;
|
||||
|
||||
objects.mixin(editorConfiguration, diffEditorConfiguration);
|
||||
// User settings defines `diffEditor.wordWrap`, but here we rename that to `diffEditor.diffWordWrap` to avoid collisions with `editor.wordWrap`.
|
||||
diffEditorConfiguration.diffWordWrap = <'off' | 'on' | 'inherit' | undefined>diffEditorConfiguration.wordWrap;
|
||||
delete diffEditorConfiguration.wordWrap;
|
||||
|
||||
Object.assign(editorConfiguration, diffEditorConfiguration);
|
||||
}
|
||||
|
||||
return editorConfiguration;
|
||||
@@ -309,12 +329,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
|
||||
|
||||
// Otherwise save it
|
||||
else {
|
||||
super.saveTextEditorViewState(resource);
|
||||
|
||||
// Make sure to clean up when the input gets disposed
|
||||
Event.once(input.onDispose)(() => {
|
||||
super.clearTextEditorViewState([resource], this.group);
|
||||
});
|
||||
super.saveTextEditorViewState(resource, input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa
|
||||
@IEditorGroupsService protected editorGroupService: IEditorGroupsService
|
||||
) {
|
||||
super(id, telemetryService, themeService, storageService);
|
||||
|
||||
this._instantiationService = instantiationService;
|
||||
|
||||
this.editorMemento = this.getEditorMemento<IEditorViewState>(editorGroupService, BaseTextEditor.TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY, 100);
|
||||
@@ -223,13 +224,27 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa
|
||||
return this.editorControl;
|
||||
}
|
||||
|
||||
protected saveTextEditorViewState(resource: URI): void {
|
||||
getViewState(): IEditorViewState | undefined {
|
||||
const resource = this.input?.resource;
|
||||
if (resource) {
|
||||
return withNullAsUndefined(this.retrieveTextEditorViewState(resource));
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
protected saveTextEditorViewState(resource: URI, cleanUpOnDispose?: IEditorInput): void {
|
||||
const editorViewState = this.retrieveTextEditorViewState(resource);
|
||||
if (!editorViewState || !this.group) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.editorMemento.saveEditorState(this.group, resource, editorViewState);
|
||||
|
||||
if (cleanUpOnDispose) {
|
||||
this.editorMemento.clearEditorStateOnDispose(resource, cleanUpOnDispose);
|
||||
}
|
||||
}
|
||||
|
||||
protected shouldRestoreTextEditorViewState(editor: IEditorInput, context?: IEditorOpenContext): boolean {
|
||||
@@ -243,15 +258,6 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa
|
||||
return true;
|
||||
}
|
||||
|
||||
getViewState(): IEditorViewState | undefined {
|
||||
const resource = this.input?.resource;
|
||||
if (resource) {
|
||||
return withNullAsUndefined(this.retrieveTextEditorViewState(resource));
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected retrieveTextEditorViewState(resource: URI): IEditorViewState | null {
|
||||
const control = this.getControl();
|
||||
if (!isCodeEditor(control)) {
|
||||
@@ -284,9 +290,9 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa
|
||||
}
|
||||
|
||||
protected clearTextEditorViewState(resources: URI[], group?: IEditorGroup): void {
|
||||
resources.forEach(resource => {
|
||||
for (const resource of resources) {
|
||||
this.editorMemento.clearEditorState(resource, group);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private updateEditorConfiguration(configuration?: IEditorConfiguration): void {
|
||||
|
||||
@@ -16,7 +16,6 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ScrollType, IEditor } from 'vs/editor/common/editorCommon';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
@@ -158,12 +157,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
|
||||
|
||||
// Otherwise save it
|
||||
else {
|
||||
super.saveTextEditorViewState(resource);
|
||||
|
||||
// Make sure to clean up when the input gets disposed
|
||||
Event.once(input.onDispose)(() => {
|
||||
super.clearTextEditorViewState([resource]);
|
||||
});
|
||||
super.saveTextEditorViewState(resource, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,18 +105,27 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container > .monaco-button-dropdown,
|
||||
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container > .monaco-button {
|
||||
margin: 4px 5px; /* allows button focus outline to be visible */
|
||||
}
|
||||
|
||||
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container .monaco-button {
|
||||
outline-offset: 2px !important;
|
||||
}
|
||||
|
||||
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container .monaco-text-button {
|
||||
width: fit-content;
|
||||
width: -moz-fit-content;
|
||||
padding: 5px 10px;
|
||||
margin: 4px 5px; /* allows button focus outline to be visible */
|
||||
display: inline-block; /* to enable ellipsis in text overflow */
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container .monaco-text-button {
|
||||
display: inline-block; /* to enable ellipsis in text overflow */
|
||||
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container .monaco-dropdown-button {
|
||||
padding: 5px
|
||||
}
|
||||
|
||||
/** Notification: Progress */
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
}
|
||||
|
||||
.monaco-workbench > .notifications-toasts .notification-toast-container > .notification-toast {
|
||||
margin: 5px; /* enables separation and drop shadows around toasts */
|
||||
margin: 8px; /* enables separation and drop shadows around toasts */
|
||||
transform: translate3d(0px, 100%, 0px); /* move the notification 50px to the bottom (to prevent bleed through) */
|
||||
opacity: 0; /* fade the toast in */
|
||||
transition: transform 300ms ease-out, opacity 300ms ease-out;
|
||||
|
||||
@@ -12,14 +12,16 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
||||
import { CLEAR_NOTIFICATION, EXPAND_NOTIFICATION, COLLAPSE_NOTIFICATION, CLEAR_ALL_NOTIFICATIONS, HIDE_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
const clearIcon = registerIcon('notifications-clear', Codicon.close);
|
||||
const clearAllIcon = registerIcon('notifications-clear-all', Codicon.clearAll);
|
||||
const hideIcon = registerIcon('notifications-hide', Codicon.chevronDown);
|
||||
const expandIcon = registerIcon('notifications-expand', Codicon.chevronUp);
|
||||
const collapseIcon = registerIcon('notifications-collapse', Codicon.chevronDown);
|
||||
const configureIcon = registerIcon('notifications-configure', Codicon.gear);
|
||||
const clearIcon = registerIcon('notifications-clear', Codicon.close, localize('clearIcon', 'Icon for the clear action in notifications.'));
|
||||
const clearAllIcon = registerIcon('notifications-clear-all', Codicon.clearAll, localize('clearAllIcon', 'Icon for the clear all action in notifications.'));
|
||||
const hideIcon = registerIcon('notifications-hide', Codicon.chevronDown, localize('hideIcon', 'Icon for the hide action in notifications.'));
|
||||
const expandIcon = registerIcon('notifications-expand', Codicon.chevronUp, localize('expandIcon', 'Icon for the expand action in notifications.'));
|
||||
const collapseIcon = registerIcon('notifications-collapse', Codicon.chevronDown, localize('collapseIcon', 'Icon for the collapse action in notifications.'));
|
||||
const configureIcon = registerIcon('notifications-configure', Codicon.gear, localize('configureIcon', 'Icon for the configure action in notifications.'));
|
||||
|
||||
export class ClearNotificationAction extends Action {
|
||||
|
||||
@@ -31,7 +33,7 @@ export class ClearNotificationAction extends Action {
|
||||
label: string,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(id, label, clearIcon.classNames);
|
||||
super(id, label, ThemeIcon.asClassName(clearIcon));
|
||||
}
|
||||
|
||||
async run(notification: INotificationViewItem): Promise<void> {
|
||||
@@ -49,7 +51,7 @@ export class ClearAllNotificationsAction extends Action {
|
||||
label: string,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(id, label, clearAllIcon.classNames);
|
||||
super(id, label, ThemeIcon.asClassName(clearAllIcon));
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
@@ -67,7 +69,7 @@ export class HideNotificationsCenterAction extends Action {
|
||||
label: string,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(id, label, hideIcon.classNames);
|
||||
super(id, label, ThemeIcon.asClassName(hideIcon));
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
@@ -85,7 +87,7 @@ export class ExpandNotificationAction extends Action {
|
||||
label: string,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(id, label, expandIcon.classNames);
|
||||
super(id, label, ThemeIcon.asClassName(expandIcon));
|
||||
}
|
||||
|
||||
async run(notification: INotificationViewItem): Promise<void> {
|
||||
@@ -103,7 +105,7 @@ export class CollapseNotificationAction extends Action {
|
||||
label: string,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(id, label, collapseIcon.classNames);
|
||||
super(id, label, ThemeIcon.asClassName(collapseIcon));
|
||||
}
|
||||
|
||||
async run(notification: INotificationViewItem): Promise<void> {
|
||||
@@ -121,7 +123,7 @@ export class ConfigureNotificationAction extends Action {
|
||||
label: string,
|
||||
public readonly configurationActions: ReadonlyArray<IAction>
|
||||
) {
|
||||
super(id, label, configureIcon.classNames);
|
||||
super(id, label, ThemeIcon.asClassName(configureIcon));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
|
||||
protected updateStyles(): void {
|
||||
if (this.notificationsCenterContainer && this.notificationsCenterHeader) {
|
||||
const widgetShadowColor = this.getColor(widgetShadow);
|
||||
this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : '';
|
||||
this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 0 8px 2px ${widgetShadowColor}` : '';
|
||||
|
||||
const borderColor = this.getColor(NOTIFICATIONS_CENTER_BORDER);
|
||||
this.notificationsCenterContainer.style.border = borderColor ? `1px solid ${borderColor}` : '';
|
||||
|
||||
@@ -15,20 +15,20 @@ import { IListService, WorkbenchList } from 'vs/platform/list/browser/listServic
|
||||
// Center
|
||||
export const SHOW_NOTIFICATIONS_CENTER = 'notifications.showList';
|
||||
export const HIDE_NOTIFICATIONS_CENTER = 'notifications.hideList';
|
||||
export const TOGGLE_NOTIFICATIONS_CENTER = 'notifications.toggleList';
|
||||
const TOGGLE_NOTIFICATIONS_CENTER = 'notifications.toggleList';
|
||||
|
||||
// Toasts
|
||||
export const HIDE_NOTIFICATION_TOAST = 'notifications.hideToasts';
|
||||
export const FOCUS_NOTIFICATION_TOAST = 'notifications.focusToasts';
|
||||
export const FOCUS_NEXT_NOTIFICATION_TOAST = 'notifications.focusNextToast';
|
||||
export const FOCUS_PREVIOUS_NOTIFICATION_TOAST = 'notifications.focusPreviousToast';
|
||||
export const FOCUS_FIRST_NOTIFICATION_TOAST = 'notifications.focusFirstToast';
|
||||
export const FOCUS_LAST_NOTIFICATION_TOAST = 'notifications.focusLastToast';
|
||||
const HIDE_NOTIFICATION_TOAST = 'notifications.hideToasts';
|
||||
const FOCUS_NOTIFICATION_TOAST = 'notifications.focusToasts';
|
||||
const FOCUS_NEXT_NOTIFICATION_TOAST = 'notifications.focusNextToast';
|
||||
const FOCUS_PREVIOUS_NOTIFICATION_TOAST = 'notifications.focusPreviousToast';
|
||||
const FOCUS_FIRST_NOTIFICATION_TOAST = 'notifications.focusFirstToast';
|
||||
const FOCUS_LAST_NOTIFICATION_TOAST = 'notifications.focusLastToast';
|
||||
|
||||
// Notification
|
||||
export const COLLAPSE_NOTIFICATION = 'notification.collapse';
|
||||
export const EXPAND_NOTIFICATION = 'notification.expand';
|
||||
export const TOGGLE_NOTIFICATION = 'notification.toggle';
|
||||
const TOGGLE_NOTIFICATION = 'notification.toggle';
|
||||
export const CLEAR_NOTIFICATION = 'notification.clear';
|
||||
export const CLEAR_ALL_NOTIFICATIONS = 'notifications.clearAll';
|
||||
|
||||
@@ -159,12 +159,20 @@ export function registerNotificationCommands(center: INotificationsCenterControl
|
||||
});
|
||||
|
||||
// Hide Toasts
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
CommandsRegistry.registerCommand(HIDE_NOTIFICATION_TOAST, accessor => toasts.hide());
|
||||
|
||||
KeybindingsRegistry.registerKeybindingRule({
|
||||
id: HIDE_NOTIFICATION_TOAST,
|
||||
weight: KeybindingWeight.WorkbenchContrib + 50,
|
||||
weight: KeybindingWeight.WorkbenchContrib - 50, // lower when not focused (e.g. let editor suggest win over this command)
|
||||
when: NotificationsToastsVisibleContext,
|
||||
primary: KeyCode.Escape,
|
||||
handler: accessor => toasts.hide()
|
||||
primary: KeyCode.Escape
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerKeybindingRule({
|
||||
id: HIDE_NOTIFICATION_TOAST,
|
||||
weight: KeybindingWeight.WorkbenchContrib + 100, // higher when focused
|
||||
when: ContextKeyExpr.and(NotificationsToastsVisibleContext, NotificationFocusedContext),
|
||||
primary: KeyCode.Escape
|
||||
});
|
||||
|
||||
// Focus Toasts
|
||||
|
||||
@@ -482,7 +482,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast
|
||||
toast.style.background = backgroundColor ? backgroundColor : '';
|
||||
|
||||
const widgetShadowColor = this.getColor(widgetShadow);
|
||||
toast.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : '';
|
||||
toast.style.boxShadow = widgetShadowColor ? `0 0 8px 2px ${widgetShadowColor}` : '';
|
||||
|
||||
const borderColor = this.getColor(NOTIFICATIONS_TOAST_BORDER);
|
||||
toast.style.border = borderColor ? `1px solid ${borderColor}` : '';
|
||||
|
||||
@@ -8,11 +8,11 @@ import { clearNode, addDisposableListener, EventType, EventHelper, $ } from 'vs/
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ButtonGroup } from 'vs/base/browser/ui/button/button';
|
||||
import { ButtonBar } from 'vs/base/browser/ui/button/button';
|
||||
import { attachButtonStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IAction, IActionRunner } from 'vs/base/common/actions';
|
||||
import { ActionRunner, ActionWithMenuAction, IAction, IActionRunner } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { dispose, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -285,7 +285,8 @@ export class NotificationTemplateRenderer extends Disposable {
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -441,27 +442,40 @@ export class NotificationTemplateRenderer extends Disposable {
|
||||
|
||||
const primaryActions = notification.actions ? notification.actions.primary : undefined;
|
||||
if (notification.expanded && isNonEmptyArray(primaryActions)) {
|
||||
const buttonGroup = new ButtonGroup(this.template.buttonsContainer, primaryActions.length, { title: true /* assign titles to buttons in case they overflow */ });
|
||||
buttonGroup.buttons.forEach((button, index) => {
|
||||
const action = primaryActions[index];
|
||||
button.label = action.label;
|
||||
|
||||
this.inputDisposables.add(button.onDidClick(e => {
|
||||
EventHelper.stop(e, true);
|
||||
|
||||
const that = this;
|
||||
const actionRunner: IActionRunner = new class extends ActionRunner {
|
||||
protected async runAction(action: IAction): Promise<void> {
|
||||
// Run action
|
||||
this.actionRunner.run(action, notification);
|
||||
that.actionRunner.run(action, notification);
|
||||
|
||||
// Hide notification (unless explicitly prevented)
|
||||
if (!(action instanceof ChoiceAction) || !action.keepOpen) {
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
}();
|
||||
const buttonToolbar = this.inputDisposables.add(new ButtonBar(this.template.buttonsContainer));
|
||||
for (const action of primaryActions) {
|
||||
const buttonOptions = { title: true, /* assign titles to buttons in case they overflow */ };
|
||||
const dropdownActions = action instanceof ChoiceAction ? action.menu
|
||||
: action instanceof ActionWithMenuAction ? action.actions : undefined;
|
||||
const button = this.inputDisposables.add(
|
||||
dropdownActions
|
||||
? buttonToolbar.addButtonWithDropdown({
|
||||
...buttonOptions,
|
||||
contextMenuProvider: this.contextMenuService,
|
||||
actions: dropdownActions,
|
||||
actionRunner
|
||||
})
|
||||
: buttonToolbar.addButton(buttonOptions));
|
||||
button.label = action.label;
|
||||
this.inputDisposables.add(button.onDidClick(e => {
|
||||
EventHelper.stop(e, true);
|
||||
actionRunner.run(action);
|
||||
}));
|
||||
|
||||
this.inputDisposables.add(attachButtonStyler(button, this.themeService));
|
||||
});
|
||||
|
||||
this.inputDisposables.add(buttonGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,10 +84,6 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.panel > .composite.title > .composite-bar-excess {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.panel > .composite.title> .panel-switcher-container > .monaco-action-bar {
|
||||
line-height: 27px; /* matches panel titles in settings */
|
||||
height: 35px;
|
||||
|
||||
@@ -18,11 +18,13 @@ import { IActivity } from 'vs/workbench/common/activity';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ActivePanelContext, PanelPositionContext } from 'vs/workbench/common/panel';
|
||||
import { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
const maximizeIcon = registerIcon('panel-maximize', Codicon.chevronUp);
|
||||
const restoreIcon = registerIcon('panel-restore', Codicon.chevronDown);
|
||||
const closeIcon = registerIcon('panel-close', Codicon.close);
|
||||
const maximizeIcon = registerIcon('panel-maximize', Codicon.chevronUp, nls.localize('maximizeIcon', 'Icon to maximize a panel.'));
|
||||
const restoreIcon = registerIcon('panel-restore', Codicon.chevronDown, nls.localize('restoreIcon', 'Icon to restore a panel.'));
|
||||
const closeIcon = registerIcon('panel-close', Codicon.close, nls.localize('closeIcon', 'Icon to close a panel.'));
|
||||
|
||||
export class ClosePanelAction extends Action {
|
||||
|
||||
@@ -34,7 +36,7 @@ export class ClosePanelAction extends Action {
|
||||
name: string,
|
||||
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
|
||||
) {
|
||||
super(id, name, closeIcon.classNames);
|
||||
super(id, name, ThemeIcon.asClassName(closeIcon));
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
@@ -106,11 +108,11 @@ export class ToggleMaximizedPanelAction extends Action {
|
||||
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
|
||||
@IEditorGroupsService editorGroupsService: IEditorGroupsService
|
||||
) {
|
||||
super(id, label, layoutService.isPanelMaximized() ? restoreIcon.classNames : maximizeIcon.classNames);
|
||||
super(id, label, layoutService.isPanelMaximized() ? ThemeIcon.asClassName(restoreIcon) : ThemeIcon.asClassName(maximizeIcon));
|
||||
|
||||
this.toDispose.add(editorGroupsService.onDidLayout(() => {
|
||||
const maximized = this.layoutService.isPanelMaximized();
|
||||
this.class = maximized ? restoreIcon.classNames : maximizeIcon.classNames;
|
||||
this.class = maximized ? ThemeIcon.asClassName(restoreIcon) : ThemeIcon.asClassName(maximizeIcon);
|
||||
this.label = maximized ? ToggleMaximizedPanelAction.RESTORE_LABEL : ToggleMaximizedPanelAction.MAXIMIZE_LABEL;
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { CompositePart, ICompositeTitleLabel } from 'vs/workbench/browser/parts/
|
||||
import { Panel, PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel';
|
||||
import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
@@ -37,7 +37,6 @@ import { ViewContainer, IViewDescriptorService, IViewContainerModel, ViewContain
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ViewMenuActions, ViewContainerMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
|
||||
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { Before2D, CompositeDragAndDropObserver, ICompositeDragAndDrop, toggleDropEffect } from 'vs/workbench/browser/dnd';
|
||||
import { IActivity } from 'vs/workbench/common/activity';
|
||||
|
||||
@@ -118,7 +117,6 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super(
|
||||
notificationService,
|
||||
@@ -140,7 +138,6 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
);
|
||||
|
||||
this.panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: PanelPart.PINNED_PANELS, version: 1 });
|
||||
|
||||
this.dndHandler = new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Panel,
|
||||
(id: string, focus?: boolean) => (this.openPanel(id, focus) as Promise<IPaneComposite | undefined>).then(panel => panel || null),
|
||||
@@ -338,7 +335,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
disposables.clear();
|
||||
this.onDidRegisterExtensions();
|
||||
this.compositeBar.onDidChange(() => this.saveCachedPanels(), this, disposables);
|
||||
this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables);
|
||||
this.storageService.onDidChangeValue(e => this.onDidStorageValueChange(e), this, disposables);
|
||||
}));
|
||||
|
||||
}
|
||||
@@ -670,7 +667,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
return this.toolBar.getItemsWidth();
|
||||
}
|
||||
|
||||
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
|
||||
private onDidStorageValueChange(e: IStorageValueChangeEvent): void {
|
||||
if (e.key === PanelPart.PINNED_PANELS && e.scope === StorageScope.GLOBAL
|
||||
&& this.cachedPanelsValue !== this.getStoredCachedPanelsValue() /* This checks if current window changed the value or not */) {
|
||||
this._cachedPanelsValue = undefined;
|
||||
@@ -760,7 +757,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
}
|
||||
|
||||
private setStoredCachedViewletsValue(value: string): void {
|
||||
this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL);
|
||||
this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL, StorageTarget.USER);
|
||||
}
|
||||
|
||||
private getPlaceholderViewContainers(): IPlaceholderViewContainer[] {
|
||||
@@ -792,7 +789,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
}
|
||||
|
||||
private setStoredPlaceholderViewContainersValue(value: string): void {
|
||||
this.storageService.store(PanelPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.WORKSPACE);
|
||||
this.storageService.store(PanelPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.WORKSPACE, StorageTarget.MACHINE);
|
||||
}
|
||||
|
||||
private getViewContainer(panelId: string): ViewContainer | undefined {
|
||||
|
||||
@@ -23,7 +23,7 @@ import { isThemeColor } from 'vs/editor/common/editorCommon';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { EventHelper, createStyleSheet, addDisposableListener, EventType, hide, show, isAncestor, appendChildren } from 'vs/base/browser/dom';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
@@ -32,7 +32,6 @@ import { ToggleStatusbarVisibilityAction } from 'vs/workbench/browser/actions/la
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Command } from 'vs/editor/common/modes';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
@@ -102,10 +101,10 @@ class StatusbarViewModel extends Disposable {
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e)));
|
||||
this._register(this.storageService.onDidChangeValue(e => this.onDidStorageValueChange(e)));
|
||||
}
|
||||
|
||||
private onDidStorageChange(event: IWorkspaceStorageChangeEvent): void {
|
||||
private onDidStorageValueChange(event: IStorageValueChangeEvent): void {
|
||||
if (event.key === StatusbarViewModel.HIDDEN_ENTRIES_KEY && event.scope === StorageScope.GLOBAL) {
|
||||
|
||||
// Keep current hidden entries
|
||||
@@ -275,7 +274,7 @@ class StatusbarViewModel extends Disposable {
|
||||
|
||||
private saveState(): void {
|
||||
if (this.hidden.size > 0) {
|
||||
this.storageService.store(StatusbarViewModel.HIDDEN_ENTRIES_KEY, JSON.stringify(Array.from(this.hidden.values())), StorageScope.GLOBAL);
|
||||
this.storageService.store(StatusbarViewModel.HIDDEN_ENTRIES_KEY, JSON.stringify(Array.from(this.hidden.values())), StorageScope.GLOBAL, StorageTarget.USER);
|
||||
} else {
|
||||
this.storageService.remove(StatusbarViewModel.HIDDEN_ENTRIES_KEY, StorageScope.GLOBAL);
|
||||
}
|
||||
@@ -405,12 +404,9 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
|
||||
) {
|
||||
super(Parts.STATUSBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
|
||||
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: StatusbarViewModel.HIDDEN_ENTRIES_KEY, version: 1 });
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IAction, Action, SubmenuAction, Separator } from 'vs/base/common/actions';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { isMacintosh, isWeb, isIOS } from 'vs/base/common/platform';
|
||||
import { isMacintosh, isWeb, isIOS, isNative } from 'vs/base/common/platform';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
@@ -21,7 +21,7 @@ import { MENUBAR_SELECTION_FOREGROUND, MENUBAR_SELECTION_BACKGROUND, MENUBAR_SEL
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IUpdateService, StateType } from 'vs/platform/update/common/update';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
@@ -122,7 +122,7 @@ export abstract class MenubarControl extends Disposable {
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)));
|
||||
|
||||
// Listen to update service
|
||||
this.updateService.onStateChange(() => this.updateMenubar());
|
||||
this.updateService.onStateChange(() => this.onUpdateStateChange());
|
||||
|
||||
// Listen for changes in recently opened menu
|
||||
this._register(this.workspacesService.onRecentlyOpenedChange(() => { this.onRecentlyOpenedChange(); }));
|
||||
@@ -148,6 +148,14 @@ export abstract class MenubarControl extends Disposable {
|
||||
return label;
|
||||
}
|
||||
|
||||
protected onUpdateStateChange(): void {
|
||||
this.updateMenubar();
|
||||
}
|
||||
|
||||
protected onUpdateKeybindings(): void {
|
||||
this.updateMenubar();
|
||||
}
|
||||
|
||||
protected getOpenRecentActions(): (Separator | IAction & { uri: URI })[] {
|
||||
if (!this.recentlyOpened) {
|
||||
return [];
|
||||
@@ -191,13 +199,27 @@ export abstract class MenubarControl extends Disposable {
|
||||
if (event.affectsConfiguration('editor.accessibilitySupport')) {
|
||||
this.notifyUserOfCustomMenubarAccessibility();
|
||||
}
|
||||
|
||||
// Since we try not update when hidden, we should
|
||||
// try to update the recently opened list on visibility changes
|
||||
if (event.affectsConfiguration('window.menuBarVisibility')) {
|
||||
this.onRecentlyOpenedChange();
|
||||
}
|
||||
}
|
||||
|
||||
private onRecentlyOpenedChange(): void {
|
||||
this.workspacesService.getRecentlyOpened().then(recentlyOpened => {
|
||||
this.recentlyOpened = recentlyOpened;
|
||||
this.updateMenubar();
|
||||
});
|
||||
private get menubarHidden(): boolean {
|
||||
return isMacintosh && isNative ? false : getMenuBarVisibility(this.configurationService) === 'hidden';
|
||||
}
|
||||
|
||||
protected onRecentlyOpenedChange(): void {
|
||||
|
||||
// Do not update recently opened when the menubar is hidden #108712
|
||||
if (!this.menubarHidden) {
|
||||
this.workspacesService.getRecentlyOpened().then(recentlyOpened => {
|
||||
this.recentlyOpened = recentlyOpened;
|
||||
this.updateMenubar();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private createOpenRecentMenuAction(recent: IRecent): IAction & { uri: URI } {
|
||||
@@ -241,7 +263,7 @@ export abstract class MenubarControl extends Disposable {
|
||||
}
|
||||
|
||||
const hasBeenNotified = this.storageService.getBoolean('menubar/accessibleMenubarNotified', StorageScope.GLOBAL, false);
|
||||
const usingCustomMenubar = getTitleBarStyle(this.configurationService, this.environmentService) === 'custom';
|
||||
const usingCustomMenubar = getTitleBarStyle(this.configurationService) === 'custom';
|
||||
|
||||
if (hasBeenNotified || usingCustomMenubar || !this.accessibilityService.isScreenReaderOptimized()) {
|
||||
return;
|
||||
@@ -257,7 +279,7 @@ export abstract class MenubarControl extends Disposable {
|
||||
}
|
||||
]);
|
||||
|
||||
this.storageService.store('menubar/accessibleMenubarNotified', true, StorageScope.GLOBAL);
|
||||
this.storageService.store('menubar/accessibleMenubarNotified', true, StorageScope.GLOBAL, StorageTarget.USER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,6 +288,7 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
private container: HTMLElement | undefined;
|
||||
private alwaysOnMnemonics: boolean = false;
|
||||
private focusInsideMenubar: boolean = false;
|
||||
private visible: boolean = true;
|
||||
|
||||
private readonly _onVisibilityChange: Emitter<boolean>;
|
||||
private readonly _onFocusStateChange: Emitter<boolean>;
|
||||
@@ -475,7 +498,7 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
}
|
||||
|
||||
private get currentMenubarVisibility(): MenuBarVisibility {
|
||||
return getMenuBarVisibility(this.configurationService, this.environmentService);
|
||||
return getMenuBarVisibility(this.configurationService);
|
||||
}
|
||||
|
||||
private get currentDisableMenuBarAltFocus(): boolean {
|
||||
@@ -530,6 +553,12 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
return currentSidebarLocation === 'right' ? Direction.Left : Direction.Right;
|
||||
}
|
||||
|
||||
private onDidVisibilityChange(visible: boolean): void {
|
||||
this.visible = visible;
|
||||
this.onRecentlyOpenedChange();
|
||||
this._onVisibilityChange.fire(visible);
|
||||
}
|
||||
|
||||
private setupCustomMenubar(firstTime: boolean): void {
|
||||
// If there is no container, we cannot setup the menubar
|
||||
if (!this.container) {
|
||||
@@ -554,7 +583,7 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.menubar.onVisibilityChange(e => this._onVisibilityChange.fire(e)));
|
||||
this._register(this.menubar.onVisibilityChange(e => this.onDidVisibilityChange(e)));
|
||||
|
||||
// Before we focus the menubar, stop updates to it so that focus-related context keys will work
|
||||
this._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_IN, () => {
|
||||
@@ -645,29 +674,15 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
visibility: this.currentMenubarVisibility,
|
||||
getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id),
|
||||
alwaysOnMnemonics: this.alwaysOnMnemonics,
|
||||
compactMode: this.currentCompactMenuMode,
|
||||
getCompactMenuActions: () => {
|
||||
if (!isWeb) {
|
||||
return []; // only for web
|
||||
}
|
||||
|
||||
const webNavigationActions: IAction[] = [];
|
||||
const webNavigationMenu = this.menuService.createMenu(MenuId.MenubarWebNavigationMenu, this.contextKeyService);
|
||||
for (const groups of webNavigationMenu.getActions()) {
|
||||
const [, actions] = groups;
|
||||
for (const action of actions) {
|
||||
action.label = mnemonicMenuLabel(this.calculateActionLabel(action));
|
||||
webNavigationActions.push(action);
|
||||
}
|
||||
}
|
||||
webNavigationMenu.dispose();
|
||||
|
||||
return webNavigationActions;
|
||||
}
|
||||
compactMode: this.currentCompactMenuMode
|
||||
};
|
||||
}
|
||||
|
||||
protected onDidChangeWindowFocus(hasFocus: boolean): void {
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.onDidChangeWindowFocus(hasFocus);
|
||||
|
||||
if (this.container) {
|
||||
@@ -682,6 +697,30 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
}
|
||||
}
|
||||
|
||||
protected onUpdateStateChange(): void {
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.onUpdateStateChange();
|
||||
}
|
||||
|
||||
protected onRecentlyOpenedChange(): void {
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.onRecentlyOpenedChange();
|
||||
}
|
||||
|
||||
protected onUpdateKeybindings(): void {
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.onUpdateKeybindings();
|
||||
}
|
||||
|
||||
protected registerListeners(): void {
|
||||
super.registerListeners();
|
||||
|
||||
|
||||
@@ -53,8 +53,8 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
|
||||
readonly minimumWidth: number = 0;
|
||||
readonly maximumWidth: number = Number.POSITIVE_INFINITY;
|
||||
get minimumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.currentMenubarVisibility === 'hidden' ? getZoomFactor() : 1)); }
|
||||
get maximumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.currentMenubarVisibility === 'hidden' ? getZoomFactor() : 1)); }
|
||||
get minimumHeight(): number { return 30 / (this.currentMenubarVisibility === 'hidden' ? getZoomFactor() : 1); }
|
||||
get maximumHeight(): number { return this.minimumHeight; }
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -100,7 +100,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
|
||||
this.contextMenu = this._register(menuService.createMenu(MenuId.TitleBarContext, contextKeyService));
|
||||
|
||||
this.titleBarStyle = getTitleBarStyle(this.configurationService, this.environmentService);
|
||||
this.titleBarStyle = getTitleBarStyle(this.configurationService);
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
@@ -461,13 +461,13 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
}
|
||||
|
||||
protected get currentMenubarVisibility(): MenuBarVisibility {
|
||||
return getMenuBarVisibility(this.configurationService, this.environmentService);
|
||||
return getMenuBarVisibility(this.configurationService);
|
||||
}
|
||||
|
||||
updateLayout(dimension: Dimension): void {
|
||||
this.lastLayoutDimensions = dimension;
|
||||
|
||||
if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
|
||||
if (getTitleBarStyle(this.configurationService) === 'custom') {
|
||||
// Only prevent zooming behavior on macOS or when the menubar is not visible
|
||||
if ((!isWeb && isMacintosh) || this.currentMenubarVisibility === 'hidden') {
|
||||
this.title.style.zoom = `${1 / getZoomFactor()}`;
|
||||
|
||||
174
lib/vscode/src/vs/workbench/browser/parts/views/media/views.css
Normal file
174
lib/vscode/src/vs/workbench/browser/parts/views/media/views.css
Normal file
@@ -0,0 +1,174 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* File icons in trees */
|
||||
|
||||
.file-icon-themable-tree.align-icons-and-twisties .monaco-tl-twistie:not(.force-twistie):not(.collapsible),
|
||||
.file-icon-themable-tree .align-icon-with-twisty .monaco-tl-twistie:not(.force-twistie):not(.collapsible),
|
||||
.file-icon-themable-tree.hide-arrows .monaco-tl-twistie:not(.force-twistie),
|
||||
.file-icon-themable-tree .monaco-tl-twistie.force-no-twistie {
|
||||
background-image: none !important;
|
||||
width: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* Misc */
|
||||
|
||||
.monaco-workbench .tree-explorer-viewlet-tree-view {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-workbench .tree-explorer-viewlet-tree-view .message {
|
||||
display: flex;
|
||||
padding: 4px 12px 4px 18px;
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
|
||||
.monaco-workbench .tree-explorer-viewlet-tree-view .message p {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.monaco-workbench .tree-explorer-viewlet-tree-view .message ul {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.monaco-workbench .tree-explorer-viewlet-tree-view .message.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monaco-workbench .tree-explorer-viewlet-tree-view .customview-tree {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-workbench .tree-explorer-viewlet-tree-view .customview-tree.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monaco-workbench .pane > .pane-body > .welcome-view {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.monaco-workbench .pane > .pane-body:not(.welcome) > .welcome-view,
|
||||
.monaco-workbench .pane > .pane-body.welcome > :not(.welcome-view) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monaco-workbench .pane > .pane-body > .welcome-view .monaco-button {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.monaco-workbench .pane > .pane-body.wide > .welcome-view .monaco-button {
|
||||
margin-left: inherit;
|
||||
max-width: 260px;
|
||||
}
|
||||
|
||||
.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 > * {
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list-row .monaco-tl-contents.align-icon-with-twisty::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list-row .monaco-tl-contents:not(.align-icon-with-twisty)::before {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row {
|
||||
padding-right: 12px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item {
|
||||
display: flex;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
flex: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
flex-wrap: nowrap;
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .monaco-inputbox {
|
||||
line-height: normal;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .custom-view-tree-node-item-resourceLabel {
|
||||
flex: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item > .custom-view-tree-node-item-icon {
|
||||
background-size: 16px;
|
||||
background-position: left center;
|
||||
background-repeat: no-repeat;
|
||||
padding-right: 6px;
|
||||
width: 16px;
|
||||
height: 22px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item > .custom-view-tree-node-item-icon.codicon {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row.selected .custom-view-tree-node-item > .custom-view-tree-node-item-icon.codicon {
|
||||
color: currentColor !important;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .custom-view-tree-node-item-resourceLabel .monaco-icon-label-container > .monaco-icon-name-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .custom-view-tree-node-item-resourceLabel::after {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .actions {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .monaco-list-row:hover .custom-view-tree-node-item .actions,
|
||||
.customview-tree .monaco-list .monaco-list-row.selected .custom-view-tree-node-item .actions,
|
||||
.customview-tree .monaco-list .monaco-list-row.focused .custom-view-tree-node-item .actions {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .custom-view-tree-node-item .actions .action-label {
|
||||
width: 16px;
|
||||
height: 100%;
|
||||
background-size: 16px;
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .custom-view-tree-node-item .actions .action-label.codicon {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.customview-tree .monaco-list .custom-view-tree-node-item .actions .action-label.codicon::before {
|
||||
vertical-align: middle;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,15 +18,15 @@ import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService, Themable } from 'vs/platform/theme/common/themeService';
|
||||
import { IThemeService, Themable, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { PaneView, IPaneViewOptions, IPaneOptions, Pane, IPaneStyles } from 'vs/base/browser/ui/splitview/paneview';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkbenchLayoutService, Position } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewDescriptor, ViewContainer, IViewDescriptorService, ViewContainerLocation, IViewPaneContainer, IViewsRegistry, IViewContentDescriptor, IAddedViewDescriptorRef, IViewDescriptorRef, IViewContainerModel } from 'vs/workbench/common/views';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewDescriptor, ViewContainer, IViewDescriptorService, ViewContainerLocation, IViewPaneContainer, IViewsRegistry, IViewContentDescriptor, IAddedViewDescriptorRef, IViewDescriptorRef, IViewContainerModel, defaultViewIcon } from 'vs/workbench/common/views';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { assertIsDefined, isString } from 'vs/base/common/types';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -50,6 +50,8 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export interface IPaneColors extends IColorMapping {
|
||||
dropBackground?: ColorIdentifier;
|
||||
@@ -70,6 +72,9 @@ type WelcomeActionClassification = {
|
||||
uri: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
|
||||
const viewPaneContainerExpandedIcon = registerIcon('view-pane-container-expanded', Codicon.chevronDown, nls.localize('viewPaneContainerExpandedIcon', 'Icon for an expanded view pane container.'));
|
||||
const viewPaneContainerCollapsedIcon = registerIcon('view-pane-container-collapsed', Codicon.chevronRight, nls.localize('viewPaneContainerCollapsedIcon', 'Icon for a collapsed view pane container.'));
|
||||
|
||||
const viewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
|
||||
|
||||
interface IItem {
|
||||
@@ -263,7 +268,10 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
if (changed) {
|
||||
this._onDidChangeBodyVisibility.fire(expanded);
|
||||
}
|
||||
|
||||
if (this.twistiesContainer) {
|
||||
this.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!expanded)));
|
||||
this.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(expanded)));
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -288,7 +296,7 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
protected renderHeader(container: HTMLElement): void {
|
||||
this.headerContainer = container;
|
||||
|
||||
this.renderTwisties(container);
|
||||
this.twistiesContainer = append(container, $(ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded()))));
|
||||
|
||||
this.renderHeaderTitle(container, this.title);
|
||||
|
||||
@@ -316,8 +324,8 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
this.updateActionsVisibility();
|
||||
}
|
||||
|
||||
protected renderTwisties(container: HTMLElement): void {
|
||||
this.twistiesContainer = append(container, $('.twisties.codicon.codicon-chevron-right'));
|
||||
protected getTwistyIcon(expanded: boolean): ThemeIcon {
|
||||
return expanded ? viewPaneContainerExpandedIcon : viewPaneContainerCollapsedIcon;
|
||||
}
|
||||
|
||||
style(styles: IPaneStyles): void {
|
||||
@@ -338,8 +346,8 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
}
|
||||
}
|
||||
|
||||
private getIcon(): string | URI {
|
||||
return this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || 'codicon-window';
|
||||
private getIcon(): ThemeIcon | URI {
|
||||
return this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || defaultViewIcon;
|
||||
}
|
||||
|
||||
protected renderHeaderTitle(container: HTMLElement, title: string): void {
|
||||
@@ -357,9 +365,8 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;
|
||||
-webkit-mask-size: 16px;
|
||||
`);
|
||||
} else if (isString(icon)) {
|
||||
this.iconContainer.classList.add('codicon');
|
||||
cssClass = icon;
|
||||
} else if (ThemeIcon.isThemeIcon(icon)) {
|
||||
cssClass = ThemeIcon.asClassName(icon);
|
||||
}
|
||||
|
||||
if (cssClass) {
|
||||
@@ -556,9 +563,7 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
this.bodyContainer.classList.add('welcome');
|
||||
this.viewWelcomeContainer.innerText = '';
|
||||
|
||||
let buttonIndex = 0;
|
||||
|
||||
for (const { content, preconditions } of contents) {
|
||||
for (const { content, precondition } of contents) {
|
||||
const lines = content.split('\n');
|
||||
|
||||
for (let line of lines) {
|
||||
@@ -581,21 +586,15 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
disposables.add(button);
|
||||
disposables.add(attachButtonStyler(button, this.themeService));
|
||||
|
||||
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 p = append(this.viewWelcomeContainer, $('p'));
|
||||
|
||||
@@ -1319,7 +1318,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
|
||||
saveState(): void {
|
||||
this.panes.forEach((view) => view.saveState());
|
||||
this.storageService.store(this.visibleViewsStorageId, this.length, StorageScope.WORKSPACE);
|
||||
this.storageService.store(this.visibleViewsStorageId, this.length, StorageScope.WORKSPACE, StorageTarget.USER);
|
||||
}
|
||||
|
||||
private onContextMenu(event: StandardMouseEvent, viewDescriptor: IViewDescriptor): void {
|
||||
|
||||
Reference in New Issue
Block a user