Merge from vscode 731f9c25632dbbf01ee3a7892ad9d2791fe0260c

This commit is contained in:
ADS Merger
2020-07-24 05:27:34 +00:00
parent eccf3cf5fe
commit d965d4aef3
145 changed files with 3072 additions and 1550 deletions

View File

@@ -77,7 +77,6 @@ const vscodeResources = [
'out-build/vs/code/electron-browser/workbench/**',
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
'out-build/vs/code/electron-browser/issue/issueReporter.js',
'out-build/vs/code/electron-browser/processExplorer/processExplorer.js',
'out-build/sql/workbench/electron-browser/splashscreen/*', // {{SQL CARBON EDIT}} STart
'out-build/sql/**/*.{svg,png,cur,html}',
'out-build/sql/base/browser/ui/table/media/*.{gif,png,svg}',

View File

@@ -54,7 +54,7 @@
"url": "vscode://schemas/keybindings"
},
{
"fileMatch": "vscode://defaultsettings/*/*.json",
"fileMatch": "vscode://defaultsettings/defaultSettings.json",
"url": "vscode://schemas/settings/default"
},
{

File diff suppressed because one or more lines are too long

View File

@@ -163,13 +163,15 @@ document.addEventListener('click', event => {
return;
}
// Pass through known schemes
if (passThroughLinkSchemes.some(scheme => node.href.startsWith(scheme))) {
return;
let hrefText = node.getAttribute('data-href');
if (!hrefText) {
// Pass through known schemes
if (passThroughLinkSchemes.some(scheme => node.href.startsWith(scheme))) {
return;
}
hrefText = node.getAttribute('href');
}
const hrefText = node.getAttribute('data-href') || node.getAttribute('href');
// If original link doesn't look like a url, delegate back to VS Code to resolve
if (!/^[a-z\-]+:/i.test(hrefText)) {
messaging.postMessage('openLink', { href: hrefText });

View File

@@ -15,6 +15,10 @@
"*",
"onAuthenticationRequest:microsoft"
],
"extensionKind": [
"ui",
"workspace"
],
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"main": "./out/extension.js",
"browser": "./dist/browser/extension.js",

View File

@@ -85,6 +85,7 @@
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"spdlog": "^0.11.1",
"sudo-prompt": "9.1.1",
"tas-client": "^0.0.950",
"v8-inspect-profiler": "^0.0.20",
"vscode-nsfw": "1.2.8",
"vscode-oniguruma": "1.3.1",

View File

@@ -4,13 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./buttonMenu';
import { IAction, IActionRunner } from 'vs/base/common/actions';
import { BaseActionViewItem, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, IActionRunner, IActionViewItemProvider } from 'vs/base/common/actions';
import { IDisposable } from 'vs/base/common/lifecycle';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { append, $, addClasses } from 'vs/base/browser/dom';
import { IDropdownMenuOptions, DropdownMenu, IActionProvider, IContextMenuProvider, ILabelRenderer } from 'vs/base/browser/ui/dropdown/dropdown';
import { IDropdownMenuOptions, DropdownMenu, IActionProvider, ILabelRenderer } from 'vs/base/browser/ui/dropdown/dropdown';
import { IContextMenuProvider } from 'vs/base/browser/contextmenu';
import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export class DropdownMenuActionViewItem extends BaseActionViewItem {
private menuActionsOrProvider: ReadonlyArray<IAction> | IActionProvider;

View File

@@ -3,17 +3,18 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions';
import { IAction, IActionRunner, ActionRunner, IActionViewItem } from 'vs/base/common/actions';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import {
IActionBarOptions, ActionsOrientation, IActionViewItem,
IActionOptions, ActionViewItem, BaseActionViewItem
IActionBarOptions, ActionsOrientation,
IActionOptions
} from 'vs/base/browser/ui/actionbar/actionbar';
import * as lifecycle from 'vs/base/common/lifecycle';
import * as DOM from 'vs/base/browser/dom';
import * as types from 'vs/base/common/types';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ActionViewItem, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
const defaultOptions: IActionBarOptions = {
orientation: ActionsOrientation.HORIZONTAL,

View File

@@ -2,11 +2,11 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IAction } from 'vs/base/common/actions';
import { IAction, IActionViewItem } from 'vs/base/common/actions';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import {
IActionBarOptions, ActionsOrientation, IActionViewItem,
IActionBarOptions, ActionsOrientation,
IActionOptions
} from 'vs/base/browser/ui/actionbar/actionbar';
import * as DOM from 'vs/base/browser/dom';

View File

@@ -8,8 +8,8 @@ import 'vs/css!./media/icons';
import { ActionBar } from './actionbar';
import { IActionRunner, IAction } from 'vs/base/common/actions';
import { ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IActionRunner, IAction, IActionViewItem } from 'vs/base/common/actions';
import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { IToolBarOptions } from 'vs/base/browser/ui/toolbar/toolbar';
import { OverflowActionBar } from 'sql/base/browser/ui/taskbar/overflowActionbar';

View File

@@ -6,11 +6,11 @@
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IAction, ActionRunner } from 'vs/base/common/actions';
import { IAction, ActionRunner, IActionViewItemProvider } from 'vs/base/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IMenuService, MenuId, MenuItemAction, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { ContextAwareMenuEntryActionViewItem, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenuService, MenuId, MenuItemAction, registerAction2, Action2, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { MenuEntryActionViewItem, createAndFillInContextMenuActions, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IContextKeyService, ContextKeyExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeViewDescriptor, IViewsRegistry, ITreeItemLabel, Extensions, IViewDescriptorService, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
@@ -21,7 +21,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { ICommandService } from 'vs/platform/commands/common/commands';
import * as DOM from 'vs/base/browser/dom';
import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels';
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { URI } from 'vs/base/common/uri';
import { dirname, basename } from 'vs/base/common/resources';
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, ThemeIcon, IThemeService } from 'vs/platform/theme/common/themeService';
@@ -47,6 +47,7 @@ import { ITreeItem, ITreeView } from 'sql/workbench/common/views';
import { UserCancelledConnectionError } from 'sql/base/common/errors';
import { IOEShimService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerViewTreeShim';
import { NodeContextKey } from 'sql/workbench/browser/parts/views/nodeContext';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export class TreeViewPane extends ViewPane {
@@ -429,7 +430,15 @@ export class TreeView extends Disposable implements ITreeView {
}
private createTree() {
const actionViewItemProvider = (action: IAction) => action instanceof MenuItemAction ? this.instantiationService.createInstance(ContextAwareMenuEntryActionViewItem, action) : undefined;
const actionViewItemProvider = (action: IAction) => {
if (action instanceof MenuItemAction) {
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
} else if (action instanceof SubmenuItemAction) {
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
}
return undefined;
};
const treeMenus = this._register(this.instantiationService.createInstance(TreeMenus, this.id));
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
const dataSource = this.instantiationService.createInstance(TreeDataSource, this, this.id, <T>(task: Promise<T>) => this.progressService.withProgress({ location: this.id }, () => task));

View File

@@ -20,8 +20,7 @@ import { EditDataInput } from 'sql/workbench/browser/editData/editDataInput';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction } from 'vs/base/common/actions';
import { IAction, IActionViewItem } from 'vs/base/common/actions';
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
import { IEditorDescriptorService } from 'sql/workbench/services/queryEditor/browser/editorDescriptorService';
import {

View File

@@ -6,8 +6,8 @@
import { localize } from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { Action, IAction } from 'vs/base/common/actions';
import { ActionBar, Separator, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, IAction, Separator } from 'vs/base/common/actions';
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { CellActionBase, CellContext } from 'sql/workbench/contrib/notebook/browser/cellViews/codeActions';
import { CellModel } from 'sql/workbench/services/notebook/browser/models/cell';
import { CellTypes, CellType } from 'sql/workbench/services/notebook/common/contracts';

View File

@@ -11,7 +11,6 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { CellContext } from 'sql/workbench/contrib/notebook/browser/cellViews/codeActions';
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
@@ -20,6 +19,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService';
import { CellModel } from 'sql/workbench/services/notebook/browser/models/cell';
import { IProductService } from 'vs/platform/product/common/productService';
import { Separator } from 'vs/base/common/actions';
suite('CellToolbarActions', function (): void {
suite('removeDuplicatedAndStartingSeparators', function (): void {

View File

@@ -32,11 +32,11 @@ import { range, find } from 'vs/base/common/arrays';
import { Orientation } from 'vs/base/browser/ui/splitview/splitview';
import { Disposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { generateUuid } from 'vs/base/common/uuid';
import { Separator, ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { isInDOM, Dimension } from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IAction } from 'vs/base/common/actions';
import { IAction, Separator } from 'vs/base/common/actions';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { ILogService } from 'vs/platform/log/common/log';
import { localize } from 'vs/nls';

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { IAction } from 'vs/base/common/actions';
import { IAction, Separator } from 'vs/base/common/actions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
@@ -24,7 +24,6 @@ import { TreeNodeContextKey } from 'sql/workbench/services/objectExplorer/common
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
import { ServerInfoContextKey } from 'sql/workbench/services/connection/common/serverInfoContextKey';
import { fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { firstIndex, find } from 'vs/base/common/arrays';
/**

View File

@@ -3,10 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IAction, IActionRunner } from 'vs/base/common/actions';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, IActionRunner, IActionViewItem } from 'vs/base/common/actions';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { SubmenuAction } from 'vs/base/browser/ui/menu/menu';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
export interface IContextMenuEvent {
@@ -16,15 +14,9 @@ export interface IContextMenuEvent {
readonly metaKey?: boolean;
}
export class ContextSubMenu extends SubmenuAction {
constructor(label: string, public entries: Array<ContextSubMenu | IAction>) {
super(label, entries, 'contextsubmenu');
}
}
export interface IContextMenuDelegate {
getAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; };
getActions(): ReadonlyArray<IAction | ContextSubMenu>;
getActions(): IAction[];
getCheckedActionsRepresentation?(action: IAction): 'radio' | 'checkbox';
getActionViewItem?(action: IAction): IActionViewItem | undefined;
getActionsContext?(event?: IContextMenuEvent): any;
@@ -36,3 +28,7 @@ export interface IContextMenuDelegate {
anchorAlignment?: AnchorAlignment;
domForShadowRoot?: HTMLElement;
}
export interface IContextMenuProvider {
showContextMenu(delegate: IContextMenuDelegate): void;
}

View File

@@ -0,0 +1,406 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./actionbar';
import * as platform from 'vs/base/common/platform';
import * as nls from 'vs/nls';
import { Disposable } from 'vs/base/common/lifecycle';
import { SelectBox, ISelectOptionItem, ISelectBoxOptions } from 'vs/base/browser/ui/selectBox/selectBox';
import { IAction, IActionRunner, Action, IActionChangeEvent, ActionRunner, Separator, IActionViewItem } from 'vs/base/common/actions';
import * as DOM from 'vs/base/browser/dom';
import * as types from 'vs/base/common/types';
import { EventType, Gesture } from 'vs/base/browser/touch';
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
import { DataTransfers } from 'vs/base/browser/dnd';
import { isFirefox } from 'vs/base/browser/browser';
export interface IBaseActionViewItemOptions {
draggable?: boolean;
isMenu?: boolean;
useEventAsContext?: boolean;
}
export class BaseActionViewItem extends Disposable implements IActionViewItem {
element: HTMLElement | undefined;
_context: any;
_action: IAction;
private _actionRunner: IActionRunner | undefined;
constructor(context: any, action: IAction, protected options: IBaseActionViewItemOptions = {}) {
super();
this._context = context || this;
this._action = action;
if (action instanceof Action) {
this._register(action.onDidChange(event => {
if (!this.element) {
// we have not been rendered yet, so there
// is no point in updating the UI
return;
}
this.handleActionChangeEvent(event);
}));
}
}
private handleActionChangeEvent(event: IActionChangeEvent): void {
if (event.enabled !== undefined) {
this.updateEnabled();
}
if (event.checked !== undefined) {
this.updateChecked();
}
if (event.class !== undefined) {
this.updateClass();
}
if (event.label !== undefined) {
this.updateLabel();
this.updateTooltip();
}
if (event.tooltip !== undefined) {
this.updateTooltip();
}
}
get actionRunner(): IActionRunner {
if (!this._actionRunner) {
this._actionRunner = this._register(new ActionRunner());
}
return this._actionRunner;
}
set actionRunner(actionRunner: IActionRunner) {
this._actionRunner = actionRunner;
}
getAction(): IAction {
return this._action;
}
isEnabled(): boolean {
return this._action.enabled;
}
setActionContext(newContext: unknown): void {
this._context = newContext;
}
render(container: HTMLElement): void {
const element = this.element = container;
this._register(Gesture.addTarget(container));
const enableDragging = this.options && this.options.draggable;
if (enableDragging) {
container.draggable = true;
if (isFirefox) {
// Firefox: requires to set a text data transfer to get going
this._register(DOM.addDisposableListener(container, DOM.EventType.DRAG_START, e => e.dataTransfer?.setData(DataTransfers.TEXT, this._action.label)));
}
}
this._register(DOM.addDisposableListener(element, EventType.Tap, e => this.onClick(e)));
this._register(DOM.addDisposableListener(element, DOM.EventType.MOUSE_DOWN, e => {
if (!enableDragging) {
DOM.EventHelper.stop(e, true); // do not run when dragging is on because that would disable it
}
if (this._action.enabled && e.button === 0) {
DOM.addClass(element, 'active');
}
}));
if (platform.isMacintosh) {
// macOS: allow to trigger the button when holding Ctrl+key and pressing the
// main mouse button. This is for scenarios where e.g. some interaction forces
// the Ctrl+key to be pressed and hold but the user still wants to interact
// with the actions (for example quick access in quick navigation mode).
this._register(DOM.addDisposableListener(element, DOM.EventType.CONTEXT_MENU, e => {
if (e.button === 0 && e.ctrlKey === true) {
this.onClick(e);
}
}));
}
this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, e => {
DOM.EventHelper.stop(e, true);
// See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
// > Writing to the clipboard
// > You can use the "cut" and "copy" commands without any special
// permission if you are using them in a short-lived event handler
// for a user action (for example, a click handler).
// => to get the Copy and Paste context menu actions working on Firefox,
// there should be no timeout here
if (this.options && this.options.isMenu) {
this.onClick(e);
} else {
platform.setImmediate(() => this.onClick(e));
}
}));
this._register(DOM.addDisposableListener(element, DOM.EventType.DBLCLICK, e => {
DOM.EventHelper.stop(e, true);
}));
[DOM.EventType.MOUSE_UP, DOM.EventType.MOUSE_OUT].forEach(event => {
this._register(DOM.addDisposableListener(element, event, e => {
DOM.EventHelper.stop(e);
DOM.removeClass(element, 'active');
}));
});
}
onClick(event: DOM.EventLike): void {
DOM.EventHelper.stop(event, true);
const context = types.isUndefinedOrNull(this._context) ? this.options?.useEventAsContext ? event : undefined : this._context;
this.actionRunner.run(this._action, context);
}
focus(): void {
if (this.element) {
this.element.focus();
DOM.addClass(this.element, 'focused');
}
}
blur(): void {
if (this.element) {
this.element.blur();
DOM.removeClass(this.element, 'focused');
}
}
protected updateEnabled(): void {
// implement in subclass
}
protected updateLabel(): void {
// implement in subclass
}
protected updateTooltip(): void {
// implement in subclass
}
protected updateClass(): void {
// implement in subclass
}
protected updateChecked(): void {
// implement in subclass
}
dispose(): void {
if (this.element) {
DOM.removeNode(this.element);
this.element = undefined;
}
super.dispose();
}
}
export interface IActionViewItemOptions extends IBaseActionViewItemOptions {
icon?: boolean;
label?: boolean;
keybinding?: string | null;
}
export class ActionViewItem extends BaseActionViewItem {
protected label: HTMLElement | undefined;
protected options: IActionViewItemOptions;
private cssClass?: string;
constructor(context: unknown, action: IAction, options: IActionViewItemOptions = {}) {
super(context, action, options);
this.options = options;
this.options.icon = options.icon !== undefined ? options.icon : false;
this.options.label = options.label !== undefined ? options.label : true;
this.cssClass = '';
}
render(container: HTMLElement): void {
super.render(container);
if (this.element) {
this.label = DOM.append(this.element, DOM.$('a.action-label'));
}
if (this.label) {
if (this._action.id === Separator.ID) {
this.label.setAttribute('role', 'presentation'); // A separator is a presentation item
} else {
if (this.options.isMenu) {
this.label.setAttribute('role', 'menuitem');
} else {
this.label.setAttribute('role', 'button');
}
}
}
if (this.options.label && this.options.keybinding && this.element) {
DOM.append(this.element, DOM.$('span.keybinding')).textContent = this.options.keybinding;
}
this.updateClass();
this.updateLabel();
this.updateTooltip();
this.updateEnabled();
this.updateChecked();
}
focus(): void {
super.focus();
if (this.label) {
this.label.focus();
}
}
updateLabel(): void {
if (this.options.label && this.label) {
this.label.textContent = this.getAction().label;
}
}
updateTooltip(): void {
let title: string | null = null;
if (this.getAction().tooltip) {
title = this.getAction().tooltip;
} else if (!this.options.label && this.getAction().label && this.options.icon) {
title = this.getAction().label;
if (this.options.keybinding) {
title = nls.localize({ key: 'titleLabel', comment: ['action title', 'action keybinding'] }, "{0} ({1})", title, this.options.keybinding);
}
}
if (title && this.label) {
this.label.title = title;
}
}
updateClass(): void {
if (this.cssClass && this.label) {
DOM.removeClasses(this.label, this.cssClass);
}
if (this.options.icon) {
this.cssClass = this.getAction().class;
if (this.label) {
DOM.addClass(this.label, 'codicon');
if (this.cssClass) {
DOM.addClasses(this.label, this.cssClass);
}
}
this.updateEnabled();
} else {
if (this.label) {
DOM.removeClass(this.label, 'codicon');
}
}
}
updateEnabled(): void {
if (this.getAction().enabled) {
if (this.label) {
this.label.removeAttribute('aria-disabled');
DOM.removeClass(this.label, 'disabled');
this.label.tabIndex = 0;
}
if (this.element) {
DOM.removeClass(this.element, 'disabled');
}
} else {
if (this.label) {
this.label.setAttribute('aria-disabled', 'true');
DOM.addClass(this.label, 'disabled');
DOM.removeTabIndexAndUpdateFocus(this.label);
}
if (this.element) {
DOM.addClass(this.element, 'disabled');
}
}
}
updateChecked(): void {
if (this.label) {
if (this.getAction().checked) {
DOM.addClass(this.label, 'checked');
} else {
DOM.removeClass(this.label, 'checked');
}
}
}
}
export class SelectActionViewItem extends BaseActionViewItem {
protected selectBox: SelectBox;
constructor(ctx: unknown, action: IAction, options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, selectBoxOptions?: ISelectBoxOptions) {
super(ctx, action);
this.selectBox = new SelectBox(options, selected, contextViewProvider, undefined, selectBoxOptions);
this._register(this.selectBox);
this.registerListeners();
}
setOptions(options: ISelectOptionItem[], selected?: number): void {
this.selectBox.setOptions(options, selected);
}
select(index: number): void {
this.selectBox.select(index);
}
private registerListeners(): void {
this._register(this.selectBox.onDidSelect(e => {
this.actionRunner.run(this._action, this.getActionContext(e.selected, e.index));
}));
}
protected getActionContext(option: string, index: number) {
return option;
}
focus(): void {
if (this.selectBox) {
this.selectBox.focus();
}
}
blur(): void {
if (this.selectBox) {
this.selectBox.blur();
}
}
render(container: HTMLElement): void {
this.selectBox.render(container);
}
}

View File

@@ -4,382 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./actionbar';
import * as platform from 'vs/base/common/platform';
import * as nls from 'vs/nls';
import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { SelectBox, ISelectOptionItem, ISelectBoxOptions } from 'vs/base/browser/ui/selectBox/selectBox';
import { IAction, IActionRunner, Action, IActionChangeEvent, ActionRunner, IRunEvent } from 'vs/base/common/actions';
import { Disposable, dispose } from 'vs/base/common/lifecycle';
import { IAction, IActionRunner, ActionRunner, IRunEvent, Separator, IActionViewItem, IActionViewItemProvider } from 'vs/base/common/actions';
import * as DOM from 'vs/base/browser/dom';
import * as types from 'vs/base/common/types';
import { EventType, Gesture } from 'vs/base/browser/touch';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
import { Event, Emitter } from 'vs/base/common/event';
import { DataTransfers } from 'vs/base/browser/dnd';
import { isFirefox } from 'vs/base/browser/browser';
export interface IActionViewItem extends IDisposable {
actionRunner: IActionRunner;
setActionContext(context: any): void;
render(element: HTMLElement): void;
isEnabled(): boolean;
focus(fromRight?: boolean): void;
blur(): void;
}
export interface IBaseActionViewItemOptions {
draggable?: boolean;
isMenu?: boolean;
useEventAsContext?: boolean;
}
export class BaseActionViewItem extends Disposable implements IActionViewItem {
element: HTMLElement | undefined;
_context: any;
_action: IAction;
private _actionRunner: IActionRunner | undefined;
constructor(context: any, action: IAction, protected options?: IBaseActionViewItemOptions) {
super();
this._context = context || this;
this._action = action;
if (action instanceof Action) {
this._register(action.onDidChange(event => {
if (!this.element) {
// we have not been rendered yet, so there
// is no point in updating the UI
return;
}
this.handleActionChangeEvent(event);
}));
}
}
private handleActionChangeEvent(event: IActionChangeEvent): void {
if (event.enabled !== undefined) {
this.updateEnabled();
}
if (event.checked !== undefined) {
this.updateChecked();
}
if (event.class !== undefined) {
this.updateClass();
}
if (event.label !== undefined) {
this.updateLabel();
this.updateTooltip();
}
if (event.tooltip !== undefined) {
this.updateTooltip();
}
}
get actionRunner(): IActionRunner {
if (!this._actionRunner) {
this._actionRunner = this._register(new ActionRunner());
}
return this._actionRunner;
}
set actionRunner(actionRunner: IActionRunner) {
this._actionRunner = actionRunner;
}
getAction(): IAction {
return this._action;
}
isEnabled(): boolean {
return this._action.enabled;
}
setActionContext(newContext: unknown): void {
this._context = newContext;
}
render(container: HTMLElement): void {
const element = this.element = container;
this._register(Gesture.addTarget(container));
const enableDragging = this.options && this.options.draggable;
if (enableDragging) {
container.draggable = true;
if (isFirefox) {
// Firefox: requires to set a text data transfer to get going
this._register(DOM.addDisposableListener(container, DOM.EventType.DRAG_START, e => e.dataTransfer?.setData(DataTransfers.TEXT, this._action.label)));
}
}
this._register(DOM.addDisposableListener(element, EventType.Tap, e => this.onClick(e)));
this._register(DOM.addDisposableListener(element, DOM.EventType.MOUSE_DOWN, e => {
if (!enableDragging) {
DOM.EventHelper.stop(e, true); // do not run when dragging is on because that would disable it
}
if (this._action.enabled && e.button === 0) {
DOM.addClass(element, 'active');
}
}));
if (platform.isMacintosh) {
// macOS: allow to trigger the button when holding Ctrl+key and pressing the
// main mouse button. This is for scenarios where e.g. some interaction forces
// the Ctrl+key to be pressed and hold but the user still wants to interact
// with the actions (for example quick access in quick navigation mode).
this._register(DOM.addDisposableListener(element, DOM.EventType.CONTEXT_MENU, e => {
if (e.button === 0 && e.ctrlKey === true) {
this.onClick(e);
}
}));
}
this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, e => {
DOM.EventHelper.stop(e, true);
// See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
// > Writing to the clipboard
// > You can use the "cut" and "copy" commands without any special
// permission if you are using them in a short-lived event handler
// for a user action (for example, a click handler).
// => to get the Copy and Paste context menu actions working on Firefox,
// there should be no timeout here
if (this.options && this.options.isMenu) {
this.onClick(e);
} else {
platform.setImmediate(() => this.onClick(e));
}
}));
this._register(DOM.addDisposableListener(element, DOM.EventType.DBLCLICK, e => {
DOM.EventHelper.stop(e, true);
}));
[DOM.EventType.MOUSE_UP, DOM.EventType.MOUSE_OUT].forEach(event => {
this._register(DOM.addDisposableListener(element, event, e => {
DOM.EventHelper.stop(e);
DOM.removeClass(element, 'active');
}));
});
}
onClick(event: DOM.EventLike): void {
DOM.EventHelper.stop(event, true);
const context = types.isUndefinedOrNull(this._context) ? this.options?.useEventAsContext ? event : undefined : this._context;
this.actionRunner.run(this._action, context);
}
focus(): void {
if (this.element) {
this.element.focus();
DOM.addClass(this.element, 'focused');
}
}
blur(): void {
if (this.element) {
this.element.blur();
DOM.removeClass(this.element, 'focused');
}
}
protected updateEnabled(): void {
// implement in subclass
}
protected updateLabel(): void {
// implement in subclass
}
protected updateTooltip(): void {
// implement in subclass
}
protected updateClass(): void {
// implement in subclass
}
protected updateChecked(): void {
// implement in subclass
}
dispose(): void {
if (this.element) {
DOM.removeNode(this.element);
this.element = undefined;
}
super.dispose();
}
}
export class Separator extends Action {
static readonly ID = 'vs.actions.separator';
constructor(label?: string) {
super(Separator.ID, label, label ? 'separator text' : 'separator');
this.checked = false;
this.enabled = false;
}
}
export interface IActionViewItemOptions extends IBaseActionViewItemOptions {
icon?: boolean;
label?: boolean;
keybinding?: string | null;
}
export class ActionViewItem extends BaseActionViewItem {
protected label: HTMLElement | undefined;
protected options: IActionViewItemOptions;
private cssClass?: string;
constructor(context: unknown, action: IAction, options: IActionViewItemOptions = {}) {
super(context, action, options);
this.options = options;
this.options.icon = options.icon !== undefined ? options.icon : false;
this.options.label = options.label !== undefined ? options.label : true;
this.cssClass = '';
}
render(container: HTMLElement): void {
super.render(container);
if (this.element) {
this.label = DOM.append(this.element, DOM.$('a.action-label'));
}
if (this.label) {
if (this._action.id === Separator.ID) {
this.label.setAttribute('role', 'presentation'); // A separator is a presentation item
} else {
if (this.options.isMenu) {
this.label.setAttribute('role', 'menuitem');
} else {
this.label.setAttribute('role', 'button');
}
}
}
if (this.options.label && this.options.keybinding && this.element) {
DOM.append(this.element, DOM.$('span.keybinding')).textContent = this.options.keybinding;
}
this.updateClass();
this.updateLabel();
this.updateTooltip();
this.updateEnabled();
this.updateChecked();
}
focus(): void {
super.focus();
if (this.label) {
this.label.focus();
}
}
updateLabel(): void {
if (this.options.label && this.label) {
this.label.textContent = this.getAction().label;
}
}
updateTooltip(): void {
let title: string | null = null;
if (this.getAction().tooltip) {
title = this.getAction().tooltip;
} else if (!this.options.label && this.getAction().label && this.options.icon) {
title = this.getAction().label;
if (this.options.keybinding) {
title = nls.localize({ key: 'titleLabel', comment: ['action title', 'action keybinding'] }, "{0} ({1})", title, this.options.keybinding);
}
}
if (title && this.label) {
this.label.title = title;
}
}
updateClass(): void {
if (this.cssClass && this.label) {
DOM.removeClasses(this.label, this.cssClass);
}
if (this.options.icon) {
this.cssClass = this.getAction().class;
if (this.label) {
DOM.addClass(this.label, 'codicon');
if (this.cssClass) {
DOM.addClasses(this.label, this.cssClass);
}
}
this.updateEnabled();
} else {
if (this.label) {
DOM.removeClass(this.label, 'codicon');
}
}
}
updateEnabled(): void {
if (this.getAction().enabled) {
if (this.label) {
this.label.removeAttribute('aria-disabled');
DOM.removeClass(this.label, 'disabled');
this.label.tabIndex = 0;
}
if (this.element) {
DOM.removeClass(this.element, 'disabled');
}
} else {
if (this.label) {
this.label.setAttribute('aria-disabled', 'true');
DOM.addClass(this.label, 'disabled');
DOM.removeTabIndexAndUpdateFocus(this.label);
}
if (this.element) {
DOM.addClass(this.element, 'disabled');
}
}
}
updateChecked(): void {
if (this.label) {
if (this.getAction().checked) {
DOM.addClass(this.label, 'checked');
} else {
DOM.removeClass(this.label, 'checked');
}
}
}
}
import { IActionViewItemOptions, ActionViewItem, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export const enum ActionsOrientation {
HORIZONTAL,
@@ -393,41 +25,30 @@ export interface ActionTrigger {
keyDown: boolean;
}
export interface IActionViewItemProvider {
(action: IAction): IActionViewItem | undefined;
}
export interface IActionBarOptions {
orientation?: ActionsOrientation;
context?: any;
actionViewItemProvider?: IActionViewItemProvider;
actionRunner?: IActionRunner;
ariaLabel?: string;
animated?: boolean;
triggerKeys?: ActionTrigger;
allowContextMenu?: boolean;
preventLoopNavigation?: boolean;
readonly orientation?: ActionsOrientation;
readonly context?: any;
readonly actionViewItemProvider?: IActionViewItemProvider;
readonly actionRunner?: IActionRunner;
readonly ariaLabel?: string;
readonly animated?: boolean;
readonly triggerKeys?: ActionTrigger;
readonly allowContextMenu?: boolean;
readonly preventLoopNavigation?: boolean;
}
const defaultOptions: IActionBarOptions = {
orientation: ActionsOrientation.HORIZONTAL,
context: null,
triggerKeys: {
keys: [KeyCode.Enter, KeyCode.Space],
keyDown: false
}
};
export interface IActionOptions extends IActionViewItemOptions {
index?: number;
}
export class ActionBar extends Disposable implements IActionRunner {
options: IActionBarOptions;
private readonly options: IActionBarOptions;
private _actionRunner: IActionRunner;
private _context: unknown;
private _orientation: ActionsOrientation;
private _triggerKeys: ActionTrigger;
// View Items
viewItems: IActionViewItem[];
@@ -450,15 +71,16 @@ export class ActionBar extends Disposable implements IActionRunner {
private _onDidBeforeRun = this._register(new Emitter<IRunEvent>());
readonly onDidBeforeRun: Event<IRunEvent> = this._onDidBeforeRun.event;
constructor(container: HTMLElement, options: IActionBarOptions = defaultOptions) {
constructor(container: HTMLElement, options: IActionBarOptions = {}) {
super();
this.options = options;
this._context = options.context;
if (!this.options.triggerKeys) {
this.options.triggerKeys = defaultOptions.triggerKeys;
}
this._context = options.context ?? null;
this._orientation = this.options.orientation ?? ActionsOrientation.HORIZONTAL;
this._triggerKeys = this.options.triggerKeys ?? {
keys: [KeyCode.Enter, KeyCode.Space],
keyDown: false
};
if (this.options.actionRunner) {
this._actionRunner = this.options.actionRunner;
@@ -483,7 +105,7 @@ export class ActionBar extends Disposable implements IActionRunner {
let previousKey: KeyCode;
let nextKey: KeyCode;
switch (this.options.orientation) {
switch (this._orientation) {
case ActionsOrientation.HORIZONTAL:
previousKey = KeyCode.LeftArrow;
nextKey = KeyCode.RightArrow;
@@ -517,7 +139,7 @@ export class ActionBar extends Disposable implements IActionRunner {
this._onDidCancel.fire();
} else if (this.isTriggerKeyEvent(event)) {
// Staying out of the else branch even if not triggered
if (this.options.triggerKeys && this.options.triggerKeys.keyDown) {
if (this._triggerKeys.keyDown) {
this.doTrigger(event);
}
} else {
@@ -535,7 +157,7 @@ export class ActionBar extends Disposable implements IActionRunner {
// Run action on Enter/Space
if (this.isTriggerKeyEvent(event)) {
if (this.options.triggerKeys && !this.options.triggerKeys.keyDown) {
if (!this._triggerKeys.keyDown) {
this.doTrigger(event);
}
@@ -582,11 +204,9 @@ export class ActionBar extends Disposable implements IActionRunner {
private isTriggerKeyEvent(event: StandardKeyboardEvent): boolean {
let ret = false;
if (this.options.triggerKeys) {
this.options.triggerKeys.keys.forEach(keyCode => {
ret = ret || event.equals(keyCode);
});
}
this._triggerKeys.keys.forEach(keyCode => {
ret = ret || event.equals(keyCode);
});
return ret;
}
@@ -845,53 +465,6 @@ export class ActionBar extends Disposable implements IActionRunner {
}
}
export class SelectActionViewItem extends BaseActionViewItem {
protected selectBox: SelectBox;
constructor(ctx: unknown, action: IAction, options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, selectBoxOptions?: ISelectBoxOptions) {
super(ctx, action);
this.selectBox = new SelectBox(options, selected, contextViewProvider, undefined, selectBoxOptions);
this._register(this.selectBox);
this.registerListeners();
}
setOptions(options: ISelectOptionItem[], selected?: number): void {
this.selectBox.setOptions(options, selected);
}
select(index: number): void {
this.selectBox.select(index);
}
private registerListeners(): void {
this._register(this.selectBox.onDidSelect(e => {
this.actionRunner.run(this._action, this.getActionContext(e.selected, e.index));
}));
}
protected getActionContext(option: string, index: number) {
return option;
}
focus(): void {
if (this.selectBox) {
this.selectBox.focus();
}
}
blur(): void {
if (this.selectBox) {
this.selectBox.blur();
}
}
render(container: HTMLElement): void {
this.selectBox.render(container);
}
}
export function prepareActions(actions: IAction[]): IAction[] {
if (!actions.length) {
return actions;

View File

@@ -10,9 +10,9 @@ import { Widget } from 'vs/base/browser/ui/widget';
import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { Codicon } from 'vs/base/common/codicons';
import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export interface ICheckboxOpts extends ICheckboxStyles {
readonly actionClassName?: string;

View File

@@ -5,14 +5,13 @@
import 'vs/css!./dropdown';
import { Gesture, EventType as GestureEventType } from 'vs/base/browser/touch';
import { ActionRunner, IAction, IActionRunner } from 'vs/base/common/actions';
import { BaseActionViewItem, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionRunner, IAction } from 'vs/base/common/actions';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IContextViewProvider, IAnchor, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { IMenuOptions } from 'vs/base/browser/ui/menu/menu';
import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes';
import { EventHelper, EventType, removeClass, addClass, append, $, addDisposableListener, addClasses, DOMEvent } from 'vs/base/browser/dom';
import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
import { KeyCode } from 'vs/base/common/keyCodes';
import { EventHelper, EventType, removeClass, addClass, append, $, addDisposableListener, DOMEvent } from 'vs/base/browser/dom';
import { IContextMenuProvider } from 'vs/base/browser/contextmenu';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { Emitter } from 'vs/base/common/event';
@@ -201,17 +200,13 @@ export class Dropdown extends BaseDropdown {
}
}
export interface IContextMenuProvider {
showContextMenu(delegate: IContextMenuDelegate): void;
}
export interface IActionProvider {
getActions(): ReadonlyArray<IAction>;
getActions(): IAction[];
}
export interface IDropdownMenuOptions extends IBaseDropdownOptions {
contextMenuProvider: IContextMenuProvider;
actions?: ReadonlyArray<IAction>;
actions?: IAction[];
actionProvider?: IActionProvider;
menuClassName?: string;
menuAsChild?: boolean; // scope down for #99448
@@ -220,7 +215,7 @@ export interface IDropdownMenuOptions extends IBaseDropdownOptions {
export class DropdownMenu extends BaseDropdown {
private _contextMenuProvider: IContextMenuProvider;
private _menuOptions: IMenuOptions | undefined;
private _actions: ReadonlyArray<IAction> = [];
private _actions: IAction[] = [];
private actionProvider?: IActionProvider;
private menuClassName: string;
private menuAsChild?: boolean;
@@ -243,7 +238,7 @@ export class DropdownMenu extends BaseDropdown {
return this._menuOptions;
}
private get actions(): ReadonlyArray<IAction> {
private get actions(): IAction[] {
if (this.actionProvider) {
return this.actionProvider.getActions();
}
@@ -251,7 +246,7 @@ export class DropdownMenu extends BaseDropdown {
return this._actions;
}
private set actions(actions: ReadonlyArray<IAction>) {
private set actions(actions: IAction[]) {
this._actions = actions;
}
@@ -283,106 +278,3 @@ export class DropdownMenu extends BaseDropdown {
removeClass(this.element, 'active');
}
}
export class DropdownMenuActionViewItem extends BaseActionViewItem {
private menuActionsOrProvider: ReadonlyArray<IAction> | IActionProvider;
private dropdownMenu: DropdownMenu | undefined;
private contextMenuProvider: IContextMenuProvider;
private actionViewItemProvider?: IActionViewItemProvider;
private keybindings?: (action: IAction) => ResolvedKeybinding | undefined;
private clazz: string | undefined;
private anchorAlignmentProvider: (() => AnchorAlignment) | undefined;
private menuAsChild?: boolean;
private _onDidChangeVisibility = this._register(new Emitter<boolean>());
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
constructor(action: IAction, menuActions: ReadonlyArray<IAction>, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner | undefined, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner | undefined, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
constructor(action: IAction, menuActionsOrProvider: ReadonlyArray<IAction> | IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner | undefined, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean) {
super(null, action);
this.menuActionsOrProvider = menuActionsOrProvider;
this.contextMenuProvider = contextMenuProvider;
this.actionViewItemProvider = actionViewItemProvider;
if (actionRunner) {
this.actionRunner = actionRunner;
}
this.keybindings = keybindings;
this.clazz = clazz;
this.anchorAlignmentProvider = anchorAlignmentProvider;
this.menuAsChild = menuAsChild;
}
render(container: HTMLElement): void {
const labelRenderer: ILabelRenderer = (el: HTMLElement): IDisposable | null => {
this.element = append(el, $('a.action-label.codicon')); // todo@aeschli: remove codicon, should come through `this.clazz`
if (this.clazz) {
addClasses(this.element, this.clazz);
}
this.element.tabIndex = 0;
this.element.setAttribute('role', 'button');
this.element.setAttribute('aria-haspopup', 'true');
this.element.setAttribute('aria-expanded', 'false');
this.element.title = this._action.label || '';
return null;
};
const options: IDropdownMenuOptions = {
contextMenuProvider: this.contextMenuProvider,
labelRenderer: labelRenderer,
menuAsChild: this.menuAsChild
};
// Render the DropdownMenu around a simple action to toggle it
if (Array.isArray(this.menuActionsOrProvider)) {
options.actions = this.menuActionsOrProvider;
} else {
options.actionProvider = this.menuActionsOrProvider as IActionProvider;
}
this.dropdownMenu = this._register(new DropdownMenu(container, options));
this._register(this.dropdownMenu.onDidChangeVisibility(visible => {
this.element?.setAttribute('aria-expanded', `${visible}`);
this._onDidChangeVisibility.fire(visible);
}));
this.dropdownMenu.menuOptions = {
actionViewItemProvider: this.actionViewItemProvider,
actionRunner: this.actionRunner,
getKeyBinding: this.keybindings,
context: this._context
};
if (this.anchorAlignmentProvider) {
const that = this;
this.dropdownMenu.menuOptions = {
...this.dropdownMenu.menuOptions,
get anchorAlignment(): AnchorAlignment {
return that.anchorAlignmentProvider!();
}
};
}
}
setActionContext(newContext: unknown): void {
super.setActionContext(newContext);
if (this.dropdownMenu) {
if (this.dropdownMenu.menuOptions) {
this.dropdownMenu.menuOptions.context = newContext;
} else {
this.dropdownMenu.menuOptions = { context: newContext };
}
}
}
show(): void {
if (this.dropdownMenu) {
this.dropdownMenu.show();
}
}
}

View File

@@ -0,0 +1,136 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./dropdown';
import { IAction, IActionRunner, IActionViewItemProvider } from 'vs/base/common/actions';
import { IDisposable } from 'vs/base/common/lifecycle';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { append, $, addClasses } from 'vs/base/browser/dom';
import { Emitter } from 'vs/base/common/event';
import { BaseActionViewItem, IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { IActionProvider, DropdownMenu, IDropdownMenuOptions, ILabelRenderer } from 'vs/base/browser/ui/dropdown/dropdown';
import { IContextMenuProvider } from 'vs/base/browser/contextmenu';
import { asArray } from 'vs/base/common/arrays';
export interface IKeybindingProvider {
(action: IAction): ResolvedKeybinding | undefined;
}
export interface IAnchorAlignmentProvider {
(): AnchorAlignment;
}
export interface IDropdownMenuActionViewItemOptions extends IBaseActionViewItemOptions {
readonly actionViewItemProvider?: IActionViewItemProvider;
readonly keybindingProvider?: IKeybindingProvider;
readonly actionRunner?: IActionRunner;
readonly classNames?: string[] | string;
readonly anchorAlignmentProvider?: IAnchorAlignmentProvider;
readonly menuAsChild?: boolean;
}
export class DropdownMenuActionViewItem extends BaseActionViewItem {
private menuActionsOrProvider: readonly IAction[] | IActionProvider;
private dropdownMenu: DropdownMenu | undefined;
private contextMenuProvider: IContextMenuProvider;
private _onDidChangeVisibility = this._register(new Emitter<boolean>());
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
constructor(
action: IAction,
menuActionsOrProvider: readonly IAction[] | IActionProvider,
contextMenuProvider: IContextMenuProvider,
protected options: IDropdownMenuActionViewItemOptions = {}
) {
super(null, action, options);
this.menuActionsOrProvider = menuActionsOrProvider;
this.contextMenuProvider = contextMenuProvider;
if (this.options.actionRunner) {
this.actionRunner = this.options.actionRunner;
}
}
render(container: HTMLElement): void {
const labelRenderer: ILabelRenderer = (el: HTMLElement): IDisposable | null => {
this.element = append(el, $('a.action-label'));
const classNames = this.options.classNames ? asArray(this.options.classNames) : [];
// todo@aeschli: remove codicon, should come through `this.options.classNames`
if (!classNames.find(c => c === 'icon')) {
classNames.push('codicon');
}
addClasses(this.element, ...classNames);
this.element.tabIndex = 0;
this.element.setAttribute('role', 'button');
this.element.setAttribute('aria-haspopup', 'true');
this.element.setAttribute('aria-expanded', 'false');
this.element.title = this._action.label || '';
return null;
};
const options: IDropdownMenuOptions = {
contextMenuProvider: this.contextMenuProvider,
labelRenderer: labelRenderer,
menuAsChild: this.options.menuAsChild
};
// Render the DropdownMenu around a simple action to toggle it
if (Array.isArray(this.menuActionsOrProvider)) {
options.actions = this.menuActionsOrProvider;
} else {
options.actionProvider = this.menuActionsOrProvider as IActionProvider;
}
this.dropdownMenu = this._register(new DropdownMenu(container, options));
this._register(this.dropdownMenu.onDidChangeVisibility(visible => {
this.element?.setAttribute('aria-expanded', `${visible}`);
this._onDidChangeVisibility.fire(visible);
}));
this.dropdownMenu.menuOptions = {
actionViewItemProvider: this.options.actionViewItemProvider,
actionRunner: this.actionRunner,
getKeyBinding: this.options.keybindingProvider,
context: this._context
};
if (this.options.anchorAlignmentProvider) {
const that = this;
this.dropdownMenu.menuOptions = {
...this.dropdownMenu.menuOptions,
get anchorAlignment(): AnchorAlignment {
return that.options.anchorAlignmentProvider!();
}
};
}
}
setActionContext(newContext: unknown): void {
super.setActionContext(newContext);
if (this.dropdownMenu) {
if (this.dropdownMenu.menuOptions) {
this.dropdownMenu.menuOptions.context = newContext;
} else {
this.dropdownMenu.menuOptions = { context: newContext };
}
}
}
show(): void {
if (this.dropdownMenu) {
this.dropdownMenu.show();
}
}
}

View File

@@ -5,8 +5,8 @@
import * as nls from 'vs/nls';
import * as strings from 'vs/base/common/strings';
import { IActionRunner, IAction, Action } from 'vs/base/common/actions';
import { ActionBar, IActionViewItemProvider, ActionsOrientation, Separator, ActionViewItem, IActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IActionRunner, IAction, SubmenuAction, Separator, IActionViewItemProvider } from 'vs/base/common/actions';
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes';
import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses, clearNode, createStyleSheet, isInShadowDOM } from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
@@ -19,6 +19,7 @@ import { Event } from 'vs/base/common/event';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { isLinux, isMacintosh } from 'vs/base/common/platform';
import { Codicon, registerIcon, stripCodicons } from 'vs/base/common/codicons';
import { BaseActionViewItem, ActionViewItem, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { formatRule } from 'vs/base/browser/ui/codicons/codiconStyles';
export const MENU_MNEMONIC_REGEX = /\(&([^\s&])\)|(^|[^&])&([^\s&])/;
@@ -42,6 +43,7 @@ export interface IMenuOptions {
anchorAlignment?: AnchorAlignment;
expandDirection?: Direction;
useEventAsContext?: boolean;
submenuIds?: Set<string>;
}
export interface IMenuStyles {
@@ -55,12 +57,6 @@ export interface IMenuStyles {
separatorColor?: Color;
}
export class SubmenuAction extends Action {
constructor(label: string, public entries: ReadonlyArray<SubmenuAction | IAction>, cssClass?: string) {
super(!!cssClass ? cssClass : 'submenu', label, '', true);
}
}
interface ISubMenuData {
parent: Menu;
submenu?: Menu;
@@ -209,6 +205,15 @@ export class Menu extends ActionBar {
menuElement.style.maxHeight = `${Math.max(10, window.innerHeight - container.getBoundingClientRect().top - 30)}px`;
actions = actions.filter(a => {
if (options.submenuIds?.has(a.id)) {
console.warn(`Found submenu cycle: ${a.id}`);
return false;
}
return true;
});
this.push(actions, { icon: true, label: true, isMenu: true });
container.appendChild(this.scrollableElement.getDomNode());
@@ -317,7 +322,8 @@ export class Menu extends ActionBar {
if (action instanceof Separator) {
return new MenuSeparatorActionViewItem(options.context, action, { icon: true });
} else if (action instanceof SubmenuAction) {
const menuActionViewItem = new SubmenuMenuActionViewItem(action, action.entries, parentData, options);
const actions = Array.isArray(action.actions) ? action.actions : action.actions();
const menuActionViewItem = new SubmenuMenuActionViewItem(action, actions, parentData, { ...options, submenuIds: new Set([...(options.submenuIds || []), action.id]) });
if (options.enableMnemonics) {
const mnemonic = menuActionViewItem.getMnemonic();

View File

@@ -11,8 +11,8 @@ import * as nls from 'vs/nls';
import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch';
import { cleanMnemonic, IMenuOptions, Menu, MENU_ESCAPED_MNEMONIC_REGEX, MENU_MNEMONIC_REGEX, SubmenuAction, IMenuStyles, Direction } from 'vs/base/browser/ui/menu/menu';
import { ActionRunner, IAction, IActionRunner } from 'vs/base/common/actions';
import { cleanMnemonic, IMenuOptions, Menu, MENU_ESCAPED_MNEMONIC_REGEX, MENU_MNEMONIC_REGEX, IMenuStyles, Direction } from 'vs/base/browser/ui/menu/menu';
import { ActionRunner, IAction, IActionRunner, SubmenuAction, Separator } from 'vs/base/common/actions';
import { RunOnceScheduler } from 'vs/base/common/async';
import { Event, Emitter } from 'vs/base/common/event';
import { KeyCode, ResolvedKeybinding, KeyMod } from 'vs/base/common/keyCodes';
@@ -22,7 +22,6 @@ import { asArray } from 'vs/base/common/arrays';
import { ScanCodeUtils, ScanCode } from 'vs/base/common/scanCode';
import { isMacintosh } from 'vs/base/common/platform';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
const $ = DOM.$;
@@ -40,7 +39,7 @@ export interface IMenuBarOptions {
}
export interface MenuBarMenu {
actions: ReadonlyArray<IAction>;
actions: IAction[];
label: string;
}
@@ -59,7 +58,7 @@ export class MenuBar extends Disposable {
buttonElement: HTMLElement;
titleElement: HTMLElement;
label: string;
actions?: ReadonlyArray<IAction>;
actions?: IAction[];
}[];
private overflowMenu!: {
@@ -506,7 +505,7 @@ export class MenuBar extends Disposable {
this.overflowMenu.actions = [];
for (let idx = this.numMenusShown; idx < this.menuCache.length; idx++) {
this.overflowMenu.actions.push(new SubmenuAction(this.menuCache[idx].label, this.menuCache[idx].actions || []));
this.overflowMenu.actions.push(new SubmenuAction(`menubar.submenu.${this.menuCache[idx].label}`, this.menuCache[idx].label, this.menuCache[idx].actions || []));
}
if (this.overflowMenu.buttonElement.nextElementSibling !== this.menuCache[this.numMenusShown].buttonElement) {

View File

@@ -5,17 +5,16 @@
import 'vs/css!./toolbar';
import * as nls from 'vs/nls';
import { Action, IActionRunner, IAction } from 'vs/base/common/actions';
import { ActionBar, ActionsOrientation, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
import { IContextMenuProvider, DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
import { Action, IActionRunner, IAction, IActionViewItemProvider, SubmenuAction } from 'vs/base/common/actions';
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { Disposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { withNullAsUndefined } from 'vs/base/common/types';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
import { Emitter } from 'vs/base/common/event';
export const CONTEXT = 'context.toolbar';
import { EventMultiplexer } from 'vs/base/common/event';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
import { IContextMenuProvider } from 'vs/base/browser/contextmenu';
const toolBarMoreIcon = registerIcon('toolbar-more', Codicon.more);
@@ -37,12 +36,13 @@ export class ToolBar extends Disposable {
private actionBar: ActionBar;
private toggleMenuAction: ToggleMenuAction;
private toggleMenuActionViewItem: DropdownMenuActionViewItem | undefined;
private toggleMenuActionViewItemDisposable: IDisposable = Disposable.None;
private submenuActionViewItems: DropdownMenuActionViewItem[] = [];
private hasSecondaryActions: boolean = false;
private lookupKeybindings: boolean;
private _onDidChangeDropdownVisibility = this._register(new Emitter<boolean>());
private _onDidChangeDropdownVisibility = this._register(new EventMultiplexer<boolean>());
readonly onDidChangeDropdownVisibility = this._onDidChangeDropdownVisibility.event;
private disposables = new DisposableStore();
constructor(container: HTMLElement, contextMenuProvider: IContextMenuProvider, options: IToolBarOptions = { orientation: ActionsOrientation.HORIZONTAL }) {
super();
@@ -61,35 +61,57 @@ export class ToolBar extends Disposable {
ariaLabel: options.ariaLabel,
actionRunner: options.actionRunner,
actionViewItemProvider: (action: IAction) => {
// Return special action item for the toggle menu action
if (action.id === ToggleMenuAction.ID) {
this.toggleMenuActionViewItemDisposable.dispose();
// Create new
this.toggleMenuActionViewItem = new DropdownMenuActionViewItem(
action,
(<ToggleMenuAction>action).menuActions,
contextMenuProvider,
this.options.actionViewItemProvider,
this.actionRunner,
this.options.getKeyBinding,
toolBarMoreIcon.classNames,
this.options.anchorAlignmentProvider,
true
{
actionViewItemProvider: this.options.actionViewItemProvider,
actionRunner: this.actionRunner,
keybindingProvider: this.options.getKeyBinding,
classNames: toolBarMoreIcon.classNames,
anchorAlignmentProvider: this.options.anchorAlignmentProvider,
menuAsChild: true
}
);
this.toggleMenuActionViewItem.setActionContext(this.actionBar.context);
this.toggleMenuActionViewItemDisposable = combinedDisposable(
this.toggleMenuActionViewItem,
this.toggleMenuActionViewItem.onDidChangeVisibility(e => this._onDidChangeDropdownVisibility.fire(e))
);
this.disposables.add(this._onDidChangeDropdownVisibility.add(this.toggleMenuActionViewItem.onDidChangeVisibility));
return this.toggleMenuActionViewItem;
}
return options.actionViewItemProvider ? options.actionViewItemProvider(action) : undefined;
if (options.actionViewItemProvider) {
const result = options.actionViewItemProvider(action);
if (result) {
return result;
}
}
if (action instanceof SubmenuAction) {
const actions = Array.isArray(action.actions) ? action.actions : action.actions();
const result = new DropdownMenuActionViewItem(
action,
actions,
contextMenuProvider,
{
actionViewItemProvider: this.options.actionViewItemProvider,
actionRunner: this.actionRunner,
keybindingProvider: this.options.getKeyBinding,
classNames: action.class,
anchorAlignmentProvider: this.options.anchorAlignmentProvider,
menuAsChild: true
}
);
result.setActionContext(this.actionBar.context);
this.submenuActionViewItems.push(result);
this.disposables.add(this._onDidChangeDropdownVisibility.add(result.onDidChangeVisibility));
return result;
}
return undefined;
}
}));
}
@@ -107,6 +129,9 @@ export class ToolBar extends Disposable {
if (this.toggleMenuActionViewItem) {
this.toggleMenuActionViewItem.setActionContext(context);
}
for (const actionViewItem of this.submenuActionViewItems) {
actionViewItem.setActionContext(context);
}
}
getContainer(): HTMLElement {
@@ -126,6 +151,8 @@ export class ToolBar extends Disposable {
}
setActions(primaryActions: ReadonlyArray<IAction>, secondaryActions?: ReadonlyArray<IAction>): void {
this.clear();
let primaryActionsToSet = primaryActions ? primaryActions.slice(0) : [];
// Inject additional action to open secondary actions if present
@@ -135,8 +162,6 @@ export class ToolBar extends Disposable {
primaryActionsToSet.push(this.toggleMenuAction);
}
this.actionBar.clear();
primaryActionsToSet.forEach(action => {
this.actionBar.push(action, { icon: true, label: false, keybinding: this.getKeybindingLabel(action) });
});
@@ -148,25 +173,15 @@ export class ToolBar extends Disposable {
return withNullAsUndefined(key?.getLabel());
}
addPrimaryAction(primaryAction: IAction): () => void {
return () => {
// Add after the "..." action if we have secondary actions
if (this.hasSecondaryActions) {
let itemCount = this.actionBar.length();
this.actionBar.push(primaryAction, { icon: true, label: false, index: itemCount, keybinding: this.getKeybindingLabel(primaryAction) });
}
// Otherwise just add to the end
else {
this.actionBar.push(primaryAction, { icon: true, label: false, keybinding: this.getKeybindingLabel(primaryAction) });
}
};
private clear(): void {
this.submenuActionViewItems = [];
this.disposables.clear();
this.actionBar.clear();
}
dispose(): void {
this.clear();
super.dispose();
this.toggleMenuActionViewItemDisposable.dispose();
}
}

View File

@@ -39,14 +39,18 @@ export interface IActionRunner extends IDisposable {
}
export interface IActionViewItem extends IDisposable {
readonly actionRunner: IActionRunner;
actionRunner: IActionRunner;
setActionContext(context: any): void;
render(element: any /* HTMLElement */): void;
isEnabled(): boolean;
focus(): void;
focus(fromRight?: boolean): void; // TODO@isidorn what is this?
blur(): void;
}
export interface IActionViewItemProvider {
(action: IAction): IActionViewItem | undefined;
}
export interface IActionChangeEvent {
readonly label?: string;
readonly tooltip?: string;
@@ -218,3 +222,22 @@ export class RadioGroup extends Disposable {
}
}
}
export class Separator extends Action {
static readonly ID = 'vs.actions.separator';
constructor(label?: string) {
super(Separator.ID, label, label ? 'separator text' : 'separator');
this.checked = false;
this.enabled = false;
}
}
export type SubmenuActions = IAction[] | (() => IAction[]);
export class SubmenuAction extends Action {
constructor(id: string, label: string, readonly actions: SubmenuActions, cssClass?: string) {
super(id, label, cssClass, true);
}
}

View File

@@ -473,11 +473,10 @@ export function range(arg: number, to?: number): number[] {
}
export function index<T>(array: ReadonlyArray<T>, indexer: (t: T) => string): { [key: string]: T; };
export function index<T, R>(array: ReadonlyArray<T>, indexer: (t: T) => string, merger?: (t: T, r: R) => R): { [key: string]: R; };
export function index<T, R>(array: ReadonlyArray<T>, indexer: (t: T) => string, merger: (t: T, r: R) => R = t => t as any): { [key: string]: R; } {
export function index<T, R>(array: ReadonlyArray<T>, indexer: (t: T) => string, mapper: (t: T) => R): { [key: string]: R; };
export function index<T, R>(array: ReadonlyArray<T>, indexer: (t: T) => string, mapper?: (t: T) => R): { [key: string]: R; } {
return array.reduce((r, t) => {
const key = indexer(t);
r[key] = merger(t, r[key]);
r[indexer(t)] = mapper ? mapper(t) : t;
return r;
}, Object.create(null));
}

View File

@@ -18,7 +18,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { Button, IButtonStyles } from 'vs/base/browser/ui/button/button';
import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import { ActionBar, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions';
import { equals } from 'vs/base/common/arrays';
import { TimeoutTimer } from 'vs/base/common/async';
@@ -28,6 +28,7 @@ import { List, IListOptions, IListStyles } from 'vs/base/browser/ui/list/listWid
import { IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox';
import { Color } from 'vs/base/common/color';
import { registerIcon, Codicon } from 'vs/base/common/codicons';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export interface IQuickInputOptions {
idPrefix: string;

View File

@@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { Separator, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions';
import { prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, Separator } from 'vs/base/common/actions';
suite('Actionbar', () => {

View File

@@ -22,9 +22,8 @@ exports.collectModules = function () {
createModuleDescription('vs/code/electron-main/main', []),
createModuleDescription('vs/code/node/cli', []),
createModuleDescription('vs/code/node/cliProcessMain', ['vs/code/node/cli']),
createModuleDescription('vs/code/electron-browser/issue/issueReporterMain', []),
createModuleDescription('vs/code/electron-sandbox/issue/issueReporterMain', []),
createModuleDescription('vs/code/electron-browser/sharedProcess/sharedProcessMain', []),
createModuleDescription('vs/code/electron-browser/issue/issueReporterMain', []),
createModuleDescription('vs/platform/driver/node/driver', []),
createModuleDescription('vs/code/electron-sandbox/processExplorer/processExplorerMain', [])
];

View File

@@ -14,6 +14,6 @@ const bootstrapWindow = (() => {
return window.MonacoBootstrapWindow;
})();
bootstrapWindow.load(['vs/code/electron-browser/issue/issueReporterMain'], function (issueReporter, configuration) {
bootstrapWindow.load(['vs/code/electron-sandbox/issue/issueReporterMain'], function (issueReporter, configuration) {
issueReporter.startup(configuration);
}, { forceEnableDeveloperKeybindings: true, disallowReloadKeybinding: true });

View File

@@ -5,9 +5,8 @@
import 'vs/css!./media/issueReporter';
import 'vs/base/browser/ui/codicons/codiconStyles'; // make sure codicon css is loaded
import * as os from 'os';
import { ElectronService, IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import { ipcRenderer, process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import { applyZoom, zoomIn, zoomOut } from 'vs/platform/windows/electron-sandbox/window';
import { $, windowOpenNoOpener, addClass } from 'vs/base/browser/dom';
import { Button } from 'vs/base/browser/ui/button/button';
@@ -17,29 +16,15 @@ import { debounce } from 'vs/base/common/decorators';
import { Disposable } from 'vs/base/common/lifecycle';
import * as platform from 'vs/base/common/platform';
import { escape } from 'vs/base/common/strings';
import { getDelayedChannel, createChannelSender } from 'vs/base/parts/ipc/common/ipc';
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
import { normalizeGitHubUrl } from 'vs/platform/issue/common/issueReporterUtil';
import { IssueReporterData as IssueReporterModelData, IssueReporterModel } from 'vs/code/electron-browser/issue/issueReporterModel';
import BaseHtml from 'vs/code/electron-browser/issue/issueReporterPage';
import { IssueReporterData as IssueReporterModelData, IssueReporterModel } from 'vs/code/electron-sandbox/issue/issueReporterModel';
import BaseHtml from 'vs/code/electron-sandbox/issue/issueReporterPage';
import { localize } from 'vs/nls';
import { isRemoteDiagnosticError, SystemInfo } from 'vs/platform/diagnostics/common/diagnostics';
import { EnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IMainProcessService, MainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { ISettingsSearchIssueReporterData, IssueReporterData, IssueReporterExtensionData, IssueReporterFeatures, IssueReporterStyles, IssueType } from 'vs/platform/issue/common/issue';
import { getLogLevel, ILogService } from 'vs/platform/log/common/log';
import { FollowerLogService, LoggerChannelClient } from 'vs/platform/log/common/logIpc';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import product from 'vs/platform/product/common/product';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { combinedAppender, LogAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc';
import { INativeWindowConfiguration } from 'vs/platform/windows/node/window';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
const MAX_URL_LENGTH = 2045;
@@ -49,9 +34,23 @@ interface SearchResult {
state?: string;
}
export interface IssueReporterConfiguration extends INativeWindowConfiguration {
export interface IssueReporterConfiguration extends IWindowConfiguration {
windowId: number;
disableExtensions: boolean;
data: IssueReporterData;
features: IssueReporterFeatures;
os: {
type: string;
arch: string;
release: string;
},
product: {
nameShort: string;
version: string;
commit: string | undefined;
date: string | undefined;
reportIssueUrl: string | undefined;
}
}
export function startup(configuration: IssueReporterConfiguration) {
@@ -66,10 +65,7 @@ export function startup(configuration: IssueReporterConfiguration) {
}
export class IssueReporter extends Disposable {
private environmentService!: INativeEnvironmentService;
private electronService!: IElectronService;
private telemetryService!: ITelemetryService;
private logService!: ILogService;
private readonly issueReporterModel: IssueReporterModel;
private numberOfSearchResultsDisplayed = 0;
private receivedSystemInfo = false;
@@ -79,7 +75,7 @@ export class IssueReporter extends Disposable {
private readonly previewButton!: Button;
constructor(configuration: IssueReporterConfiguration) {
constructor(private readonly configuration: IssueReporterConfiguration) {
super();
this.initServices(configuration);
@@ -90,10 +86,10 @@ export class IssueReporter extends Disposable {
this.issueReporterModel = new IssueReporterModel({
issueType: configuration.data.issueType || IssueType.Bug,
versionInfo: {
vscodeVersion: `${product.nameShort} ${product.version} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})`,
os: `${os.type()} ${os.arch()} ${os.release()}${isSnap ? ' snap' : ''}`
vscodeVersion: `${configuration.product.nameShort} ${configuration.product.version} (${configuration.product.commit || 'Commit unknown'}, ${configuration.product.date || 'Date unknown'})`,
os: `${this.configuration.os.type} ${this.configuration.os.arch} ${this.configuration.os.release}${isSnap ? ' snap' : ''}`
},
extensionsDisabled: !!this.environmentService.disableExtensions,
extensionsDisabled: !!configuration.disableExtensions,
fileOnExtension: configuration.data.extensionId ? !targetExtension?.isBuiltin : undefined,
selectedExtension: targetExtension,
});
@@ -121,7 +117,6 @@ export class IssueReporter extends Disposable {
}
ipcRenderer.on('vscode:issuePerformanceInfoResponse', (_: unknown, info: Partial<IssueReporterData>) => {
this.logService.trace('issueReporter: Received performance data');
this.issueReporterModel.update(info);
this.receivedPerformanceInfo = true;
@@ -132,7 +127,6 @@ export class IssueReporter extends Disposable {
});
ipcRenderer.on('vscode:issueSystemInfoResponse', (_: unknown, info: SystemInfo) => {
this.logService.trace('issueReporter: Received system data');
this.issueReporterModel.update({ systemInfo: info });
this.receivedSystemInfo = true;
@@ -144,7 +138,6 @@ export class IssueReporter extends Disposable {
if (configuration.data.issueType === IssueType.PerformanceIssue) {
ipcRenderer.send('vscode:issuePerformanceInfoRequest');
}
this.logService.trace('issueReporter: Sent data requests');
if (window.document.documentElement.lang !== 'en') {
show(this.getElementById('english'));
@@ -266,7 +259,7 @@ export class IssueReporter extends Disposable {
this.issueReporterModel.update({ numberOfThemeExtesions, enabledNonThemeExtesions: nonThemes, allExtensions: installedExtensions });
this.updateExtensionTable(nonThemes, numberOfThemeExtesions);
if (this.environmentService.disableExtensions || installedExtensions.length === 0) {
if (this.configuration.disableExtensions || installedExtensions.length === 0) {
(<HTMLButtonElement>this.getElementById('disableExtensions')).disabled = true;
}
@@ -314,40 +307,13 @@ export class IssueReporter extends Disposable {
}
}
private initServices(configuration: INativeWindowConfiguration): void {
private initServices(configuration: IssueReporterConfiguration): void {
const serviceCollection = new ServiceCollection();
const mainProcessService = new MainProcessService(configuration.windowId);
serviceCollection.set(IMainProcessService, mainProcessService);
this.electronService = new ElectronService(configuration.windowId, mainProcessService) as IElectronService;
serviceCollection.set(IElectronService, this.electronService);
this.environmentService = new EnvironmentService(configuration, configuration.execPath);
const logService = new SpdLogService(`issuereporter${configuration.windowId}`, this.environmentService.logsPath, getLogLevel(this.environmentService));
const loggerClient = new LoggerChannelClient(mainProcessService.getChannel('logger'));
this.logService = new FollowerLogService(loggerClient, logService);
const sharedProcessService = createChannelSender<ISharedProcessService>(mainProcessService.getChannel('sharedProcess'));
const sharedProcess = sharedProcessService.whenSharedProcessReady()
.then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${configuration.windowId}`));
const instantiationService = new InstantiationService(serviceCollection, true);
if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender')));
const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService));
const commonProperties = resolveCommonProperties(product.commit || 'Commit unknown', product.version, configuration.machineId, product.msftInternalDomains, this.environmentService.installSourcePath);
const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot];
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, sendErrorTelemetry: true };
const telemetryService = instantiationService.createInstance(TelemetryService, config);
this._register(telemetryService);
this.telemetryService = telemetryService;
} else {
this.telemetryService = NullTelemetryService;
}
}
private setEventHandlers(): void {
@@ -617,11 +583,11 @@ export class IssueReporter extends Disposable {
}, timeToWait * 1000);
}
}
}).catch(e => {
this.logSearchError(e);
}).catch(_ => {
// Ignore
});
}).catch(e => {
this.logSearchError(e);
}).catch(_ => {
// Ignore
});
}
@@ -648,11 +614,11 @@ export class IssueReporter extends Disposable {
} else {
throw new Error('Unexpected response, no candidates property');
}
}).catch((error) => {
this.logSearchError(error);
}).catch(_ => {
// Ignore
});
}).catch((error) => {
this.logSearchError(error);
}).catch(_ => {
// Ignore
});
}
@@ -705,18 +671,6 @@ export class IssueReporter extends Disposable {
}
}
private logSearchError(error: Error) {
this.logService.warn('issueReporter#search ', error.message);
type IssueReporterSearchErrorClassification = {
message: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' }
};
type IssueReporterSearchError = {
message: string;
};
this.telemetryService.publicLogError2<IssueReporterSearchError, IssueReporterSearchErrorClassification>('issueReporterSearchError', { message: error.message });
}
private setUpTypes(): void {
const makeOption = (issueType: IssueType, description: string) => `<option value="${issueType.valueOf()}">${escape(description)}</option>`;
@@ -910,15 +864,6 @@ export class IssueReporter extends Disposable {
return false;
}
type IssueReporterSubmitClassification = {
issueType: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
numSimilarIssuesDisplayed: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
};
type IssueReporterSubmitEvent = {
issueType: any;
numSimilarIssuesDisplayed: number;
};
this.telemetryService.publicLog2<IssueReporterSubmitEvent, IssueReporterSubmitClassification>('issueReporterSubmit', { issueType: this.issueReporterModel.getData().issueType, numSimilarIssuesDisplayed: this.numberOfSearchResultsDisplayed });
this.hasBeenSubmitted = true;
const baseUrl = this.getIssueUrlWithTitle((<HTMLInputElement>this.getElementById('issue-title')).value);
@@ -967,7 +912,7 @@ export class IssueReporter extends Disposable {
}
private getIssueUrlWithTitle(issueTitle: string): string {
let repositoryUrl = product.reportIssueUrl;
let repositoryUrl = this.configuration.product.reportIssueUrl;
if (this.issueReporterModel.fileOnExtension()) {
const extensionGitHubUrl = this.getExtensionGitHubUrl();
if (extensionGitHubUrl) {
@@ -975,7 +920,7 @@ export class IssueReporter extends Disposable {
}
}
const queryStringPrefix = product.reportIssueUrl && product.reportIssueUrl.indexOf('?') === -1 ? '?' : '&';
const queryStringPrefix = this.configuration.product.reportIssueUrl && this.configuration.product.reportIssueUrl.indexOf('?') === -1 ? '?' : '&';
return `${repositoryUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`;
}
@@ -1136,7 +1081,7 @@ export class IssueReporter extends Disposable {
private updateExtensionTable(extensions: IssueReporterExtensionData[], numThemeExtensions: number): void {
const target = document.querySelector('.block-extensions .block-info');
if (target) {
if (this.environmentService.disableExtensions) {
if (this.configuration.disableExtensions) {
target.innerHTML = localize('disabledExtensions', "Extensions are disabled");
return;
}
@@ -1193,7 +1138,6 @@ export class IssueReporter extends Disposable {
// Exclude right click
if (event.which < 3) {
windowOpenNoOpener((<HTMLAnchorElement>event.target).href);
this.telemetryService.publicLog2('issueReporterViewSimilarIssue');
}
}

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { assign } from 'vs/base/common/objects';
import { IssueType, ISettingSearchResult, IssueReporterExtensionData } from 'vs/platform/issue/common/issue';
import { SystemInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
@@ -49,7 +48,7 @@ export class IssueReporterModel {
allExtensions: []
};
this._data = initialData ? assign(defaultData, initialData) : defaultData;
this._data = initialData ? Object.assign(defaultData, initialData) : defaultData;
}
getData(): IssueReporterData {
@@ -57,7 +56,7 @@ export class IssueReporterModel {
}
update(newData: Partial<IssueReporterData>): void {
assign(this._data, newData);
Object.assign(this._data, newData);
}
// {{SQL CARBON EDIT}}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { IssueReporterModel } from 'vs/code/electron-browser/issue/issueReporterModel';
import { IssueReporterModel } from 'vs/code/electron-sandbox/issue/issueReporterModel';
import { normalizeGitHubUrl } from 'vs/platform/issue/common/issueReporterUtil';
import { IssueType } from 'vs/platform/issue/common/issue';

View File

@@ -4,9 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { getDomNodePagePosition } from 'vs/base/browser/dom';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAnchor } from 'vs/base/browser/ui/contextview/contextview';
import { Action, IAction } from 'vs/base/common/actions';
import { Action, IAction, Separator } from 'vs/base/common/actions';
import { canceled } from 'vs/base/common/errors';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { Lazy } from 'vs/base/common/lazy';

View File

@@ -6,9 +6,8 @@
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { ActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAnchor } from 'vs/base/browser/ui/contextview/contextview';
import { IAction } from 'vs/base/common/actions';
import { IAction, Separator, SubmenuAction } from 'vs/base/common/actions';
import { KeyCode, KeyMod, ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
@@ -23,7 +22,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
import { ITextModel } from 'vs/editor/common/model';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export class ContextMenuController implements IEditorContribution {
@@ -153,7 +152,7 @@ export class ContextMenuController implements IEditorContribution {
if (action instanceof SubmenuItemAction) {
const subActions = this._getMenuActions(model, action.item.submenu);
if (subActions.length > 0) {
result.push(new ContextSubMenu(action.label, subActions));
result.push(new SubmenuAction(action.id, action.label, subActions));
addedItems++;
}
} else {
@@ -174,7 +173,7 @@ export class ContextMenuController implements IEditorContribution {
return result;
}
private _doShowContextMenu(actions: ReadonlyArray<IAction>, anchor: IAnchor | null = null): void {
private _doShowContextMenu(actions: IAction[], anchor: IAnchor | null = null): void {
if (!this._editor.hasModel()) {
return;
}

View File

@@ -26,9 +26,9 @@ import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/action
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
import { MenuId, IMenuService } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { createAndFillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
class MessageWidget {
@@ -246,10 +246,10 @@ export class MarkerNavigationWidget extends PeekViewWidget {
@IThemeService private readonly _themeService: IThemeService,
@IOpenerService private readonly _openerService: IOpenerService,
@IMenuService private readonly _menuService: IMenuService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IInstantiationService instantiationService: IInstantiationService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService
) {
super(editor, { showArrow: true, showFrame: true, isAccessible: true });
super(editor, { showArrow: true, showFrame: true, isAccessible: true }, instantiationService);
this._severity = MarkerSeverity.Warning;
this._backgroundColor = Color.white;
@@ -311,8 +311,8 @@ export class MarkerNavigationWidget extends PeekViewWidget {
protected _getActionBarOptions(): IActionBarOptions {
return {
orientation: ActionsOrientation.HORIZONTAL,
actionViewItemProvider: action => action instanceof MenuItemAction ? this._instantiationService.createInstance(MenuEntryActionViewItem, action) : undefined
...super._getActionBarOptions(),
orientation: ActionsOrientation.HORIZONTAL
};
}

View File

@@ -220,7 +220,7 @@ export class ReferenceWidget extends peekView.PeekViewWidget {
@ILabelService private readonly _uriLabel: ILabelService,
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService,
) {
super(editor, { showFrame: false, showArrow: true, isResizeable: true, isAccessible: true });
super(editor, { showFrame: false, showArrow: true, isResizeable: true, isAccessible: true }, _instantiationService);
this._applyTheme(themeService.getColorTheme());
this._callOnDispose.add(themeService.onDidColorThemeChange(this._applyTheme.bind(this)));

View File

@@ -18,7 +18,7 @@ import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeE
import { IOptions, IStyles, ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
import * as nls from 'vs/nls';
import { RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ServicesAccessor, createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable } from 'vs/base/common/lifecycle';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
@@ -26,7 +26,8 @@ import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { registerColor, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { Codicon } from 'vs/base/common/codicons';
import { MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
export const IPeekViewService = createDecorator<IPeekViewService>('IPeekViewService');
export interface IPeekViewService {
@@ -115,7 +116,11 @@ export abstract class PeekViewWidget extends ZoneWidget {
protected _actionbarWidget?: ActionBar;
protected _bodyElement?: HTMLDivElement;
constructor(editor: ICodeEditor, options: IPeekViewOptions = {}) {
constructor(
editor: ICodeEditor,
options: IPeekViewOptions,
@IInstantiationService protected readonly instantiationService: IInstantiationService
) {
super(editor, options);
objects.mixin(this.options, defaultOptions, false);
}
@@ -199,7 +204,17 @@ export abstract class PeekViewWidget extends ZoneWidget {
}
protected _getActionBarOptions(): IActionBarOptions {
return {};
return {
actionViewItemProvider: action => {
if (action instanceof MenuItemAction) {
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
} else if (action instanceof SubmenuItemAction) {
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
}
return undefined;
}
};
}
protected _onTitleClick(event: IMouseEvent): void {

View File

@@ -43,9 +43,10 @@ import { MarkdownString } from 'vs/base/common/htmlContent';
import { flatten, isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMenuService } from 'vs/platform/actions/common/actions';
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction } from 'vs/base/common/actions';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, IActionViewItemProvider } from 'vs/base/common/actions';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
const expandSuggestionDocsByDefault = false;

View File

@@ -552,6 +552,9 @@ export class StandaloneTelemetryService implements ITelemetryService {
public setEnabled(value: boolean): void {
}
public setExperimentProperty(name: string, value: string): void {
}
public publicLog(eventName: string, data?: any): Promise<void> {
return Promise.resolve(undefined);
}

View File

@@ -5,8 +5,7 @@
import { addClasses, createCSSRule, removeClasses, asCSSUrl } from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event';
import { ActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction } from 'vs/base/common/actions';
import { IAction, Separator } from 'vs/base/common/actions';
import { Emitter } from 'vs/base/common/event';
import { IdGenerator } from 'vs/base/common/idGenerator';
import { IDisposable, toDisposable, MutableDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
@@ -17,6 +16,8 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
// The alternative key on all platforms is alt. On windows we also support shift as an alternative key #44136
class AlternativeKeyEmitter extends Emitter<boolean> {
@@ -125,19 +126,11 @@ export function fillInActions(groups: ReadonlyArray<[string, ReadonlyArray<MenuI
}
}
export function createActionViewItem(action: IAction, keybindingService: IKeybindingService, notificationService: INotificationService, contextMenuService: IContextMenuService): ActionViewItem | undefined {
if (action instanceof MenuItemAction) {
return new MenuEntryActionViewItem(action, keybindingService, notificationService, contextMenuService);
}
return undefined;
}
const ids = new IdGenerator('menu-item-action-item-icon-');
export class MenuEntryActionViewItem extends ActionViewItem {
const ICON_PATH_TO_CSS_RULES = new Map<string /* path*/, string /* CSS rule */>();
static readonly ICON_PATH_TO_CSS_RULES: Map<string /* path*/, string /* CSS rule */> = new Map<string, string>();
export class MenuEntryActionViewItem extends ActionViewItem {
private _wantsAltCommand: boolean = false;
private readonly _itemClassDispose = this._register(new MutableDisposable());
@@ -165,7 +158,7 @@ export class MenuEntryActionViewItem extends ActionViewItem {
this._altKey.suppressAltKeyUp();
}
this.actionRunner.run(this._commandAction)
this.actionRunner.run(this._commandAction, this._context)
.then(undefined, err => this._notificationService.error(err));
}
@@ -236,7 +229,7 @@ export class MenuEntryActionViewItem extends ActionViewItem {
}
}
_updateItemClass(item: ICommandAction): void {
protected _updateItemClass(item: ICommandAction): void { // {{SQL CARBON EDIT}} make it overwritable
this._itemClassDispose.value = undefined;
const icon = this._commandAction.checked && (item.toggled as { icon?: Icon })?.icon ? (item.toggled as { icon: Icon }).icon : item.icon;
@@ -257,17 +250,17 @@ export class MenuEntryActionViewItem extends ActionViewItem {
// icon path
let iconClass: string;
if (icon?.dark?.scheme) {
if (icon.dark?.scheme) {
const iconPathMapKey = icon.dark.toString();
if (MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
iconClass = MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
if (ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
iconClass = ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
} else {
iconClass = ids.nextId();
createCSSRule(`.icon.${iconClass}`, `background-image: ${asCSSUrl(icon.light || icon.dark)}`);
createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: ${asCSSUrl(icon.dark)}`);
MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
}
if (this.label) {
@@ -284,17 +277,34 @@ export class MenuEntryActionViewItem extends ActionViewItem {
}
}
// Need to subclass MenuEntryActionViewItem in order to respect
// the action context coming from any action bar, without breaking
// existing users
export class ContextAwareMenuEntryActionViewItem extends MenuEntryActionViewItem {
export class SubmenuEntryActionViewItem extends DropdownMenuActionViewItem {
onClick(event: MouseEvent): void {
event.preventDefault();
event.stopPropagation();
constructor(
action: SubmenuItemAction,
@INotificationService _notificationService: INotificationService,
@IContextMenuService _contextMenuService: IContextMenuService
) {
const classNames: string[] = [];
this.actionRunner.run(this._commandAction, this._context)
.then(undefined, err => this._notificationService.error(err));
if (action.item.icon) {
if (ThemeIcon.isThemeIcon(action.item.icon)) {
classNames.push(ThemeIcon.asClassName(action.item.icon)!);
} else if (action.item.icon.dark?.scheme) {
const iconPathMapKey = action.item.icon.dark.toString();
if (ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
classNames.push('icon', ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!);
} else {
const className = ids.nextId();
classNames.push('icon', className);
createCSSRule(`.icon.${className}`, `background-image: ${asCSSUrl(action.item.icon.light || action.item.icon.dark)}`);
createCSSRule(`.vs-dark .icon.${className}, .hc-black .icon.${className}`, `background-image: ${asCSSUrl(action.item.icon.dark)}`);
ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, className);
}
}
}
super(action, Array.isArray(action.actions) ? action.actions : action.actions(), _contextMenuService, { classNames });
}
}
@@ -323,7 +333,7 @@ export class LabeledMenuItemActionItem extends MenuEntryActionViewItem {
// Overwrite item class to ensure that we can pass in a CSS class that other items use
// Leverages the _defaultCSSClassToAdd property that's passed into the constructor
_updateItemClass(item: ICommandAction): void {
protected _updateItemClass(item: ICommandAction): void {
dispose(this._labeledItemClassDispose);
this._labeledItemClassDispose = undefined;
@@ -336,13 +346,13 @@ export class LabeledMenuItemActionItem extends MenuEntryActionViewItem {
if (item.icon?.dark?.scheme) {
const iconPathMapKey = item.icon.dark.toString();
if (MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
iconClass = MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
if (ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
iconClass = ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
} else {
iconClass = ids.nextId();
createCSSRule(`.codicon.${iconClass}`, `background-image: ${asCSSUrl(item.icon.light || item.icon.dark)}`);
createCSSRule(`.vs-dark .codicon.${iconClass}, .hc-black .codicon.${iconClass}`, `background-image: ${asCSSUrl(item.icon.dark)}`);
MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
}
if (this.label) {

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Action } from 'vs/base/common/actions';
import { Action, IAction, Separator, SubmenuAction } from 'vs/base/common/actions';
import { SyncDescriptor0, createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IConstructorSignature2, createDecorator, BrandedService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindings, KeybindingsRegistry, IKeybindingRule } from 'vs/platform/keybinding/common/keybindingsRegistry';
@@ -47,6 +47,7 @@ export interface IMenuItem {
export interface ISubmenuItem {
title: string | ILocalizedString;
submenu: MenuId;
icon?: Icon;
when?: ContextKeyExpression;
group?: 'navigation' | string;
order?: number;
@@ -302,12 +303,35 @@ export class ExecuteCommandAction extends Action {
}
}
export class SubmenuItemAction extends Action {
export class SubmenuItemAction extends SubmenuAction {
readonly item: ISubmenuItem;
constructor(item: ISubmenuItem) {
typeof item.title === 'string' ? super('', item.title, 'submenu') : super('', item.title.value, 'submenu');
this.item = item;
constructor(
readonly item: ISubmenuItem,
menuService: IMenuService,
contextKeyService: IContextKeyService,
options?: IMenuActionOptions
) {
super(`submenuitem.${item.submenu.id}`, typeof item.title === 'string' ? item.title : item.title.value, () => {
const result: IAction[] = [];
const menu = menuService.createMenu(item.submenu, contextKeyService);
const groups = menu.getActions(options);
menu.dispose();
for (let group of groups) {
const [, actions] = group;
if (actions.length > 0) {
result.push(...actions);
result.push(new Separator());
}
}
if (result.length) {
result.pop(); // remove last separator
}
return result;
}, 'submenu');
}
}

View File

@@ -20,7 +20,7 @@ export class MenuService implements IMenuService {
}
createMenu(id: MenuId, contextKeyService: IContextKeyService): IMenu {
return new Menu(id, this._commandService, contextKeyService);
return new Menu(id, this._commandService, contextKeyService, this);
}
}
@@ -38,7 +38,8 @@ class Menu implements IMenu {
constructor(
private readonly _id: MenuId,
@ICommandService private readonly _commandService: ICommandService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IMenuService private readonly _menuService: IMenuService
) {
this._build();
@@ -114,7 +115,7 @@ class Menu implements IMenu {
if (this._contextKeyService.contextMatchesRules(item.when)) {
const action = isIMenuItem(item)
? new MenuItemAction(item.command, item.alt, options, this._contextKeyService, this._commandService)
: new SubmenuItemAction(item);
: new SubmenuItemAction(item, this._menuService, this._contextKeyService, options);
activeActions.push(action);
}

View File

@@ -3,11 +3,11 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionbar';
import { CheckboxActionViewItem } from 'vs/base/browser/ui/checkbox/checkbox';
import { IAction } from 'vs/base/common/actions';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachCheckboxStyler } from 'vs/platform/theme/common/styler';
import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';
export class ThemableCheckboxActionViewItem extends CheckboxActionViewItem {

View File

@@ -170,7 +170,7 @@ class Query {
withFilter(filterType: FilterType, ...values: string[]): Query {
const criteria = [
...this.state.criteria,
...values.map(value => ({ filterType, value }))
...values.length ? values.map(value => ({ filterType, value })) : [{ filterType }]
];
return new Query(assign({}, this.state, { criteria }));
@@ -494,6 +494,12 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
return '';
});
// Use featured filter
text = text.replace(/\bfeatured(\s+|\b|$)/g, () => {
query = query.withFilter(FilterType.Featured);
return '';
});
text = text.trim();
if (text) {

View File

@@ -4,6 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import * as os from 'os';
import product from 'vs/platform/product/common/product';
import * as objects from 'vs/base/common/objects';
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
import { ICommonIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/common/issue';
@@ -196,12 +198,23 @@ export class IssueMainService implements ICommonIssueService {
backgroundColor: data.styles.backgroundColor || DEFAULT_BACKGROUND_COLOR,
webPreferences: {
preload: URI.parse(require.toUrl('vs/base/parts/sandbox/electron-browser/preload.js')).fsPath,
nodeIntegration: true,
enableWebSQL: false,
enableRemoteModule: false,
spellcheck: false,
nativeWindowOpen: true,
zoomFactor: zoomLevelToZoomFactor(data.zoomLevel)
zoomFactor: zoomLevelToZoomFactor(data.zoomLevel),
...this.environmentService.sandbox ?
// Sandbox
{
sandbox: true,
contextIsolation: true
} :
// No Sandbox
{
nodeIntegration: true
}
}
});
@@ -408,10 +421,23 @@ export class IssueMainService implements ICommonIssueService {
machineId: this.machineId,
userEnv: this.userEnv,
data,
features
features,
disableExtensions: this.environmentService.disableExtensions,
os: {
type: os.type(),
arch: os.arch(),
release: os.release(),
},
product: {
nameShort: product.nameShort,
version: product.version,
commit: product.commit,
date: product.date,
reportIssueUrl: product.reportIssueUrl
}
};
return toLauchUrl('vs/code/electron-browser/issue/issueReporter.html', windowConfiguration);
return toLauchUrl('vs/code/electron-sandbox/issue/issueReporter.html', windowConfiguration);
}
}

View File

@@ -49,6 +49,13 @@ export interface IProductConfiguration {
readonly settingsSearchBuildId?: number;
readonly settingsSearchUrl?: string;
readonly tasConfig?: {
endpoint: string;
telemetryEventName: string;
featuresTelemetryPropertyName: string;
assignmentContextTelemetryPropertyName: string;
};
readonly experimentsUrl?: string;
readonly extensionsGallery?: {

View File

@@ -46,6 +46,8 @@ export interface ITelemetryService {
getTelemetryInfo(): Promise<ITelemetryInfo>;
setExperimentProperty(name: string, value: string): void;
isOptedIn: boolean;
}

View File

@@ -31,6 +31,7 @@ export class TelemetryService implements ITelemetryService {
private _appender: ITelemetryAppender;
private _commonProperties: Promise<{ [name: string]: any; }>;
private _experimentProperties: { [name: string]: string } = {};
private _piiPaths: string[];
private _userOptIn: boolean;
private _enabled: boolean;
@@ -79,6 +80,10 @@ export class TelemetryService implements ITelemetryService {
}
}
setExperimentProperty(name: string, value: string): void {
this._experimentProperties[name] = value;
}
setEnabled(value: boolean): void {
this._enabled = value;
}
@@ -119,6 +124,9 @@ export class TelemetryService implements ITelemetryService {
// (first) add common properties
data = mixin(data, values);
// (next) add experiment properties
data = mixin(data, this._experimentProperties);
// (last) remove all PII from data
data = cloneAndChange(data, value => {
if (typeof value === 'string') {

View File

@@ -28,6 +28,7 @@ export const NullTelemetryService = new class implements ITelemetryService {
return this.publicLogError(eventName, data as ITelemetryData);
}
setExperimentProperty() { }
setEnabled() { }
isOptedIn = true;
getTelemetryInfo(): Promise<ITelemetryInfo> {

View File

@@ -392,7 +392,7 @@ export const menuSeparatorBackground = registerColor('menu.separatorBackground',
export const snippetTabstopHighlightBackground = registerColor('editor.snippetTabstopHighlightBackground', { dark: new Color(new RGBA(124, 124, 124, 0.3)), light: new Color(new RGBA(10, 50, 100, 0.2)), hc: new Color(new RGBA(124, 124, 124, 0.3)) }, nls.localize('snippetTabstopHighlightBackground', "Highlight background color of a snippet tabstop."));
export const snippetTabstopHighlightBorder = registerColor('editor.snippetTabstopHighlightBorder', { dark: null, light: null, hc: null }, nls.localize('snippetTabstopHighlightBorder', "Highlight border color of a snippet tabstop."));
export const snippetFinalTabstopHighlightBackground = registerColor('editor.snippetFinalTabstopHighlightBackground', { dark: null, light: null, hc: null }, nls.localize('snippetFinalTabstopHighlightBackground', "Highlight background color of the final tabstop of a snippet."));
export const snippetFinalTabstopHighlightBorder = registerColor('editor.snippetFinalTabstopHighlightBorder', { dark: '#525252', light: new Color(new RGBA(10, 50, 100, 0.5)), hc: '#525252' }, nls.localize('snippetFinalTabstopHighlightBorder', "Highlight border color of the final stabstop of a snippet."));
export const snippetFinalTabstopHighlightBorder = registerColor('editor.snippetFinalTabstopHighlightBorder', { dark: '#525252', light: new Color(new RGBA(10, 50, 100, 0.5)), hc: '#525252' }, nls.localize('snippetFinalTabstopHighlightBorder', "Highlight border color of the final tabstop of a snippet."));
/**
* Breadcrumb colors

View File

@@ -18,6 +18,7 @@ import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { fromNow } from 'vs/base/common/date';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { Platform, platform } from 'vs/base/common/platform';
const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline', 'vscode.github-browser'];
@@ -390,7 +391,11 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
}
const remoteConnection = this.remoteAgentService.getConnection();
if (remoteConnection && remoteConnection.remoteAuthority && remoteConnection.remoteAuthority.startsWith('vsonline') && VSO_ALLOWED_EXTENSIONS.includes(extensionId)) {
const isVSO = remoteConnection !== null
? remoteConnection.remoteAuthority.startsWith('vsonline')
: platform === Platform.Web;
if (isVSO && VSO_ALLOWED_EXTENSIONS.includes(extensionId)) {
addAccountUsage(this.storageService, providerId, accountName, extensionId, extensionName);
return true;
}

View File

@@ -634,7 +634,7 @@ export class MainThreadTask implements MainThreadTaskShape {
return URI.parse(`${info.scheme}://${info.authority}${path}`);
},
context: this._extHostContext,
resolveVariables: (workspaceFolder: IWorkspaceFolder, toResolve: ResolveSet, target: ConfigurationTarget): Promise<ResolvedVariables> => {
resolveVariables: (workspaceFolder: IWorkspaceFolder, toResolve: ResolveSet, target: ConfigurationTarget): Promise<ResolvedVariables | undefined> => {
const vars: string[] = [];
toResolve.variables.forEach(item => vars.push(item));
return Promise.resolve(this._proxy.$resolveVariables(workspaceFolder.uri, { process: toResolve.process, variables: vars })).then(values => {
@@ -642,8 +642,12 @@ export class MainThreadTask implements MainThreadTaskShape {
forEach(values.variables, (entry) => {
partiallyResolvedVars.push(entry.value);
});
return new Promise<ResolvedVariables>((resolve, reject) => {
return new Promise<ResolvedVariables | undefined>((resolve, reject) => {
this._configurationResolverService.resolveWithInteraction(workspaceFolder, partiallyResolvedVars, 'tasks', undefined, target).then(resolvedVars => {
if (!resolvedVars) {
resolve(undefined);
}
const result: ResolvedVariables = {
process: undefined,
variables: new Map<string, string>()
@@ -677,4 +681,9 @@ export class MainThreadTask implements MainThreadTaskShape {
}
});
}
async $registerSupportedExecutions(custom?: boolean, shell?: boolean, process?: boolean): Promise<void> {
return this._taskService.registerSupportedExecutions(custom, shell, process);
}
}

View File

@@ -791,6 +791,7 @@ export interface MainThreadTaskShape extends IDisposable {
$terminateTask(id: string): Promise<void>;
$registerTaskSystem(scheme: string, info: tasks.TaskSystemInfoDTO): void;
$customExecutionComplete(id: string, result?: number): Promise<void>;
$registerSupportedExecutions(custom?: boolean, shell?: boolean, process?: boolean): Promise<void>;
}
export interface MainThreadExtensionServiceShape extends IDisposable {

View File

@@ -419,6 +419,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
this._activeCustomExecutions2 = new Map<string, types.CustomExecution>();
this._logService = logService;
this._deprecationService = deprecationService;
this._proxy.$registerSupportedExecutions(true);
}
public registerTaskProvider(extension: IExtensionDescription, type: string, provider: vscode.TaskProvider): vscode.Disposable {

View File

@@ -10,14 +10,203 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { forEach } from 'vs/base/common/collections';
import { IExtensionPointUser, ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { MenuId, MenuRegistry, ILocalizedString, IMenuItem, ICommandAction } from 'vs/platform/actions/common/actions';
import { MenuId, MenuRegistry, ILocalizedString, IMenuItem, ICommandAction, ISubmenuItem } from 'vs/platform/actions/common/actions';
import { URI } from 'vs/base/common/uri';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { Iterable } from 'vs/base/common/iterator';
import { index } from 'vs/base/common/arrays';
interface IAPIMenu {
readonly key: string;
readonly id: MenuId;
readonly description: string;
readonly proposed?: boolean; // defaults to false
readonly supportsSubmenus?: boolean; // defaults to true
}
const apiMenus: IAPIMenu[] = [
{
key: 'commandPalette',
id: MenuId.CommandPalette,
description: localize('menus.commandPalette', "The Command Palette"),
supportsSubmenus: false
},
{
key: 'touchBar',
id: MenuId.TouchBarContext,
description: localize('menus.touchBar', "The touch bar (macOS only)"),
supportsSubmenus: false
},
{
key: 'editor/title',
id: MenuId.EditorTitle,
description: localize('menus.editorTitle', "The editor title menu")
},
{
key: 'editor/context',
id: MenuId.EditorContext,
description: localize('menus.editorContext', "The editor context menu")
},
{
key: 'explorer/context',
id: MenuId.ExplorerContext,
description: localize('menus.explorerContext', "The file explorer context menu")
},
{
key: 'editor/title/context',
id: MenuId.EditorTitleContext,
description: localize('menus.editorTabContext', "The editor tabs context menu")
},
{
key: 'debug/callstack/context',
id: MenuId.DebugCallStackContext,
description: localize('menus.debugCallstackContext', "The debug callstack context menu")
},
{
key: 'debug/toolBar',
id: MenuId.DebugToolBar,
description: localize('menus.debugToolBar', "The debug toolbar menu")
},
{
key: 'menuBar/webNavigation',
id: MenuId.MenubarWebNavigationMenu,
description: localize('menus.webNavigation', "The top level navigational menu (web only)"),
proposed: true,
supportsSubmenus: false
},
{
key: 'scm/title',
id: MenuId.SCMTitle,
description: localize('menus.scmTitle', "The Source Control title menu")
},
{
key: 'scm/sourceControl',
id: MenuId.SCMSourceControl,
description: localize('menus.scmSourceControl', "The Source Control menu")
},
{
key: 'scm/resourceState/context',
id: MenuId.SCMResourceContext,
description: localize('menus.resourceGroupContext', "The Source Control resource group context menu")
},
{
key: 'scm/resourceFolder/context',
id: MenuId.SCMResourceFolderContext,
description: localize('menus.resourceStateContext', "The Source Control resource state context menu")
},
{
key: 'scm/resourceGroup/context',
id: MenuId.SCMResourceGroupContext,
description: localize('menus.resourceFolderContext', "The Source Control resource folder context menu")
},
{
key: 'scm/change/title',
id: MenuId.SCMChangeContext,
description: localize('menus.changeTitle', "The Source Control inline change menu")
},
{
key: 'statusBar/windowIndicator',
id: MenuId.StatusBarWindowIndicatorMenu,
description: localize('menus.statusBarWindowIndicator', "The window indicator menu in the status bar"),
proposed: true,
supportsSubmenus: false
},
{
key: 'view/title',
id: MenuId.ViewTitle,
description: localize('view.viewTitle', "The contributed view title menu")
},
{
key: 'view/item/context',
id: MenuId.ViewItemContext,
description: localize('view.itemContext', "The contributed view item context menu")
},
{
key: 'comments/commentThread/title',
id: MenuId.CommentThreadTitle,
description: localize('commentThread.title', "The contributed comment thread title menu")
},
{
key: 'comments/commentThread/context',
id: MenuId.CommentThreadActions,
description: localize('commentThread.actions', "The contributed comment thread context menu, rendered as buttons below the comment editor"),
supportsSubmenus: false
},
{
key: 'comments/comment/title',
id: MenuId.CommentTitle,
description: localize('comment.title', "The contributed comment title menu")
},
{
key: 'comments/comment/context',
id: MenuId.CommentActions,
description: localize('comment.actions', "The contributed comment context menu, rendered as buttons below the comment editor"),
supportsSubmenus: false
},
{
key: 'notebook/cell/title',
id: MenuId.NotebookCellTitle,
description: localize('notebook.cell.title', "The contributed notebook cell title menu"),
proposed: true
},
{
key: 'extension/context',
id: MenuId.ExtensionContext,
description: localize('menus.extensionContext', "The extension context menu")
},
{
key: 'timeline/title',
id: MenuId.TimelineTitle,
description: localize('view.timelineTitle', "The Timeline view title menu")
},
{
key: 'timeline/item/context',
id: MenuId.TimelineItemContext,
description: localize('view.timelineContext', "The Timeline view item context menu")
},
// {{SQL CARBON EDIT}} start menu entries
{
key: 'dashboard/toolbar',
id: MenuId.DashboardToolbar,
description: localize('dashboard.toolbar', "The dashboard toolbar action menu")
},
{
key: 'notebook/cell/title',
id: MenuId.NotebookCellTitle,
description: localize('notebook.cellTitle', "The notebook cell title menu")
},
{
key: 'notebooks/title',
id: MenuId.NotebookTitle,
description: localize('notebook.title', "The notebook title menu")
},
{
key: 'notebook/toolbar',
id: MenuId.NotebookToolbar,
description: localize('notebook.toolbar', "The notebook toolbar menu")
},
{
key: 'dataExplorer/action',
id: MenuId.DataExplorerAction,
description: localize('dataExplorer.action', "The dataexplorer view container title action menu")
},
{
key: 'dataExplorer/context',
id: MenuId.DataExplorerContext,
description: localize('dataExplorer.context', "The dataexplorer item context menu")
},
{
key: 'objectExplorer/item/context',
id: MenuId.DataExplorerContext,
description: localize('objectExplorer.context', "The object explorer item context menu")
},
// {{SQL CARBON EDIT}} end menu entries
];
namespace schema {
// --- menus contribution point
// --- menus, submenus contribution point
export interface IUserFriendlyMenuItem {
command: string;
@@ -26,87 +215,102 @@ namespace schema {
group?: string;
}
export function parseMenuId(value: string): MenuId | undefined {
switch (value) {
case 'commandPalette': return MenuId.CommandPalette;
case 'touchBar': return MenuId.TouchBarContext;
case 'editor/title': return MenuId.EditorTitle;
case 'editor/context': return MenuId.EditorContext;
case 'explorer/context': return MenuId.ExplorerContext;
case 'editor/title/context': return MenuId.EditorTitleContext;
case 'debug/callstack/context': return MenuId.DebugCallStackContext;
case 'debug/toolbar': return MenuId.DebugToolBar;
case 'debug/toolBar': return MenuId.DebugToolBar;
case 'menuBar/webNavigation': return MenuId.MenubarWebNavigationMenu;
case 'scm/title': return MenuId.SCMTitle;
case 'scm/sourceControl': return MenuId.SCMSourceControl;
case 'scm/resourceState/context': return MenuId.SCMResourceContext;
case 'scm/resourceFolder/context': return MenuId.SCMResourceFolderContext;
case 'scm/resourceGroup/context': return MenuId.SCMResourceGroupContext;
case 'scm/change/title': return MenuId.SCMChangeContext;//
case 'statusBar/windowIndicator': return MenuId.StatusBarWindowIndicatorMenu;
case 'view/title': return MenuId.ViewTitle;
case 'view/item/context': return MenuId.ViewItemContext;
// {{SQL CARBON EDIT}}
case 'objectExplorer/item/context': return MenuId.ObjectExplorerItemContext;
case 'notebook/toolbar': return MenuId.NotebookToolbar;
case 'dataExplorer/context': return MenuId.DataExplorerContext;
case 'dataExplorer/action': return MenuId.DataExplorerAction;
case 'notebooks/title': return MenuId.NotebookTitle;
case 'comments/commentThread/title': return MenuId.CommentThreadTitle;
case 'comments/commentThread/context': return MenuId.CommentThreadActions;
case 'comments/comment/title': return MenuId.CommentTitle;
case 'comments/comment/context': return MenuId.CommentActions;
case 'notebook/cell/title': return MenuId.NotebookCellTitle;
case 'extension/context': return MenuId.ExtensionContext;
case 'dashboard/toolbar': return MenuId.DashboardToolbar;
case 'timeline/title': return MenuId.TimelineTitle;
case 'timeline/item/context': return MenuId.TimelineItemContext;
}
return undefined;
export interface IUserFriendlySubmenuItem {
submenu: string;
when?: string;
group?: string;
}
export function isProposedAPI(menuId: MenuId): boolean {
switch (menuId) {
case MenuId.StatusBarWindowIndicatorMenu:
case MenuId.MenubarWebNavigationMenu:
case MenuId.NotebookCellTitle:
return true;
}
return false;
export interface IUserFriendlySubmenu {
id: string;
label: string;
icon?: IUserFriendlyIcon;
}
export function isValidMenuItems(menu: IUserFriendlyMenuItem[], collector: ExtensionMessageCollector): boolean {
if (!Array.isArray(menu)) {
collector.error(localize('requirearray', "menu items must be an array"));
export function isMenuItem(item: IUserFriendlyMenuItem | IUserFriendlySubmenuItem): item is IUserFriendlyMenuItem {
return typeof (item as IUserFriendlyMenuItem).command === 'string';
}
export function isValidMenuItem(item: IUserFriendlyMenuItem, collector: ExtensionMessageCollector): boolean {
if (typeof item.command !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'command'));
return false;
}
if (item.alt && typeof item.alt !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'alt'));
return false;
}
if (item.when && typeof item.when !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when'));
return false;
}
if (item.group && typeof item.group !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'group'));
return false;
}
for (let item of menu) {
if (typeof item.command !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'command'));
return false;
}
if (item.alt && typeof item.alt !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'alt'));
return false;
}
if (item.when && typeof item.when !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when'));
return false;
}
if (item.group && typeof item.group !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'group'));
return false;
return true;
}
export function isValidSubmenuItem(item: IUserFriendlySubmenuItem, collector: ExtensionMessageCollector): boolean {
if (typeof item.submenu !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'submenu'));
return false;
}
if (item.when && typeof item.when !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when'));
return false;
}
if (item.group && typeof item.group !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'group'));
return false;
}
return true;
}
export function isValidItems(items: (IUserFriendlyMenuItem | IUserFriendlySubmenuItem)[], collector: ExtensionMessageCollector): boolean {
if (!Array.isArray(items)) {
collector.error(localize('requirearray', "submenu items must be an array"));
return false;
}
for (let item of items) {
if (isMenuItem(item)) {
if (!isValidMenuItem(item, collector)) {
return false;
}
} else {
if (!isValidSubmenuItem(item, collector)) {
return false;
}
}
}
return true;
}
export function isValidSubmenu(submenu: IUserFriendlySubmenu, collector: ExtensionMessageCollector): boolean {
if (typeof submenu !== 'object') {
collector.error(localize('require', "submenu items must be an object"));
return false;
}
if (typeof submenu.id !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'id'));
return false;
}
if (typeof submenu.label !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'label'));
return false;
}
return true;
}
const menuItem: IJSONSchema = {
type: 'object',
required: ['command'],
properties: {
command: {
description: localize('vscode.extension.contributes.menuItem.command', 'Identifier of the command to execute. The command must be declared in the \'commands\'-section'),
@@ -127,136 +331,73 @@ namespace schema {
}
};
const submenuItem: IJSONSchema = {
type: 'object',
required: ['submenu'],
properties: {
submenu: {
description: localize('vscode.extension.contributes.menuItem.submenu', 'Identifier of the submenu to display in this item.'),
type: 'string'
},
when: {
description: localize('vscode.extension.contributes.menuItem.when', 'Condition which must be true to show this item'),
type: 'string'
},
group: {
description: localize('vscode.extension.contributes.menuItem.group', 'Group into which this command belongs'),
type: 'string'
}
}
};
const submenu: IJSONSchema = {
type: 'object',
required: ['id', 'label'],
properties: {
id: {
description: localize('vscode.extension.contributes.submenu.id', 'Identifier of the menu to display as a submenu.'),
type: 'string'
},
label: {
description: localize('vscode.extension.contributes.submenu.label', 'The label of the menu item which leads to this submenu.'),
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.submenu.icon', '(Optional) Icon which is used to represent the submenu in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
anyOf: [{
type: 'string'
},
{
type: 'object',
properties: {
light: {
description: localize('vscode.extension.contributes.submenu.icon.light', 'Icon path when a light theme is used'),
type: 'string'
},
dark: {
description: localize('vscode.extension.contributes.submenu.icon.dark', 'Icon path when a dark theme is used'),
type: 'string'
}
}
}]
}
}
};
export const menusContribution: IJSONSchema = {
description: localize('vscode.extension.contributes.menus', "Contributes menu items to the editor"),
type: 'object',
properties: {
'commandPalette': {
description: localize('menus.commandPalette', "The Command Palette"),
type: 'array',
items: menuItem
},
'touchBar': {
description: localize('menus.touchBar', "The touch bar (macOS only)"),
type: 'array',
items: menuItem
},
'editor/title': {
description: localize('menus.editorTitle', "The editor title menu"),
type: 'array',
items: menuItem
},
'editor/context': {
description: localize('menus.editorContext', "The editor context menu"),
type: 'array',
items: menuItem
},
'explorer/context': {
description: localize('menus.explorerContext', "The file explorer context menu"),
type: 'array',
items: menuItem
},
'editor/title/context': {
description: localize('menus.editorTabContext', "The editor tabs context menu"),
type: 'array',
items: menuItem
},
'debug/callstack/context': {
description: localize('menus.debugCallstackContext', "The debug callstack context menu"),
type: 'array',
items: menuItem
},
'debug/toolBar': {
description: localize('menus.debugToolBar', "The debug toolbar menu"),
type: 'array',
items: menuItem
},
'menuBar/webNavigation': {
description: localize('menus.webNavigation', "The top level navigational menu (web only)"),
type: 'array',
items: menuItem
},
'scm/title': {
description: localize('menus.scmTitle', "The Source Control title menu"),
type: 'array',
items: menuItem
},
'scm/sourceControl': {
description: localize('menus.scmSourceControl', "The Source Control menu"),
type: 'array',
items: menuItem
},
'scm/resourceGroup/context': {
description: localize('menus.resourceGroupContext', "The Source Control resource group context menu"),
type: 'array',
items: menuItem
},
'scm/resourceState/context': {
description: localize('menus.resourceStateContext', "The Source Control resource state context menu"),
type: 'array',
items: menuItem
},
'scm/resourceFolder/context': {
description: localize('menus.resourceFolderContext', "The Source Control resource folder context menu"),
type: 'array',
items: menuItem
},
'scm/change/title': {
description: localize('menus.changeTitle', "The Source Control inline change menu"),
type: 'array',
items: menuItem
},
'view/title': {
description: localize('view.viewTitle', "The contributed view title menu"),
type: 'array',
items: menuItem
},
'view/item/context': {
description: localize('view.itemContext', "The contributed view item context menu"),
type: 'array',
items: menuItem
},
'comments/commentThread/title': {
description: localize('commentThread.title', "The contributed comment thread title menu"),
type: 'array',
items: menuItem
},
'comments/commentThread/context': {
description: localize('commentThread.actions', "The contributed comment thread context menu, rendered as buttons below the comment editor"),
type: 'array',
items: menuItem
},
'comments/comment/title': {
description: localize('comment.title', "The contributed comment title menu"),
type: 'array',
items: menuItem
},
'comments/comment/context': {
description: localize('comment.actions', "The contributed comment context menu, rendered as buttons below the comment editor"),
type: 'array',
items: menuItem
},
'notebook/cell/title': {
description: localize('notebook.cell.title', "The contributed notebook cell title menu"),
type: 'array',
items: menuItem
},
'extension/context': {
description: localize('menus.extensionContext', "The extension context menu"),
type: 'array',
items: menuItem
},
'timeline/title': {
description: localize('view.timelineTitle', "The Timeline view title menu"),
type: 'array',
items: menuItem
},
'timeline/item/context': {
description: localize('view.timelineContext', "The Timeline view item context menu"),
type: 'array',
items: menuItem
},
}
properties: index(apiMenus, menu => menu.key, menu => ({
description: menu.proposed ? `(${localize('proposed', "Proposed API")}) ${menu.description}` : menu.description,
type: 'array',
items: menu.supportsSubmenus === false ? menuItem : { oneOf: [menuItem, submenuItem] }
}))
};
export const submenusContribution: IJSONSchema = {
description: localize('vscode.extension.contributes.submenus', "(Proposed API) Contributes submenu items to the editor"),
type: 'array',
items: submenu
};
// --- commands contribution point
@@ -437,74 +578,175 @@ commandsExtensionPoint.setHandler(extensions => {
_commandRegistrations.add(MenuRegistry.addCommands(newCommands));
});
const _menuRegistrations = new DisposableStore();
interface IRegisteredSubmenu {
readonly id: MenuId;
readonly label: string;
readonly icon?: { dark: URI; light?: URI; } | ThemeIcon;
}
ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyMenuItem[] }>({
extensionPoint: 'menus',
jsonSchema: schema.menusContribution
}).setHandler(extensions => {
const _submenus = new Map<string, IRegisteredSubmenu>();
// remove all previous menu registrations
_menuRegistrations.clear();
const submenusExtensionPoint = ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlySubmenu[]>({
extensionPoint: 'submenus',
jsonSchema: schema.submenusContribution
});
const items: { id: MenuId, item: IMenuItem }[] = [];
submenusExtensionPoint.setHandler(extensions => {
_submenus.clear();
for (let extension of extensions) {
const { value, collector } = extension;
forEach(value, entry => {
if (!schema.isValidMenuItems(entry.value, collector)) {
if (!schema.isValidSubmenu(entry.value, collector)) {
return;
}
const menu = schema.parseMenuId(entry.key);
if (typeof menu === 'undefined') {
if (!entry.value.id) {
collector.warn(localize('submenuId.invalid.id', "`{0}` is not a valid submenu identifier", entry.value.id));
return;
}
if (!entry.value.label) {
collector.warn(localize('submenuId.invalid.label', "`{0}` is not a valid submenu label", entry.value.label));
return;
}
if (!extension.description.enableProposedApi) {
collector.error(localize('submenu.proposedAPI.invalid', "Submenus are proposed API and are only available when running out of dev or with the following command line switch: --enable-proposed-api {1}", extension.description.identifier.value));
return;
}
let absoluteIcon: { dark: URI; light?: URI; } | ThemeIcon | undefined;
if (entry.value.icon) {
if (typeof entry.value.icon === 'string') {
absoluteIcon = ThemeIcon.fromString(entry.value.icon) || { dark: resources.joinPath(extension.description.extensionLocation, entry.value.icon) };
} else {
absoluteIcon = {
dark: resources.joinPath(extension.description.extensionLocation, entry.value.icon.dark),
light: resources.joinPath(extension.description.extensionLocation, entry.value.icon.light)
};
}
}
const item: IRegisteredSubmenu = {
id: new MenuId(`api:${entry.value.id}`),
label: entry.value.label,
icon: absoluteIcon
};
_submenus.set(entry.value.id, item);
});
}
});
const _apiMenusByKey = new Map(Iterable.map(Iterable.from(apiMenus), menu => ([menu.key, menu])));
const _menuRegistrations = new DisposableStore();
const menusExtensionPoint = ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: (schema.IUserFriendlyMenuItem | schema.IUserFriendlySubmenuItem)[] }>({
extensionPoint: 'menus',
jsonSchema: schema.menusContribution,
deps: [submenusExtensionPoint]
});
menusExtensionPoint.setHandler(extensions => {
// remove all previous menu registrations
_menuRegistrations.clear();
const items: { id: MenuId, item: IMenuItem | ISubmenuItem }[] = [];
for (let extension of extensions) {
const { value, collector } = extension;
forEach(value, entry => {
if (!schema.isValidItems(entry.value, collector)) {
return;
}
let menu = _apiMenusByKey.get(entry.key);
let isSubmenu = false;
if (!menu) {
const submenu = _submenus.get(entry.key);
if (submenu) {
menu = {
key: entry.key,
id: submenu.id,
description: ''
};
isSubmenu = true;
}
}
if (!menu) {
collector.warn(localize('menuId.invalid', "`{0}` is not a valid menu identifier", entry.key));
return;
}
if (schema.isProposedAPI(menu) && !extension.description.enableProposedApi) {
if (menu.proposed && !extension.description.enableProposedApi) {
collector.error(localize('proposedAPI.invalid', "{0} is a proposed menu identifier and is only available when running out of dev or with the following command line switch: --enable-proposed-api {1}", entry.key, extension.description.identifier.value));
return;
}
for (let item of entry.value) {
let command = MenuRegistry.getCommand(item.command);
let alt = item.alt && MenuRegistry.getCommand(item.alt) || undefined;
if (isSubmenu && !extension.description.enableProposedApi) {
collector.error(localize('proposedAPI.invalid.submenu', "{0} is a submenu identifier and is only available when running out of dev or with the following command line switch: --enable-proposed-api {1}", entry.key, extension.description.identifier.value));
return;
}
if (!command) {
collector.error(localize('missing.command', "Menu item references a command `{0}` which is not defined in the 'commands' section.", item.command));
continue;
}
if (item.alt && !alt) {
collector.warn(localize('missing.altCommand', "Menu item references an alt-command `{0}` which is not defined in the 'commands' section.", item.alt));
}
if (item.command === item.alt) {
collector.info(localize('dupe.command', "Menu item references the same command as default and alt-command"));
for (const menuItem of entry.value) {
let item: IMenuItem | ISubmenuItem;
if (schema.isMenuItem(menuItem)) {
const command = MenuRegistry.getCommand(menuItem.command);
const alt = menuItem.alt && MenuRegistry.getCommand(menuItem.alt) || undefined;
if (!command) {
collector.error(localize('missing.command', "Menu item references a command `{0}` which is not defined in the 'commands' section.", menuItem.command));
continue;
}
if (menuItem.alt && !alt) {
collector.warn(localize('missing.altCommand', "Menu item references an alt-command `{0}` which is not defined in the 'commands' section.", menuItem.alt));
}
if (menuItem.command === menuItem.alt) {
collector.info(localize('dupe.command', "Menu item references the same command as default and alt-command"));
}
item = { command, alt, group: undefined, order: undefined, when: undefined };
} else {
if (!extension.description.enableProposedApi) {
collector.error(localize('proposedAPI.invalid.submenureference', "Menu item references a submenu which is only available when running out of dev or with the following command line switch: --enable-proposed-api {0}", extension.description.identifier.value));
continue;
}
if (menu.supportsSubmenus === false) {
collector.error(localize('proposedAPI.unsupported.submenureference', "Menu item references a submenu for a menu which doesn't have submenu support."));
continue;
}
const submenu = _submenus.get(menuItem.submenu);
if (!submenu) {
collector.error(localize('missing.submenu', "Menu item references a submenu `{0}` which is not defined in the 'submenus' section.", menuItem.submenu));
continue;
}
item = { submenu: submenu.id, icon: submenu.icon, title: submenu.label, group: undefined, order: undefined, when: undefined };
}
let group: string | undefined;
let order: number | undefined;
if (item.group) {
const idx = item.group.lastIndexOf('@');
if (menuItem.group) {
const idx = menuItem.group.lastIndexOf('@');
if (idx > 0) {
group = item.group.substr(0, idx);
order = Number(item.group.substr(idx + 1)) || undefined;
item.group = menuItem.group.substr(0, idx);
item.order = Number(menuItem.group.substr(idx + 1)) || undefined;
} else {
group = item.group;
item.group = menuItem.group;
}
}
items.push({
id: menu,
item: {
command,
alt,
group,
order,
when: ContextKeyExpr.deserialize(item.when)
}
});
item.when = ContextKeyExpr.deserialize(menuItem.when);
items.push({ id: menu.id, item });
}
});
}

View File

@@ -47,6 +47,7 @@ export class ExtHostTask extends ExtHostTaskBase {
platform: process.platform
});
}
this._proxy.$registerSupportedExecutions(true, true, true);
}
public async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution> {

View File

@@ -3,9 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IAction, Action } from 'vs/base/common/actions';
import { IAction, Action, Separator } from 'vs/base/common/actions';
import { localize } from 'vs/nls';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Disposable } from 'vs/base/common/lifecycle';

View File

@@ -3,8 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, IActionRunner, ActionRunner, IActionViewItem } from 'vs/base/common/actions';
import { Component } from 'vs/workbench/common/component';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IComposite, ICompositeControl } from 'vs/workbench/common/composite';

View File

@@ -15,10 +15,9 @@ import { Composite } from 'vs/workbench/browser/composite';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ViewPaneContainer } from './parts/views/viewPaneContainer';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
import { IAction, IActionViewItem } from 'vs/base/common/actions';
import { IAction, IActionViewItem, Separator } from 'vs/base/common/actions';
import { ViewContainerMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
import { MenuId } from 'vs/platform/actions/common/actions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
export class PaneComposite extends Composite implements IPaneComposite {

View File

@@ -8,7 +8,7 @@ import * as nls from 'vs/nls';
import * as DOM from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { Action, IAction } from 'vs/base/common/actions';
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';
@@ -27,12 +27,11 @@ 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 { ActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { isMacintosh } from 'vs/base/common/platform';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { 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';
export class ViewContainerActivityAction extends ActivityAction {
@@ -163,7 +162,7 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
});
const result = await Promise.all(allSessions);
let menus: (IAction | ContextSubMenu)[] = [];
let menus: IAction[] = [];
result.forEach(sessionInfo => {
const providerDisplayName = this.authenticationService.getLabel(sessionInfo.providerId);
Object.keys(sessionInfo.sessions).forEach(accountName => {
@@ -177,7 +176,7 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
const actions = hasEmbedderAccountSession ? [manageExtensionsAction] : [manageExtensionsAction, signOutAction];
const menu = new ContextSubMenu(`${accountName} (${providerDisplayName})`, actions);
const menu = new SubmenuAction('activitybar.submenu', `${accountName} (${providerDisplayName})`, actions);
menus.push(menu);
});
});

View File

@@ -5,7 +5,7 @@
import 'vs/css!./media/activitybarpart';
import * as nls from 'vs/nls';
import { ActionsOrientation, ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { GLOBAL_ACTIVITY_ID, IActivity, ACCOUNTS_ACTIIVTY_ID } from 'vs/workbench/common/activity';
import { Part } from 'vs/workbench/browser/part';
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, HomeAction, HomeActionViewItem, ACCOUNTS_VISIBILITY_PREFERENCE_KEY } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
@@ -37,7 +37,7 @@ 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 } from 'vs/base/common/actions';
import { Action, Separator } from 'vs/base/common/actions';
import { Event } from 'vs/base/common/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';

View File

@@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Action, IAction } from 'vs/base/common/actions';
import { Action, IAction, Separator } from 'vs/base/common/actions';
import { illegalArgument } from 'vs/base/common/errors';
import * as arrays from 'vs/base/common/arrays';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IBadge } from 'vs/workbench/services/activity/common/activity';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ActionBar, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { CompositeActionViewItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionViewItem, ActivityAction, ICompositeBar, ICompositeBarColors } from 'vs/workbench/browser/parts/compositeBarActions';
import { Dimension, $, addDisposableListener, EventType, EventHelper, toggleClass, isAncestor } from 'vs/base/browser/dom';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
@@ -629,7 +629,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
});
}
private getContextMenuActions(): ReadonlyArray<IAction> {
private getContextMenuActions(): IAction[] {
const actions: IAction[] = this.model.visibleItems
.map(({ id, name, activityAction }) => (<IAction>{
id,

View File

@@ -4,9 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { Action, Separator } from 'vs/base/common/actions';
import * as dom from 'vs/base/browser/dom';
import { BaseActionViewItem, IBaseActionViewItemOptions, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { dispose, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
@@ -21,6 +20,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { CompositeDragAndDropObserver, ICompositeDragAndDrop, Before2D, toggleDropEffect } from 'vs/workbench/browser/dnd';
import { Color } from 'vs/base/common/color';
import { Codicon } from 'vs/base/common/codicons';
import { IBaseActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export interface ICompositeActivity {
badge: IBadge;

View File

@@ -11,9 +11,9 @@ import * as strings from 'vs/base/common/strings';
import { Emitter } from 'vs/base/common/event';
import * as errors from 'vs/base/common/errors';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IActionViewItem, ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, IActionViewItem } from 'vs/base/common/actions';
import { Part, IPartOptions } from 'vs/workbench/browser/part';
import { Composite, CompositeRegistry } from 'vs/workbench/browser/composite';
import { IComposite } from 'vs/workbench/common/composite';

View File

@@ -7,16 +7,16 @@ import 'vs/css!./media/titlecontrol';
import { applyDragImage, DataTransfers } from 'vs/base/browser/dnd';
import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IAction, IRunEvent, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { IAction, IRunEvent, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, IActionViewItem } from 'vs/base/common/actions';
import * as arrays from 'vs/base/common/arrays';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { getCodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { localize } from 'vs/nls';
import { createActionViewItem, createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { ExecuteCommandAction, IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { createAndFillInActionBarActions, createAndFillInContextMenuActions, MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { ExecuteCommandAction, IMenu, IMenuService, MenuId, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
@@ -164,17 +164,22 @@ export abstract class TitleControl extends Themable {
const activeEditorPane = this.group.activeEditorPane;
// Check Active Editor
let actionViewItem: IActionViewItem | undefined = undefined;
if (activeEditorPane instanceof BaseEditor) {
actionViewItem = activeEditorPane.getActionViewItem(action);
const result = activeEditorPane.getActionViewItem(action);
if (result) {
return result;
}
}
// Check extensions
if (!actionViewItem) {
actionViewItem = createActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
if (action instanceof MenuItemAction) {
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
} else if (action instanceof SubmenuItemAction) {
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
}
return actionViewItem;
return undefined;
}
protected updateEditorActionsToolbar(): void {

View File

@@ -16,7 +16,6 @@ import { 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';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
import { INotificationViewItem, NotificationViewItem, NotificationViewItemContentChangeKind, INotificationMessage, ChoiceAction } from 'vs/workbench/common/notifications';
import { ClearNotificationAction, ExpandNotificationAction, CollapseNotificationAction, ConfigureNotificationAction } from 'vs/workbench/browser/parts/notifications/notificationsActions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -24,6 +23,7 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { Severity } from 'vs/platform/notification/common/notification';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { Codicon } from 'vs/base/common/codicons';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
export class NotificationsListDelegate implements IListVirtualDelegate<INotificationViewItem> {
@@ -211,7 +211,7 @@ export class NotificationRenderer implements IListRenderer<INotificationViewItem
ariaLabel: localize('notificationActions', "Notification Actions"),
actionViewItemProvider: action => {
if (action && action instanceof ConfigureNotificationAction) {
const item = new DropdownMenuActionViewItem(action, action.configurationActions, this.contextMenuService, undefined, this.actionRunner, undefined, action.class);
const item = new DropdownMenuActionViewItem(action, action.configurationActions, this.contextMenuService, { actionRunner: this.actionRunner, classNames: action.class });
data.toDispose.add(item);
return item;

View File

@@ -14,7 +14,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/common/statusbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Action, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { Action, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, Separator } from 'vs/base/common/actions';
import { IThemeService, registerThemingParticipant, IColorTheme, ICssStyleCollector, ThemeColor, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService';
import { STATUS_BAR_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_ITEM_HOVER_BACKGROUND, STATUS_BAR_ITEM_ACTIVE_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND, STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND, STATUS_BAR_BORDER, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER } from 'vs/workbench/common/theme';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
@@ -29,7 +29,6 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { coalesce } from 'vs/base/common/arrays';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { ToggleStatusbarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { assertIsDefined } from 'vs/base/common/types';
import { Emitter } from 'vs/base/common/event';
import { Command } from 'vs/editor/common/modes';

View File

@@ -8,8 +8,7 @@ import { IMenuService, MenuId, IMenu, SubmenuItemAction, registerAction2, Action
import { registerThemingParticipant, IColorTheme, ICssStyleCollector, IThemeService } from 'vs/platform/theme/common/themeService';
import { MenuBarVisibility, getTitleBarStyle, IWindowOpenable, getMenuBarVisibility } from 'vs/platform/windows/common/windows';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IAction, Action } from 'vs/base/common/actions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
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';
@@ -27,7 +26,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { MenuBar, IMenuBarOptions } from 'vs/base/browser/ui/menu/menubar';
import { SubmenuAction, Direction } from 'vs/base/browser/ui/menu/menu';
import { Direction } from 'vs/base/browser/ui/menu/menu';
import { attachMenuStyler } from 'vs/platform/theme/common/styler';
import { mnemonicMenuLabel, unmnemonicLabel } from 'vs/base/common/labels';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
@@ -600,7 +599,7 @@ export class CustomMenubarControl extends MenubarControl {
const submenuActions: SubmenuAction[] = [];
updateActions(submenu, submenuActions, topLevelTitle);
target.push(new SubmenuAction(mnemonicMenuLabel(action.label), submenuActions));
target.push(new SubmenuAction(action.id, mnemonicMenuLabel(action.label), submenuActions));
} else {
action.label = mnemonicMenuLabel(this.calculateActionLabel(action));
target.push(action);

View File

@@ -12,8 +12,8 @@ import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND,
import { append, $, trackFocus, toggleClass, EventType, isAncestor, Dimension, addDisposableListener, removeClass, addClass, createCSSRule, asCSSUrl, addClasses } from 'vs/base/browser/dom';
import { IDisposable, combinedDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { firstIndex } from 'vs/base/common/arrays';
import { IAction } from 'vs/base/common/actions';
import { IActionViewItem, ActionsOrientation, Separator, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, Separator, IActionViewItem } from 'vs/base/common/actions';
import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { Registry } from 'vs/platform/registry/common/platform';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -33,8 +33,8 @@ import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewl
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { Component } from 'vs/workbench/common/component';
import { MenuId, MenuItemAction, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions';
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { MenuId, MenuItemAction, registerAction2, Action2, IAction2Options, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { ViewMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
import { parseLinkedText } from 'vs/base/common/linkedText';
import { IOpenerService } from 'vs/platform/opener/common/opener';
@@ -482,7 +482,9 @@ export abstract class ViewPane extends Pane implements IView {
getActionViewItem(action: IAction): IActionViewItem | undefined {
if (action instanceof MenuItemAction) {
return this.instantiationService.createInstance(ContextAwareMenuEntryActionViewItem, action);
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
} else if (action instanceof SubmenuItemAction) {
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
}
return undefined;
}

View File

@@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import * as DOM from 'vs/base/browser/dom';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action, IAction } from 'vs/base/common/actions';
import { Action, IAction, Separator, SubmenuAction } from 'vs/base/common/actions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { CompositeDescriptor, CompositeRegistry } from 'vs/workbench/browser/composite';
@@ -26,8 +26,6 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { PaneComposite } from 'vs/workbench/browser/panecomposite';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { Event } from 'vs/base/common/event';
export abstract class Viewlet extends PaneComposite implements IViewlet {
@@ -79,7 +77,7 @@ export abstract class Viewlet extends PaneComposite implements IViewlet {
}
return [
new ContextSubMenu(nls.localize('views', "Views"), viewVisibilityActions),
new SubmenuAction('workbench.views', nls.localize('views', "Views"), viewVisibilityActions),
new Separator(),
...secondaryActions
];

View File

@@ -32,9 +32,9 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import { Color } from 'vs/base/common/color';
import { TreeMouseEventTarget, ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { URI } from 'vs/base/common/uri';
import { MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
import { MenuId, IMenuService } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { createAndFillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
const enum State {
Loading = 'loading',
@@ -94,7 +94,7 @@ export class CallHierarchyTreePeekWidget extends peekView.PeekViewWidget {
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) {
super(editor, { showFrame: true, showArrow: true, isResizeable: true, isAccessible: true });
super(editor, { showFrame: true, showArrow: true, isResizeable: true, isAccessible: true }, _instantiationService);
this.create();
this._peekViewService.addExclusiveWidget(editor, this);
this._applyTheme(themeService.getColorTheme());
@@ -142,8 +142,8 @@ export class CallHierarchyTreePeekWidget extends peekView.PeekViewWidget {
protected _getActionBarOptions(): IActionBarOptions {
return {
orientation: ActionsOrientation.HORIZONTAL,
actionViewItemProvider: action => action instanceof MenuItemAction ? this._instantiationService.createInstance(MenuEntryActionViewItem, action) : undefined
...super._getActionBarOptions(),
orientation: ActionsOrientation.HORIZONTAL
};
}

View File

@@ -6,8 +6,8 @@
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import * as modes from 'vs/editor/common/modes';
import { ActionsOrientation, ActionViewItem, ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, IActionRunner, IAction } from 'vs/base/common/actions';
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, IActionRunner, IAction, Separator } from 'vs/base/common/actions';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { ITextModel } from 'vs/editor/common/model';
@@ -23,17 +23,17 @@ import { Emitter, Event } from 'vs/base/common/event';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { ToggleReactionsAction, ReactionAction, ReactionActionViewItem } from './reactionsAction';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget';
import { MenuItemAction, SubmenuItemAction, IMenu } from 'vs/platform/actions/common/actions';
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { CommentFormActions } from 'vs/workbench/contrib/comments/browser/commentFormActions';
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
export class CommentNode extends Disposable {
private _domNode: HTMLElement;
@@ -79,7 +79,6 @@ export class CommentNode extends Disposable {
@ICommentService private commentService: ICommentService,
@IModelService private modelService: IModelService,
@IModeService private modeService: IModeService,
@IKeybindingService private keybindingService: IKeybindingService,
@INotificationService private notificationService: INotificationService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IContextKeyService contextKeyService: IContextKeyService
@@ -154,13 +153,12 @@ export class CommentNode extends Disposable {
action,
(<ToggleReactionsAction>action).menuActions,
this.contextMenuService,
action => {
return this.actionViewItemProvider(action as Action);
},
this.actionRunner!,
undefined,
'toolbar-toggle-pickReactions codicon codicon-reactions',
() => { return AnchorAlignment.RIGHT; }
{
actionViewItemProvider: action => this.actionViewItemProvider(action as Action),
actionRunner: this.actionRunner,
classNames: ['toolbar-toggle-pickReactions', 'codicon', 'codicon-reactions'],
anchorAlignmentProvider: () => AnchorAlignment.RIGHT
}
);
}
return this.actionViewItemProvider(action as Action);
@@ -221,8 +219,9 @@ export class CommentNode extends Disposable {
let item = new ReactionActionViewItem(action);
return item;
} else if (action instanceof MenuItemAction) {
let item = new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
return item;
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
} else if (action instanceof SubmenuItemAction) {
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
} else {
let item = new ActionViewItem({}, action, options);
return item;
@@ -259,16 +258,17 @@ export class CommentNode extends Disposable {
toggleReactionAction,
(<ToggleReactionsAction>toggleReactionAction).menuActions,
this.contextMenuService,
action => {
if (action.id === ToggleReactionsAction.ID) {
return toggleReactionActionViewItem;
}
return this.actionViewItemProvider(action as Action);
},
this.actionRunner!,
undefined,
'toolbar-toggle-pickReactions',
() => { return AnchorAlignment.RIGHT; }
{
actionViewItemProvider: action => {
if (action.id === ToggleReactionsAction.ID) {
return toggleReactionActionViewItem;
}
return this.actionViewItemProvider(action as Action);
},
actionRunner: this.actionRunner,
classNames: 'toolbar-toggle-pickReactions',
anchorAlignmentProvider: () => AnchorAlignment.RIGHT
}
);
return toggleReactionAction;
@@ -283,13 +283,12 @@ export class CommentNode extends Disposable {
action,
(<ToggleReactionsAction>action).menuActions,
this.contextMenuService,
action => {
return this.actionViewItemProvider(action as Action);
},
this.actionRunner!,
undefined,
'toolbar-toggle-pickReactions',
() => { return AnchorAlignment.RIGHT; }
{
actionViewItemProvider: action => this.actionViewItemProvider(action as Action),
actionRunner: this.actionRunner,
classNames: 'toolbar-toggle-pickReactions',
anchorAlignmentProvider: () => AnchorAlignment.RIGHT
}
);
}
return this.actionViewItemProvider(action as Action);

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as dom from 'vs/base/browser/dom';
import { ActionBar, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, IAction } from 'vs/base/common/actions';
import * as arrays from 'vs/base/common/arrays';
import { Color } from 'vs/base/common/color';
@@ -26,13 +26,10 @@ import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
import { peekViewBorder } from 'vs/editor/contrib/peekView/peekView';
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
import * as nls from 'vs/nls';
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { contrastBorder, editorForeground, focusBorder, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground, transparent } from 'vs/platform/theme/common/colorRegistry';
import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';
@@ -49,6 +46,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
import { KeyCode } from 'vs/base/common/keyCodes';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration';
const COLLAPSE_ACTION_CLASS = 'expand-review-action codicon-chevron-up';
@@ -109,15 +107,12 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
private _owner: string,
private _commentThread: modes.CommentThread,
private _pendingComment: string | null,
@IInstantiationService instantiationService: IInstantiationService,
@IInstantiationService private instantiationService: IInstantiationService,
@IModeService private modeService: IModeService,
@IModelService private modelService: IModelService,
@IThemeService private themeService: IThemeService,
@ICommentService private commentService: ICommentService,
@IOpenerService private openerService: IOpenerService,
@IKeybindingService private keybindingService: IKeybindingService,
@INotificationService private notificationService: INotificationService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IContextKeyService contextKeyService: IContextKeyService
) {
super(editor, { keepEditorSelection: true });
@@ -239,11 +234,11 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._actionbarWidget = new ActionBar(actionsContainer, {
actionViewItemProvider: (action: IAction) => {
if (action instanceof MenuItemAction) {
let item = new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
return item;
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
} else if (action instanceof SubmenuItemAction) {
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
} else {
let item = new ActionViewItem({}, action, { label: false, icon: true });
return item;
return new ActionViewItem({}, action, { label: false, icon: true });
}
}
});

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { $ } from 'vs/base/browser/dom';
import { Action, IAction } from 'vs/base/common/actions';
import { coalesce, findFirstInSorted } from 'vs/base/common/arrays';
@@ -547,8 +546,8 @@ export class CommentController implements IEditorContribution {
return picks;
}
private getContextMenuActions(commentInfos: { ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges }[], lineNumber: number): (IAction | ContextSubMenu)[] {
const actions: (IAction | ContextSubMenu)[] = [];
private getContextMenuActions(commentInfos: { ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges }[], lineNumber: number): IAction[] {
const actions: IAction[] = [];
commentInfos.forEach(commentInfo => {
const { ownerId, extensionId, label } = commentInfo;

View File

@@ -5,9 +5,9 @@
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, IAction } from 'vs/base/common/actions';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export class ToggleReactionsAction extends Action {
static readonly ID = 'toolbar.toggle.pickReactions';

View File

@@ -8,7 +8,7 @@ import * as env from 'vs/base/common/platform';
import * as dom from 'vs/base/browser/dom';
import { URI } from 'vs/base/common/uri';
import severity from 'vs/base/common/severity';
import { IAction, Action } from 'vs/base/common/actions';
import { IAction, Action, SubmenuAction } from 'vs/base/common/actions';
import { Range } from 'vs/editor/common/core/range';
import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
import { IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, ITextModel, OverviewRulerLane, IModelDecorationOverviewRulerOptions } from 'vs/editor/common/model';
@@ -18,7 +18,6 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { RemoveBreakpointAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, BreakpointWidgetContext, IBreakpointEditorContribution, IBreakpointUpdateData, IDebugConfiguration, State, IDebugSession } from 'vs/workbench/contrib/debug/common/debug';
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
@@ -288,8 +287,8 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi
}));
}
private getContextMenuActions(breakpoints: ReadonlyArray<IBreakpoint>, uri: URI, lineNumber: number, column?: number): Array<IAction | ContextSubMenu> {
const actions: Array<IAction | ContextSubMenu> = [];
private getContextMenuActions(breakpoints: ReadonlyArray<IBreakpoint>, uri: URI, lineNumber: number, column?: number): IAction[] {
const actions: IAction[] = [];
if (breakpoints.length === 1) {
const breakpointType = breakpoints[0].logMessage ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService));
@@ -310,7 +309,7 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi
));
} else if (breakpoints.length > 1) {
const sorted = breakpoints.slice().sort((first, second) => (first.column && second.column) ? first.column - second.column : 1);
actions.push(new ContextSubMenu(nls.localize('removeBreakpoints', "Remove Breakpoints"), sorted.map(bp => new Action(
actions.push(new SubmenuAction('debug.removeBreakpoints', nls.localize('removeBreakpoints', "Remove Breakpoints"), sorted.map(bp => new Action(
'removeInlineBreakpoint',
bp.column ? nls.localize('removeInlineBreakpointOnColumn', "Remove Inline Breakpoint on Column {0}", bp.column) : nls.localize('removeLineBreakpoint', "Remove Line Breakpoint"),
undefined,
@@ -318,7 +317,7 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi
() => this.debugService.removeBreakpoints(bp.getId())
))));
actions.push(new ContextSubMenu(nls.localize('editBreakpoints', "Edit Breakpoints"), sorted.map(bp =>
actions.push(new SubmenuAction('debug.editBReakpoints', nls.localize('editBreakpoints', "Edit Breakpoints"), sorted.map(bp =>
new Action('editBreakpoint',
bp.column ? nls.localize('editInlineBreakpointOnColumn', "Edit Inline Breakpoint on Column {0}", bp.column) : nls.localize('editLineBrekapoint', "Edit Line Breakpoint"),
undefined,
@@ -327,7 +326,7 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi
)
)));
actions.push(new ContextSubMenu(nls.localize('enableDisableBreakpoints', "Enable/Disable Breakpoints"), sorted.map(bp => new Action(
actions.push(new SubmenuAction('debug.enableDisableBreakpoints', nls.localize('enableDisableBreakpoints', "Enable/Disable Breakpoints"), sorted.map(bp => new Action(
bp.enabled ? 'disableColumnBreakpoint' : 'enableColumnBreakpoint',
bp.enabled ? (bp.column ? nls.localize('disableInlineColumnBreakpoint', "Disable Inline Breakpoint on Column {0}", bp.column) : nls.localize('disableBreakpointOnLine', "Disable Line Breakpoint"))
: (bp.column ? nls.localize('enableBreakpoints', "Enable Inline Breakpoint on Column {0}", bp.column) : nls.localize('enableBreakpointOnLine', "Enable Line Breakpoint")),
@@ -548,7 +547,7 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable {
private readonly breakpoint: IBreakpoint | undefined,
private readonly debugService: IDebugService,
private readonly contextMenuService: IContextMenuService,
private readonly getContextMenuActions: () => ReadonlyArray<IAction | ContextSubMenu>
private readonly getContextMenuActions: () => IAction[]
) {
this.range = this.editor.getModel().getDecorationRange(decorationId);
this.toDispose.push(this.editor.onDidChangeModelDecorations(() => {

View File

@@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import * as resources from 'vs/base/common/resources';
import * as dom from 'vs/base/browser/dom';
import { IAction, Action } from 'vs/base/common/actions';
import { IAction, Action, Separator } from 'vs/base/common/actions';
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINTS_FOCUSED, State, DEBUG_SCHEME, IFunctionBreakpoint, IExceptionBreakpoint, IEnablement, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, IDebugModel, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
import { ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
import { AddFunctionBreakpointAction, ToggleBreakpointsActivatedAction, RemoveAllBreakpointsAction, RemoveBreakpointAction, EnableAllBreakpointsAction, DisableAllBreakpointsAction, ReapplyBreakpointsAction } from 'vs/workbench/contrib/debug/browser/debugActions';
@@ -16,7 +16,6 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Constants } from 'vs/base/common/uint';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IListVirtualDelegate, IListContextMenuEvent, IListRenderer } from 'vs/base/browser/ui/list/list';
import { IEditorPane } from 'vs/workbench/common/editor';
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';

View File

@@ -11,7 +11,7 @@ import { IDebugService, State, IStackFrame, IDebugSession, IThread, CONTEXT_CALL
import { Thread, StackFrame, ThreadAndSessionIds } from 'vs/workbench/contrib/debug/common/debugModel';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MenuId, IMenu, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
import { MenuId, IMenu, IMenuService, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { IAction, Action } from 'vs/base/common/actions';
@@ -21,7 +21,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { ILabelService } from 'vs/platform/label/common/label';
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { createAndFillInContextMenuActions, createAndFillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { createAndFillInContextMenuActions, createAndFillInActionBarActions, MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
import { WorkbenchCompressibleAsyncDataTree } from 'vs/platform/list/browser/listService';
@@ -489,10 +489,7 @@ class SessionsRenderer implements ICompressibleTreeRenderer<IDebugSession, Fuzzy
constructor(
private menu: IMenu,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IDebugService private readonly debugService: IDebugService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@INotificationService private readonly notificationService: INotificationService,
@IContextMenuService private readonly contextMenuService: IContextMenuService
@IDebugService private readonly debugService: IDebugService
) { }
get templateId(): string {
@@ -509,8 +506,9 @@ class SessionsRenderer implements ICompressibleTreeRenderer<IDebugSession, Fuzzy
const actionBar = new ActionBar(session, {
actionViewItemProvider: action => {
if (action instanceof MenuItemAction) {
// We need the MenuEntryActionViewItem so the icon would get rendered
return new MenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
} else if (action instanceof SubmenuItemAction) {
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
}
return undefined;

View File

@@ -4,12 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { IAction, IActionRunner } from 'vs/base/common/actions';
import { IAction, IActionRunner, IActionViewItem } from 'vs/base/common/actions';
import { KeyCode } from 'vs/base/common/keyCodes';
import * as dom from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { SelectBox, ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';
import { SelectActionViewItem, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IDebugService, IDebugSession, IDebugConfiguration, IConfig, ILaunch } from 'vs/workbench/contrib/debug/common/debug';
@@ -20,6 +19,7 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ADD_CONFIGURATION_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
const $ = dom.$;

View File

@@ -9,8 +9,8 @@ import * as browser from 'vs/base/browser/browser';
import * as dom from 'vs/base/browser/dom';
import * as arrays from 'vs/base/common/arrays';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { IAction, IRunEvent, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { ActionBar, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, IRunEvent, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, Separator } from 'vs/base/common/actions';
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IDebugConfiguration, IDebugService, State } from 'vs/workbench/contrib/debug/common/debug';
@@ -21,13 +21,12 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { registerThemingParticipant, IThemeService, Themable } from 'vs/platform/theme/common/themeService';
import { registerColor, contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
import { localize } from 'vs/nls';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { createAndFillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
import { createAndFillInActionBarActions, MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, IMenuService, MenuId, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
@@ -57,7 +56,6 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
@IStorageService private readonly storageService: IStorageService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IThemeService themeService: IThemeService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IMenuService menuService: IMenuService,
@IContextMenuService contextMenuService: IContextMenuService,
@@ -80,9 +78,10 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
actionViewItemProvider: (action: IAction) => {
if (action.id === FocusSessionAction.ID) {
return this.instantiationService.createInstance(FocusSessionActionViewItem, action);
}
if (action instanceof MenuItemAction) {
return new MenuEntryActionViewItem(action, this.keybindingService, this.notificationService, contextMenuService);
} else if (action instanceof MenuItemAction) {
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
} else if (action instanceof SubmenuItemAction) {
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
}
return undefined;

View File

@@ -5,9 +5,8 @@
import 'vs/css!./media/debugViewlet';
import * as nls from 'vs/nls';
import { IAction } from 'vs/base/common/actions';
import { IAction, IActionViewItem } from 'vs/base/common/actions';
import * as DOM from 'vs/base/browser/dom';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, IDebugConfiguration, CONTEXT_DEBUG_UX, CONTEXT_DEBUG_UX_KEY, REPL_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
import { StartAction, ConfigureAction, SelectAndStartAction, FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { StartDebugActionViewItem, FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
@@ -24,12 +23,10 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la
import { memoize } from 'vs/base/common/decorators';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ViewPane, ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IMenu, MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
import { IMenu, MenuId, IMenuService, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IViewDescriptorService, IViewsService } from 'vs/workbench/common/views';
import { WelcomeView } from 'vs/workbench/contrib/debug/browser/welcomeView';
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
@@ -55,11 +52,9 @@ export class DebugViewPaneContainer extends ViewPaneContainer {
@IContextMenuService contextMenuService: IContextMenuService,
@IExtensionService extensionService: IExtensionService,
@IConfigurationService configurationService: IConfigurationService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IContextViewService private readonly contextViewService: IContextViewService,
@IMenuService private readonly menuService: IMenuService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@INotificationService private readonly notificationService: INotificationService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService
) {
super(VIEWLET_ID, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
@@ -165,7 +160,9 @@ export class DebugViewPaneContainer extends ViewPaneContainer {
return new FocusSessionActionViewItem(action, this.debugService, this.themeService, this.contextViewService, this.configurationService);
}
if (action instanceof MenuItemAction) {
return new MenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
} else if (action instanceof SubmenuItemAction) {
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
}
return undefined;

View File

@@ -38,7 +38,7 @@
cursor: grabbing;
}
.monaco-workbench .debug-toolbar .monaco-action-bar .action-item > .action-label {
.monaco-workbench .debug-toolbar .monaco-action-bar .action-item .action-label {
width: 32px;
height: 32px;
margin-right: 0;

View File

@@ -5,7 +5,7 @@
import 'vs/css!./media/repl';
import { URI as uri } from 'vs/base/common/uri';
import { IAction, IActionViewItem, Action } from 'vs/base/common/actions';
import { IAction, IActionViewItem, Action, Separator } from 'vs/base/common/actions';
import * as dom from 'vs/base/browser/dom';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -41,7 +41,6 @@ import { first } from 'vs/base/common/arrays';
import { ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { removeAnsiEscapeCodes } from 'vs/base/common/strings';
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
@@ -440,7 +439,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
return this.instantiationService.createInstance(SelectReplActionViewItem, this.selectReplAction);
}
return undefined;
return super.getActionViewItem(action);
}
getActions(): IAction[] {

View File

@@ -13,9 +13,8 @@ import { Variable, Scope, ErrorScope, StackFrame } from 'vs/workbench/contrib/de
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { renderViewTree, renderVariable, IInputBoxOptions, AbstractExpressionsRenderer, IExpressionTemplateData } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { IAction, Action } from 'vs/base/common/actions';
import { IAction, Action, Separator } from 'vs/base/common/actions';
import { CopyValueAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';

View File

@@ -14,8 +14,7 @@ import { AddWatchExpressionAction, RemoveAllWatchExpressionsAction, CopyValueAct
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IAction, Action } from 'vs/base/common/actions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, Action, Separator } from 'vs/base/common/actions';
import { renderExpressionValue, renderViewTree, IInputBoxOptions, AbstractExpressionsRenderer, IExpressionTemplateData } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';

View File

@@ -5,12 +5,11 @@
import 'vs/css!./media/extensionActions';
import { localize } from 'vs/nls';
import { IAction, Action } from 'vs/base/common/actions';
import { IAction, Action, Separator, SubmenuAction } from 'vs/base/common/actions';
import { Delayer } from 'vs/base/common/async';
import * as DOM from 'vs/base/browser/dom';
import { Event } from 'vs/base/common/event';
import * as json from 'vs/base/common/json';
import { ActionViewItem, Separator, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { dispose, Disposable } from 'vs/base/common/lifecycle';
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewPaneContainer, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG, TOGGLE_IGNORE_EXTENSION_ACTION_ID } from 'vs/workbench/contrib/extensions/common/extensions';
@@ -61,6 +60,7 @@ import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/d
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { Codicon } from 'vs/base/common/codicons';
import { IViewsService } from 'vs/workbench/common/views';
import { IActionViewItemOptions, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; // {{SQL CARBON EDIT}}
import product from 'vs/platform/product/common/product';
@@ -729,7 +729,7 @@ export class DropDownMenuActionViewItem extends ExtensionActionViewItem {
}
}
export function getContextMenuActions(menuService: IMenuService, contextKeyService: IContextKeyService, instantiationService: IInstantiationService, extension: IExtension | undefined | null): ExtensionAction[][] {
export function getContextMenuActions(menuService: IMenuService, contextKeyService: IContextKeyService, instantiationService: IInstantiationService, extension: IExtension | undefined | null): IAction[][] {
const scopedContextKeyService = contextKeyService.createScoped();
if (extension) {
scopedContextKeyService.createKey<string>('extension', extension.identifier.id);
@@ -740,9 +740,14 @@ export function getContextMenuActions(menuService: IMenuService, contextKeyServi
}
}
const groups: ExtensionAction[][] = [];
const groups: IAction[][] = [];
const menu = menuService.createMenu(MenuId.ExtensionContext, scopedContextKeyService);
menu.getActions({ shouldForwardArgs: true }).forEach(([, actions]) => groups.push(actions.map(action => instantiationService.createInstance(MenuItemExtensionAction, action))));
menu.getActions({ shouldForwardArgs: true }).forEach(([, actions]) => groups.push(actions.map(action => {
if (action instanceof SubmenuAction) {
return action;
}
return instantiationService.createInstance(MenuItemExtensionAction, action);
})));
menu.dispose();
return groups;
@@ -771,7 +776,7 @@ export class ManageExtensionAction extends ExtensionDropDownAction {
}
async getActionGroups(runningExtensions: IExtensionDescription[]): Promise<IAction[][]> {
const groups: ExtensionAction[][] = [];
const groups: IAction[][] = [];
if (this.extension) {
const actions = await Promise.all([
SetColorThemeAction.create(this.workbenchThemeService, this.instantiationService, this.extension),
@@ -802,7 +807,11 @@ export class ManageExtensionAction extends ExtensionDropDownAction {
getContextMenuActions(this.menuService, this.contextKeyService, this.instantiationService, this.extension).forEach(actions => groups.push(actions));
groups.forEach(group => group.forEach(extensionAction => extensionAction.extension = this.extension));
groups.forEach(group => group.forEach(extensionAction => {
if (extensionAction instanceof ExtensionAction) {
extensionAction.extension = this.extension;
}
}));
return groups;
}
@@ -1769,7 +1778,28 @@ export class ShowPopularExtensionsAction extends Action {
return this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
.then(viewlet => {
viewlet.search('@sort:installs ');
viewlet.search('@popular ');
viewlet.focus();
});
}
}
export class PredefinedExtensionFilterAction extends Action {
constructor(
id: string,
label: string,
private readonly filter: string,
@IViewletService private readonly viewletService: IViewletService
) {
super(id, label, undefined, true);
}
run(): Promise<void> {
return this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
.then(viewlet => {
viewlet.search(`${this.filter} `);
viewlet.focus();
});
}

View File

@@ -10,8 +10,7 @@ import { isPromiseCanceledError } from 'vs/base/common/errors';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { Event as EventOf, Emitter } from 'vs/base/common/event';
import { IAction, Action } from 'vs/base/common/actions';
import { Separator, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, Action, Separator, SubmenuAction } from 'vs/base/common/actions';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { append, $, addClass, toggleClass, Dimension, hide, show } from 'vs/base/browser/dom';
@@ -20,11 +19,12 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, AutoUpdateConfigurationKey, CloseExtensionDetailsOnViewChangeKey } from '../common/extensions';
import {
ShowRecommendedExtensionsAction, /*ShowPopularExtensionsAction,*/
ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, SearchCategoryAction, /*RecentlyPublishedExtensionsAction, */ShowInstalledExtensionsAction, ShowOutdatedExtensionsAction, ShowDisabledExtensionsAction, ShowEnabledExtensionsAction
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, SearchCategoryAction,
/*RecentlyPublishedExtensionsAction, */ShowInstalledExtensionsAction, ShowOutdatedExtensionsAction, ShowDisabledExtensionsAction,
ShowEnabledExtensionsAction, PredefinedExtensionFilterAction
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IWorkbenchExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInFeatureExtensionsView, BuiltInThemesExtensionsView, BuiltInProgrammingLanguageExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView, OutdatedExtensionsView, InstalledExtensionsView, SearchBuiltInExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews';
@@ -59,8 +59,6 @@ import { IPreferencesService } from 'vs/workbench/services/preferences/common/pr
import { DragAndDropObserver } from 'vs/workbench/browser/dnd';
import { URI } from 'vs/base/common/uri';
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
const NonEmptyWorkspaceContext = new RawContextKey<boolean>('nonEmptyWorkspace', false);
const DefaultViewsContext = new RawContextKey<boolean>('defaultExtensionViews', true);
@@ -347,6 +345,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
@IInstantiationService instantiationService: IInstantiationService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
@INotificationService private readonly notificationService: INotificationService,
@IViewletService private readonly viewletService: IViewletService,
@IThemeService themeService: IThemeService,
@@ -497,41 +496,43 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
}
getActions(): IAction[] {
const filterActions: IAction[] = [];
// Local extensions filters
filterActions.push(...[
this.instantiationService.createInstance(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, localize('builtin filter', "Built-in")),
this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, localize('installed filter', "Installed")),
this.instantiationService.createInstance(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, localize('enabled filter', "Enabled")),
this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, localize('disabled filter', "Disabled")),
this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, localize('outdated filter', "Outdated")),
]);
if (this.extensionGalleryService.isEnabled()) {
filterActions.splice(0, 0, ...[
// this.instantiationService.createInstance(PredefinedExtensionFilterAction, 'extensions.filter.featured', localize('featured filter', "Featured"), '@featured'), // {{SQL CARBON EDIT}}
// this.instantiationService.createInstance(PredefinedExtensionFilterAction, 'extensions.filter.popular', localize('most popular filter', "Most Popular"), '@popular'), // {{SQL CARBON EDIT}}
this.instantiationService.createInstance(PredefinedExtensionFilterAction, 'extensions.filter.recommended', localize('most popular recommended', "Recommended"), '@recommended'),
// this.instantiationService.createInstance(RecentlyPublishedExtensionsAction, RecentlyPublishedExtensionsAction.ID, localize('recently published filter', "Recently Published")), // {{SQL CARBON EDIT}}
new SubmenuAction('workbench.extensions.action.filterExtensionsByCategory', localize('filter by category', "Category"), EXTENSION_CATEGORIES.map(category => this.instantiationService.createInstance(SearchCategoryAction, `extensions.actions.searchByCategory.${category}`, category, category))),
new Separator(),
]);
filterActions.push(...[
new Separator(),
new SubmenuAction('workbench.extensions.action.sortBy', localize('sorty by', "Sort By"), [
// this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.install', localize('sort by installs', "Install Count"), this.onSearchChange, 'installs'), // {{SQL CARBON EDIT}}
// this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.rating', localize('sort by rating', "Rating"), this.onSearchChange, 'rating'), // {{SQL CARBON EDIT}}
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.name', localize('sort by name', "Name"), this.onSearchChange, 'name'),
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.publishedDate', localize('sort by date', "Published Date"), this.onSearchChange, 'publishedDate'),
]),
]);
}
return [
new Action('workbench.extensions.action.filterExtensions', localize('filterExtensions', "Filter Extensions..."), 'codicon-filter', true),
new SubmenuAction('workbench.extensions.action.filterExtensions', localize('filterExtensions', "Filter Extensions..."), filterActions, 'codicon-filter'),
this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, this.searchBox ? this.searchBox.getValue() : ''),
];
}
getActionViewItem(action: IAction): IActionViewItem | undefined {
if (action.id === 'workbench.extensions.action.filterExtensions') {
return new DropdownMenuActionViewItem(action,
[
// this.instantiationService.createInstance(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, localize('most popular filter', "Most Popular")), // {{SQL CARBON EDIT}}
// this.instantiationService.createInstance(RecentlyPublishedExtensionsAction, RecentlyPublishedExtensionsAction.ID, localize('recently published filter', "Recently Published")), // {{SQL CARBON EDIT}}
this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('recomended filter', "Recommended")),
new ContextSubMenu(localize('filter by category', "Category"), EXTENSION_CATEGORIES.map(category => this.instantiationService.createInstance(SearchCategoryAction, `extensions.actions.searchByCategory.${category}`, category, category))),
new Separator(),
this.instantiationService.createInstance(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, localize('builtin filter', "Built-in")),
this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, localize('installed filter', "Installed")),
this.instantiationService.createInstance(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, localize('enabled filter', "Enabled")),
this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, localize('disabled filter', "Disabled")),
this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, localize('outdated filter', "Outdated")),
new Separator(),
new ContextSubMenu(localize('sorty by', "Sort By"), [
// this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.install', localize('sort by installs', "Install Count"), this.onSearchChange, 'installs'), // {{SQL CARBON EDIT}}
// this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.rating', localize('sort by rating', "Rating"), this.onSearchChange, 'rating'), // {{SQL CARBON EDIT}}
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.name', localize('sort by name', "Name"), this.onSearchChange, 'name'),
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.publishedDate', localize('sort by date', "Published Date"), this.onSearchChange, 'publishedDate'),
]),
],
this.contextMenuService, undefined, undefined, undefined, 'codicon-filter', undefined, true);
}
return super.getActionViewItem(action);
}
getSecondaryActions(): IAction[] {
const actions: IAction[] = [];
@@ -541,11 +542,13 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
} else {
actions.push(this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL));
}
actions.push(this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL));
actions.push(new Separator());
actions.push(this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL));
actions.push(this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL));
actions.push(this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL));
actions.push(new Separator());
actions.push(this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL));
return actions;
}
@@ -565,7 +568,14 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
}
private normalizedQuery(): string {
return this.searchBox ? this.searchBox.getValue().replace(/@category/g, 'category').replace(/@tag:/g, 'tag:').replace(/@ext:/g, 'ext:') : '';
return this.searchBox
? this.searchBox.getValue()
.replace(/@category/g, 'category')
.replace(/@tag:/g, 'tag:')
.replace(/@ext:/g, 'ext:')
.replace(/@featured/g, 'featured')
.replace(/@popular/g, '@sort:installs')
: '';
}
saveState(): void {

View File

@@ -25,8 +25,7 @@ import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction, InstallLocalExtensionsInRemoteAction, getContextMenuActions } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction, InstallLocalExtensionsInRemoteAction, getContextMenuActions, ExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { WorkbenchPagedList, ListResourceNavigator } from 'vs/platform/list/browser/listService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
@@ -38,7 +37,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria';
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IAction, Action } from 'vs/base/common/actions';
import { IAction, Action, Separator } from 'vs/base/common/actions';
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { IProductService } from 'vs/platform/product/common/productService';
@@ -248,7 +247,11 @@ export class ExtensionsListView extends ViewPane {
});
} else if (e.element) {
const groups = getContextMenuActions(this.menuService, this.contextKeyService.createScoped(), this.instantiationService, e.element);
groups.forEach(group => group.forEach(extensionAction => extensionAction.extension = e.element!));
groups.forEach(group => group.forEach(extensionAction => {
if (extensionAction instanceof ExtensionAction) {
extensionAction.extension = e.element!;
}
}));
let actions: IAction[] = [];
for (const menuActions of groups) {
actions = [...actions, ...menuActions, new Separator()];

View File

@@ -40,6 +40,7 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { asDomUri } from 'vs/base/browser/dom';
import { getIgnoredExtensions } from 'vs/platform/userDataSync/common/extensionsMerge';
import { isWeb } from 'vs/base/common/platform';
import { getExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil';
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; // {{SQL CARBON EDIT}}
import { IOpenerService } from 'vs/platform/opener/common/opener'; // {{SQL CARBON EDIT}}
@@ -686,14 +687,79 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
if (extensions.length === 1) {
return extensions[0];
}
const enabledExtensions = extensions.filter(e => e.local && this.extensionEnablementService.isEnabled(e.local));
if (enabledExtensions.length === 0) {
return extensions[0];
}
if (enabledExtensions.length === 1) {
return enabledExtensions[0];
}
return enabledExtensions.find(e => e.server === this.extensionManagementServerService.remoteExtensionManagementServer) || enabledExtensions[0];
const extensionsToChoose = enabledExtensions.length ? enabledExtensions : extensions;
let extension = extensionsToChoose.find(extension => {
for (const extensionKind of getExtensionKind(extension.local!.manifest, this.productService, this.configurationService)) {
switch (extensionKind) {
case 'ui':
/* UI extension is chosen only if it is installed locally */
if (extension.server === this.extensionManagementServerService.localExtensionManagementServer) {
return true;
}
return false;
case 'workspace':
/* Choose remote workspace extension if exists */
if (extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
return true;
}
return false;
case 'web':
/* Choose web extension if exists */
if (extension.server === this.extensionManagementServerService.webExtensionManagementServer) {
return true;
}
return false;
}
}
return false;
});
if (!extension && this.extensionManagementServerService.localExtensionManagementServer) {
extension = extensionsToChoose.find(extension => {
for (const extensionKind of getExtensionKind(extension.local!.manifest, this.productService, this.configurationService)) {
switch (extensionKind) {
case 'workspace':
/* Choose local workspace extension if exists */
if (extension.server === this.extensionManagementServerService.localExtensionManagementServer) {
return true;
}
return false;
case 'web':
/* Choose local web extension if exists */
if (extension.server === this.extensionManagementServerService.localExtensionManagementServer) {
return true;
}
return false;
}
}
return false;
});
}
if (!extension && this.extensionManagementServerService.remoteExtensionManagementServer) {
extension = extensionsToChoose.find(extension => {
for (const extensionKind of getExtensionKind(extension.local!.manifest, this.productService, this.configurationService)) {
switch (extensionKind) {
case 'web':
/* Choose remote web extension if exists */
if (extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
return true;
}
return false;
}
}
return false;
});
}
return extension || extensions[0];
}
private fromGallery(gallery: IGalleryExtension, maliciousExtensionSet: Set<string>): IExtension {

View File

@@ -7,7 +7,7 @@ import 'vs/css!./media/runtimeExtensionsEditor';
import * as nls from 'vs/nls';
import * as os from 'os';
import { IProductService } from 'vs/platform/product/common/productService';
import { Action, IAction } from 'vs/base/common/actions';
import { Action, IAction, Separator } from 'vs/base/common/actions';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
@@ -18,7 +18,7 @@ import { IExtensionService, IExtensionsStatus, IExtensionHostProfile } from 'vs/
import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';
import { WorkbenchList } from 'vs/platform/list/browser/listService';
import { append, $, addClass, toggleClass, Dimension, clearNode } from 'vs/base/browser/dom';
import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
@@ -164,16 +164,17 @@ export class RuntimeExtensionsEditor extends BaseEditor {
this._register(this._extensionService.onDidChangeExtensionsStatus(() => this._updateSoon.schedule()));
}
private _updateExtensions(): void {
this._elements = this._resolveExtensions();
private async _updateExtensions(): Promise<void> {
this._elements = await this._resolveExtensions();
if (this._list) {
this._list.splice(0, this._list.length, this._elements);
}
}
private _resolveExtensions(): IRuntimeExtension[] {
private async _resolveExtensions(): Promise<IRuntimeExtension[]> {
let marketplaceMap: { [id: string]: IExtension; } = Object.create(null);
for (let extension of this._extensionsWorkbenchService.local) {
const marketPlaceExtensions = await this._extensionsWorkbenchService.queryLocal();
for (let extension of marketPlaceExtensions) {
marketplaceMap[ExtensionIdentifier.toKey(extension.identifier.id)] = extension;
}
@@ -328,7 +329,7 @@ export class RuntimeExtensionsEditor extends BaseEditor {
} else {
data.icon.style.visibility = 'inherit';
}
data.name.textContent = element.marketplaceInfo ? element.marketplaceInfo.displayName : element.description.displayName || '';
data.name.textContent = element.marketplaceInfo.displayName;
data.version.textContent = element.description.version;
const activationTimes = element.status.activationTimes!;
@@ -462,11 +463,10 @@ export class RuntimeExtensionsEditor extends BaseEditor {
actions.push(new ReportExtensionIssueAction(e.element, this._openerService, this._clipboardService, this._productService));
actions.push(new Separator());
if (e.element.marketplaceInfo) {
actions.push(new Action('runtimeExtensionsEditor.action.disableWorkspace', nls.localize('disable workspace', "Disable (Workspace)"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.DisabledWorkspace)));
actions.push(new Action('runtimeExtensionsEditor.action.disable', nls.localize('disable', "Disable"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.DisabledGlobally)));
actions.push(new Separator());
}
actions.push(new Action('runtimeExtensionsEditor.action.disableWorkspace', nls.localize('disable workspace', "Disable (Workspace)"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.DisabledWorkspace)));
actions.push(new Action('runtimeExtensionsEditor.action.disable', nls.localize('disable', "Disable"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.DisabledGlobally)));
actions.push(new Separator());
const state = this._extensionHostProfileService.state;
if (state === ProfileSessionState.Running) {
actions.push(this._instantiationService.createInstance(StopExtensionHostProfileAction, StopExtensionHostProfileAction.ID, StopExtensionHostProfileAction.LABEL));

View File

@@ -14,7 +14,7 @@ import {
IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension,
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier, InstallOperation, IExtensionTipsService, IGalleryMetadata
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionRecommendationsService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
@@ -34,7 +34,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { NativeURLService } from 'vs/platform/url/common/urlService';
import { URI } from 'vs/base/common/uri';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { ExtensionType, IExtension, ExtensionKind } from 'vs/platform/extensions/common/extensions';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
@@ -46,6 +46,8 @@ import { TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestSer
import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
import { ExtensionTipsService } from 'vs/platform/extensionManagement/node/extensionTipsService';
import { Schemas } from 'vs/base/common/network';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
suite('ExtensionsWorkbenchServiceTest', () => {
@@ -981,6 +983,384 @@ suite('ExtensionsWorkbenchServiceTest', () => {
assert.equal(actual[0].enablementState, EnablementState.DisabledWorkspace);
});
test('test user extension is preferred when the same extension exists as system and user extension', async () => {
testObject = await aWorkbenchService();
const userExtension = aLocalExtension('pub.a');
const systemExtension = aLocalExtension('pub.a', {}, { type: ExtensionType.System });
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [systemExtension, userExtension]);
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, userExtension);
});
test('test user extension is disabled when the same extension exists as system and user extension and system extension is disabled', async () => {
testObject = await aWorkbenchService();
const systemExtension = aLocalExtension('pub.a', {}, { type: ExtensionType.System });
await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([systemExtension], EnablementState.DisabledGlobally);
const userExtension = aLocalExtension('pub.a');
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [systemExtension, userExtension]);
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, userExtension);
assert.equal(actual[0].enablementState, EnablementState.DisabledGlobally);
});
test('Test local ui extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['ui'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local workspace extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local web extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['web'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local ui,workspace extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['ui', 'workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local workspace,ui extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['workspace', 'ui'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local ui,workspace,web extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['ui', 'workspace', 'web'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local ui,web,workspace extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['ui', 'web', 'workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local web,ui,workspace extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['web', 'ui', 'workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local web,workspace,ui extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['web', 'workspace', 'ui'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local workspace,web,ui extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['workspace', 'web', 'ui'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local workspace,ui,web extension is chosen if it exists only in local server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['workspace', 'ui', 'web'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local UI extension is chosen if it exists in both servers', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['ui'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test local ui,workspace extension is chosen if it exists in both servers', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['ui', 'workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test remote workspace extension is chosen if it exists in remote server', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['workspace'];
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, remoteExtension);
});
test('Test remote workspace extension is chosen if it exists in both servers', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, remoteExtension);
});
test('Test remote workspace extension is chosen if it exists in both servers and local is disabled', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([localExtension], EnablementState.DisabledGlobally);
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, remoteExtension);
assert.equal(actual[0].enablementState, EnablementState.DisabledGlobally);
});
test('Test remote workspace extension is chosen if it exists in both servers and remote is disabled in workspace', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([remoteExtension], EnablementState.DisabledWorkspace);
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, remoteExtension);
assert.equal(actual[0].enablementState, EnablementState.DisabledWorkspace);
});
test('Test local ui, workspace extension is chosen if it exists in both servers and local is disabled', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['ui', 'workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([localExtension], EnablementState.DisabledGlobally);
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
assert.equal(actual[0].enablementState, EnablementState.DisabledGlobally);
});
test('Test local ui, workspace extension is chosen if it exists in both servers and local is disabled in workspace', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['ui', 'workspace'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([localExtension], EnablementState.DisabledWorkspace);
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
assert.equal(actual[0].enablementState, EnablementState.DisabledWorkspace);
});
test('Test local web extension is chosen if it exists in both servers', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['web'];
const localExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`) });
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, localExtension);
});
test('Test remote web extension is chosen if it exists only in remote', async () => {
// multi server setup
const extensionKind: ExtensionKind[] = ['web'];
const remoteExtension = aLocalExtension('a', { extensionKind }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([]), createExtensionManagementService([remoteExtension]));
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
testObject = await aWorkbenchService();
const actual = await testObject.queryLocal();
assert.equal(actual.length, 1);
assert.equal(actual[0].local, remoteExtension);
});
async function aWorkbenchService(): Promise<ExtensionsWorkbenchService> {
const workbenchService: ExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
await workbenchService.queryLocal();
@@ -1031,4 +1411,49 @@ suite('ExtensionsWorkbenchServiceTest', () => {
});
});
}
function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService, localExtensionManagementService?: IExtensionManagementService, remoteExtensionManagementService?: IExtensionManagementService): IExtensionManagementServerService {
const localExtensionManagementServer: IExtensionManagementServer = {
id: 'vscode-local',
label: 'local',
extensionManagementService: localExtensionManagementService || createExtensionManagementService()
};
const remoteExtensionManagementServer: IExtensionManagementServer = {
id: 'vscode-remote',
label: 'remote',
extensionManagementService: remoteExtensionManagementService || createExtensionManagementService()
};
return {
_serviceBrand: undefined,
localExtensionManagementServer,
remoteExtensionManagementServer,
webExtensionManagementServer: null,
getExtensionManagementServer: (extension: IExtension) => {
if (extension.location.scheme === Schemas.file) {
return localExtensionManagementServer;
}
if (extension.location.scheme === REMOTE_HOST_SCHEME) {
return remoteExtensionManagementServer;
}
throw new Error('');
}
};
}
function createExtensionManagementService(installed: ILocalExtension[] = []): IExtensionManagementService {
return <IExtensionManagementService>{
onInstallExtension: Event.None,
onDidInstallExtension: Event.None,
onUninstallExtension: Event.None,
onDidUninstallExtension: Event.None,
getInstalled: () => Promise.resolve<ILocalExtension[]>(installed),
installFromGallery: (extension: IGalleryExtension) => Promise.reject(new Error('not supported')),
updateMetadata: async (local: ILocalExtension, metadata: IGalleryMetadata) => {
local.identifier.uuid = metadata.id;
local.publisherDisplayName = metadata.publisherDisplayName;
local.publisherId = metadata.publisherId;
return local;
}
};
}
});

View File

@@ -16,7 +16,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { ActionBar, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { QuickFixAction, QuickFixActionViewItem } from 'vs/workbench/contrib/markers/browser/markersViewActions';
import { ILabelService } from 'vs/platform/label/common/label';
import { dirname, basename, isEqual } from 'vs/base/common/resources';
@@ -52,6 +52,7 @@ import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Progress } from 'vs/platform/progress/common/progress';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
export type TreeElement = ResourceMarkers | Marker | RelatedInformation;

View File

@@ -7,7 +7,7 @@ import 'vs/css!./media/markers';
import { URI } from 'vs/base/common/uri';
import * as dom from 'vs/base/browser/dom';
import { IAction, IActionViewItem, Action } from 'vs/base/common/actions';
import { IAction, IActionViewItem, Action, Separator } from 'vs/base/common/actions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import Constants from 'vs/workbench/contrib/markers/browser/constants';
@@ -33,7 +33,7 @@ import { deepClone } from 'vs/base/common/objects';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, TreeElement, MarkersTreeAccessibilityProvider, MarkersViewModel, ResourceDragAndDrop } from 'vs/workbench/contrib/markers/browser/markersTreeViewer';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Separator, ActionViewItem, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IMenuService, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
@@ -50,6 +50,7 @@ import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/vie
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { Codicon } from 'vs/base/common/codicons';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
function createResourceMarkersIterator(resourceMarkers: ResourceMarkers): Iterable<ITreeElement<TreeElement>> {
return Iterable.map(resourceMarkers.markers, m => {

View File

@@ -5,7 +5,7 @@
import { Delayer } from 'vs/base/common/async';
import * as DOM from 'vs/base/browser/dom';
import { Action, IAction, IActionRunner } from 'vs/base/common/actions';
import { Action, IAction, IActionRunner, Separator } from 'vs/base/common/actions';
import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';
import { KeyCode } from 'vs/base/common/keyCodes';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
@@ -15,7 +15,7 @@ import Constants from 'vs/workbench/contrib/markers/browser/constants';
import { IThemeService, registerThemingParticipant, ICssStyleCollector, IColorTheme } from 'vs/platform/theme/common/themeService';
import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
import { toDisposable, Disposable } from 'vs/base/common/lifecycle';
import { BaseActionViewItem, ActionViewItem, ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { badgeBackground, badgeForeground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground } from 'vs/platform/theme/common/colorRegistry';
import { localize } from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -23,10 +23,11 @@ import { ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedH
import { Marker } from 'vs/workbench/contrib/markers/browser/markersModel';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Event, Emitter } from 'vs/base/common/event';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { IViewsService } from 'vs/workbench/common/views';
import { Codicon } from 'vs/base/common/codicons';
import { BaseActionViewItem, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
export class ShowProblemsPanelAction extends Action {
@@ -179,11 +180,12 @@ class FiltersDropdownMenuActionViewItem extends DropdownMenuActionViewItem {
super(action,
{ getActions: () => this.getActions() },
contextMenuService,
action => undefined,
actionRunner!,
undefined,
action.class,
() => { return AnchorAlignment.RIGHT; });
{
actionRunner,
classNames: action.class,
anchorAlignmentProvider: () => AnchorAlignment.RIGHT
}
);
}
render(container: HTMLElement): void {

View File

@@ -18,7 +18,7 @@ export const BOTTOM_CELL_TOOLBAR_OFFSET = 12;
export const CELL_STATUSBAR_HEIGHT = 22;
// Margin above editor
export const EDITOR_TOP_MARGIN = 6;
export const CELL_TOP_MARGIN = 6;
export const CELL_BOTTOM_MARGIN = 6;
// Top and bottom padding inside the monaco editor in a cell, which are included in `cell.editorHeight`
@@ -26,3 +26,5 @@ export const EDITOR_TOP_PADDING = 12;
export const EDITOR_BOTTOM_PADDING = 4;
export const CELL_OUTPUT_PADDING = 14;
export const COLLAPSED_INDICATOR_HEIGHT = 24;

Some files were not shown because too many files have changed in this diff Show More