awa
This commit is contained in:
@@ -0,0 +1,336 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as dom from '../../../base/browser/dom.js';
|
||||
import { KeybindingLabel } from '../../../base/browser/ui/keybindingLabel/keybindingLabel.js';
|
||||
import { List } from '../../../base/browser/ui/list/listWidget.js';
|
||||
import { CancellationTokenSource } from '../../../base/common/cancellation.js';
|
||||
import { Codicon } from '../../../base/common/codicons.js';
|
||||
import { Disposable } from '../../../base/common/lifecycle.js';
|
||||
import { OS } from '../../../base/common/platform.js';
|
||||
import { ThemeIcon } from '../../../base/common/themables.js';
|
||||
import './actionWidget.css';
|
||||
import { localize } from '../../../nls.js';
|
||||
import { IContextViewService } from '../../contextview/browser/contextView.js';
|
||||
import { IKeybindingService } from '../../keybinding/common/keybinding.js';
|
||||
import { defaultListStyles } from '../../theme/browser/defaultStyles.js';
|
||||
import { asCssVariable } from '../../theme/common/colorRegistry.js';
|
||||
import { ILayoutService } from '../../layout/browser/layoutService.js';
|
||||
export const acceptSelectedActionCommand = 'acceptSelectedCodeAction';
|
||||
export const previewSelectedActionCommand = 'previewSelectedCodeAction';
|
||||
class HeaderRenderer {
|
||||
get templateId() { return "header" /* ActionListItemKind.Header */; }
|
||||
renderTemplate(container) {
|
||||
container.classList.add('group-header');
|
||||
const text = document.createElement('span');
|
||||
container.append(text);
|
||||
return { container, text };
|
||||
}
|
||||
renderElement(element, _index, templateData) {
|
||||
templateData.text.textContent = element.group?.title ?? element.label ?? '';
|
||||
}
|
||||
disposeTemplate(_templateData) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
class SeparatorRenderer {
|
||||
get templateId() { return "separator" /* ActionListItemKind.Separator */; }
|
||||
renderTemplate(container) {
|
||||
container.classList.add('separator');
|
||||
const text = document.createElement('span');
|
||||
container.append(text);
|
||||
return { container, text };
|
||||
}
|
||||
renderElement(element, _index, templateData) {
|
||||
templateData.text.textContent = element.label ?? '';
|
||||
}
|
||||
disposeTemplate(_templateData) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
let ActionItemRenderer = class ActionItemRenderer {
|
||||
get templateId() { return "action" /* ActionListItemKind.Action */; }
|
||||
constructor(_supportsPreview, _keybindingService) {
|
||||
this._supportsPreview = _supportsPreview;
|
||||
this._keybindingService = _keybindingService;
|
||||
}
|
||||
renderTemplate(container) {
|
||||
container.classList.add(this.templateId);
|
||||
const icon = document.createElement('div');
|
||||
icon.className = 'icon';
|
||||
container.append(icon);
|
||||
const text = document.createElement('span');
|
||||
text.className = 'title';
|
||||
container.append(text);
|
||||
const description = document.createElement('span');
|
||||
description.className = 'description';
|
||||
container.append(description);
|
||||
const keybinding = new KeybindingLabel(container, OS);
|
||||
return { container, icon, text, description, keybinding };
|
||||
}
|
||||
renderElement(element, _index, data) {
|
||||
if (element.group?.icon) {
|
||||
data.icon.className = ThemeIcon.asClassName(element.group.icon);
|
||||
if (element.group.icon.color) {
|
||||
data.icon.style.color = asCssVariable(element.group.icon.color.id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
data.icon.className = ThemeIcon.asClassName(Codicon.lightBulb);
|
||||
data.icon.style.color = 'var(--vscode-editorLightBulb-foreground)';
|
||||
}
|
||||
if (!element.item || !element.label) {
|
||||
return;
|
||||
}
|
||||
dom.setVisibility(!element.hideIcon, data.icon);
|
||||
data.text.textContent = stripNewlines(element.label);
|
||||
// if there is a keybinding, prioritize over description for now
|
||||
if (element.keybinding) {
|
||||
data.description.textContent = element.keybinding.getLabel();
|
||||
data.description.style.display = 'inline';
|
||||
data.description.style.letterSpacing = '0.5px';
|
||||
}
|
||||
else if (element.description) {
|
||||
data.description.textContent = stripNewlines(element.description);
|
||||
data.description.style.display = 'inline';
|
||||
}
|
||||
else {
|
||||
data.description.textContent = '';
|
||||
data.description.style.display = 'none';
|
||||
}
|
||||
const actionTitle = this._keybindingService.lookupKeybinding(acceptSelectedActionCommand)?.getLabel();
|
||||
const previewTitle = this._keybindingService.lookupKeybinding(previewSelectedActionCommand)?.getLabel();
|
||||
data.container.classList.toggle('option-disabled', element.disabled);
|
||||
if (element.tooltip) {
|
||||
data.container.title = element.tooltip;
|
||||
}
|
||||
else if (element.disabled) {
|
||||
data.container.title = element.label;
|
||||
}
|
||||
else if (actionTitle && previewTitle) {
|
||||
if (this._supportsPreview && element.canPreview) {
|
||||
data.container.title = localize(1638, "{0} to Apply, {1} to Preview", actionTitle, previewTitle);
|
||||
}
|
||||
else {
|
||||
data.container.title = localize(1639, "{0} to Apply", actionTitle);
|
||||
}
|
||||
}
|
||||
else {
|
||||
data.container.title = '';
|
||||
}
|
||||
}
|
||||
disposeTemplate(templateData) {
|
||||
templateData.keybinding.dispose();
|
||||
}
|
||||
};
|
||||
ActionItemRenderer = __decorate([
|
||||
__param(1, IKeybindingService)
|
||||
], ActionItemRenderer);
|
||||
class AcceptSelectedEvent extends UIEvent {
|
||||
constructor() { super('acceptSelectedAction'); }
|
||||
}
|
||||
class PreviewSelectedEvent extends UIEvent {
|
||||
constructor() { super('previewSelectedAction'); }
|
||||
}
|
||||
function getKeyboardNavigationLabel(item) {
|
||||
// Filter out header vs. action vs. separator
|
||||
if (item.kind === 'action') {
|
||||
return item.label;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
let ActionList = class ActionList extends Disposable {
|
||||
constructor(user, preview, items, _delegate, accessibilityProvider, _contextViewService, _keybindingService, _layoutService) {
|
||||
super();
|
||||
this._delegate = _delegate;
|
||||
this._contextViewService = _contextViewService;
|
||||
this._keybindingService = _keybindingService;
|
||||
this._layoutService = _layoutService;
|
||||
this._actionLineHeight = 28;
|
||||
this._headerLineHeight = 28;
|
||||
this._separatorLineHeight = 8;
|
||||
this.cts = this._register(new CancellationTokenSource());
|
||||
this.domNode = document.createElement('div');
|
||||
this.domNode.classList.add('actionList');
|
||||
const virtualDelegate = {
|
||||
getHeight: element => {
|
||||
switch (element.kind) {
|
||||
case "header" /* ActionListItemKind.Header */:
|
||||
return this._headerLineHeight;
|
||||
case "separator" /* ActionListItemKind.Separator */:
|
||||
return this._separatorLineHeight;
|
||||
default:
|
||||
return this._actionLineHeight;
|
||||
}
|
||||
},
|
||||
getTemplateId: element => element.kind
|
||||
};
|
||||
this._list = this._register(new List(user, this.domNode, virtualDelegate, [
|
||||
new ActionItemRenderer(preview, this._keybindingService),
|
||||
new HeaderRenderer(),
|
||||
new SeparatorRenderer(),
|
||||
], {
|
||||
keyboardSupport: false,
|
||||
typeNavigationEnabled: true,
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel },
|
||||
accessibilityProvider: {
|
||||
getAriaLabel: element => {
|
||||
if (element.kind === "action" /* ActionListItemKind.Action */) {
|
||||
let label = element.label ? stripNewlines(element?.label) : '';
|
||||
if (element.description) {
|
||||
label = label + ', ' + stripNewlines(element.description);
|
||||
}
|
||||
if (element.disabled) {
|
||||
label = localize(1640, "{0}, Disabled Reason: {1}", label, element.disabled);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getWidgetAriaLabel: () => localize(1641, "Action Widget"),
|
||||
getRole: (e) => {
|
||||
switch (e.kind) {
|
||||
case "action" /* ActionListItemKind.Action */:
|
||||
return 'option';
|
||||
case "separator" /* ActionListItemKind.Separator */:
|
||||
return 'separator';
|
||||
default:
|
||||
return 'separator';
|
||||
}
|
||||
},
|
||||
getWidgetRole: () => 'listbox',
|
||||
...accessibilityProvider
|
||||
},
|
||||
}));
|
||||
this._list.style(defaultListStyles);
|
||||
this._register(this._list.onMouseClick(e => this.onListClick(e)));
|
||||
this._register(this._list.onMouseOver(e => this.onListHover(e)));
|
||||
this._register(this._list.onDidChangeFocus(() => this.onFocus()));
|
||||
this._register(this._list.onDidChangeSelection(e => this.onListSelection(e)));
|
||||
this._allMenuItems = items;
|
||||
this._list.splice(0, this._list.length, this._allMenuItems);
|
||||
if (this._list.length) {
|
||||
this.focusNext();
|
||||
}
|
||||
}
|
||||
focusCondition(element) {
|
||||
return !element.disabled && element.kind === "action" /* ActionListItemKind.Action */;
|
||||
}
|
||||
hide(didCancel) {
|
||||
this._delegate.onHide(didCancel);
|
||||
this.cts.cancel();
|
||||
this._contextViewService.hideContextView();
|
||||
}
|
||||
layout(minWidth) {
|
||||
// Updating list height, depending on how many separators and headers there are.
|
||||
const numHeaders = this._allMenuItems.filter(item => item.kind === 'header').length;
|
||||
const numSeparators = this._allMenuItems.filter(item => item.kind === 'separator').length;
|
||||
const itemsHeight = this._allMenuItems.length * this._actionLineHeight;
|
||||
const heightWithHeaders = itemsHeight + numHeaders * this._headerLineHeight - numHeaders * this._actionLineHeight;
|
||||
const heightWithSeparators = heightWithHeaders + numSeparators * this._separatorLineHeight - numSeparators * this._actionLineHeight;
|
||||
this._list.layout(heightWithSeparators);
|
||||
let maxWidth = minWidth;
|
||||
if (this._allMenuItems.length >= 50) {
|
||||
maxWidth = 380;
|
||||
}
|
||||
else {
|
||||
// For finding width dynamically (not using resize observer)
|
||||
const itemWidths = this._allMenuItems.map((_, index) => {
|
||||
const element = this.domNode.ownerDocument.getElementById(this._list.getElementID(index));
|
||||
if (element) {
|
||||
element.style.width = 'auto';
|
||||
const width = element.getBoundingClientRect().width;
|
||||
element.style.width = '';
|
||||
return width;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
// resize observer - can be used in the future since list widget supports dynamic height but not width
|
||||
maxWidth = Math.max(...itemWidths, minWidth);
|
||||
}
|
||||
const maxVhPrecentage = 0.7;
|
||||
const height = Math.min(heightWithSeparators, this._layoutService.getContainer(dom.getWindow(this.domNode)).clientHeight * maxVhPrecentage);
|
||||
this._list.layout(height, maxWidth);
|
||||
this.domNode.style.height = `${height}px`;
|
||||
this._list.domFocus();
|
||||
return maxWidth;
|
||||
}
|
||||
focusPrevious() {
|
||||
this._list.focusPrevious(1, true, undefined, this.focusCondition);
|
||||
}
|
||||
focusNext() {
|
||||
this._list.focusNext(1, true, undefined, this.focusCondition);
|
||||
}
|
||||
acceptSelected(preview) {
|
||||
const focused = this._list.getFocus();
|
||||
if (focused.length === 0) {
|
||||
return;
|
||||
}
|
||||
const focusIndex = focused[0];
|
||||
const element = this._list.element(focusIndex);
|
||||
if (!this.focusCondition(element)) {
|
||||
return;
|
||||
}
|
||||
const event = preview ? new PreviewSelectedEvent() : new AcceptSelectedEvent();
|
||||
this._list.setSelection([focusIndex], event);
|
||||
}
|
||||
onListSelection(e) {
|
||||
if (!e.elements.length) {
|
||||
return;
|
||||
}
|
||||
const element = e.elements[0];
|
||||
if (element.item && this.focusCondition(element)) {
|
||||
this._delegate.onSelect(element.item, e.browserEvent instanceof PreviewSelectedEvent);
|
||||
}
|
||||
else {
|
||||
this._list.setSelection([]);
|
||||
}
|
||||
}
|
||||
onFocus() {
|
||||
const focused = this._list.getFocus();
|
||||
if (focused.length === 0) {
|
||||
return;
|
||||
}
|
||||
const focusIndex = focused[0];
|
||||
const element = this._list.element(focusIndex);
|
||||
this._delegate.onFocus?.(element.item);
|
||||
}
|
||||
async onListHover(e) {
|
||||
const element = e.element;
|
||||
if (element && element.item && this.focusCondition(element)) {
|
||||
if (this._delegate.onHover && !element.disabled && element.kind === "action" /* ActionListItemKind.Action */) {
|
||||
const result = await this._delegate.onHover(element.item, this.cts.token);
|
||||
element.canPreview = result ? result.canPreview : undefined;
|
||||
}
|
||||
if (e.index) {
|
||||
this._list.splice(e.index, 1, [element]);
|
||||
}
|
||||
}
|
||||
this._list.setFocus(typeof e.index === 'number' ? [e.index] : []);
|
||||
}
|
||||
onListClick(e) {
|
||||
if (e.element && this.focusCondition(e.element)) {
|
||||
this._list.setFocus([]);
|
||||
}
|
||||
}
|
||||
};
|
||||
ActionList = __decorate([
|
||||
__param(5, IContextViewService),
|
||||
__param(6, IKeybindingService),
|
||||
__param(7, ILayoutService)
|
||||
], ActionList);
|
||||
export { ActionList };
|
||||
function stripNewlines(str) {
|
||||
return str.replace(/\r\n|\r|\n/g, ' ');
|
||||
}
|
||||
//# sourceMappingURL=actionList.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,197 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.action-widget {
|
||||
font-size: 13px;
|
||||
border-radius: 0;
|
||||
min-width: 100px;
|
||||
max-width: 80vw;
|
||||
z-index: 40;
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: 1px solid var(--vscode-menu-border) !important;
|
||||
border-radius: 5px;
|
||||
background-color: var(--vscode-menu-background);
|
||||
color: var(--vscode-menu-foreground);
|
||||
padding: 4px;
|
||||
box-shadow: 0 2px 8px var(--vscode-widget-shadow);
|
||||
}
|
||||
|
||||
.context-view-block {
|
||||
position: fixed;
|
||||
cursor: initial;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.context-view-pointerBlock {
|
||||
position: fixed;
|
||||
cursor: initial;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
border: none !important;
|
||||
border-width: 0 !important;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list:focus:before {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list .monaco-scrollable-element {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/** Styles for each row in the list element **/
|
||||
.action-widget .monaco-list .monaco-list-row {
|
||||
padding: 0 4px 0 4px;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
touch-action: none;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list .monaco-list-row.action.focused:not(.option-disabled) {
|
||||
background-color: var(--vscode-list-activeSelectionBackground) !important;
|
||||
color: var(--vscode-list-activeSelectionForeground);
|
||||
outline: 1px solid var(--vscode-menu-selectionBorder, transparent);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list-row.group-header {
|
||||
color: var(--vscode-descriptionForeground) !important;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list-row.group-header:not(:first-of-type) {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.action-widget .monaco-scrollable-element .monaco-list-rows .monaco-list-row.separator {
|
||||
border-top: 1px solid var(--vscode-editorHoverWidget-border);
|
||||
color: var(--vscode-descriptionForeground);
|
||||
font-size: 12px;
|
||||
padding: 0;
|
||||
margin: 4px 0 0 0;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.action-widget .monaco-scrollable-element .monaco-list-rows .monaco-list-row.separator.focused {
|
||||
outline: 0 solid;
|
||||
background-color: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list-row.separator:first-of-type {
|
||||
border-top: none;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list .group-header,
|
||||
.action-widget .monaco-list .option-disabled,
|
||||
.action-widget .monaco-list .option-disabled:before,
|
||||
.action-widget .monaco-list .option-disabled .focused,
|
||||
.action-widget .monaco-list .option-disabled .focused:before {
|
||||
cursor: default !important;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
background-color: transparent !important;
|
||||
outline: 0 solid !important;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list-row.action {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list-row.action.option-disabled,
|
||||
.action-widget .monaco-list:focus .monaco-list-row.focused.action.option-disabled,
|
||||
.action-widget .monaco-list-row.action.option-disabled .codicon,
|
||||
.action-widget .monaco-list:not(.drop-target):not(.dragging) .monaco-list-row:hover:not(.selected):not(.focused).option-disabled {
|
||||
color: var(--vscode-disabledForeground);
|
||||
}
|
||||
|
||||
|
||||
.action-widget .monaco-list-row.action:not(.option-disabled) .codicon {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list-row.action .title {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list-row.action .monaco-keybinding > .monaco-keybinding-key {
|
||||
background-color: var(--vscode-keybindingLabel-background);
|
||||
color: var(--vscode-keybindingLabel-foreground);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: 3px;
|
||||
border-color: var(--vscode-keybindingLabel-border);
|
||||
border-bottom-color: var(--vscode-keybindingLabel-bottomBorder);
|
||||
box-shadow: inset 0 -1px 0 var(--vscode-widget-shadow);
|
||||
}
|
||||
|
||||
/* Action bar */
|
||||
|
||||
.action-widget .action-widget-action-bar {
|
||||
background-color: var(--vscode-menu-background);
|
||||
border-top: 1px solid var(--vscode-menu-border);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.action-widget .action-widget-action-bar::before {
|
||||
display: block;
|
||||
content: "";
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action-widget .action-widget-action-bar .actions-container {
|
||||
padding: 4px 8px 2px 24px;
|
||||
}
|
||||
|
||||
.action-widget-action-bar .action-label {
|
||||
color: var(--vscode-textLink-activeForeground);
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
padding: 0;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.action-widget-action-bar .action-item {
|
||||
margin-right: 16px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.action-widget-action-bar .action-label:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.monaco-action-bar .actions-container.highlight-toggled .action-label.checked {
|
||||
/* The important gives this rule precedence over the hover rule. */
|
||||
background: var(--vscode-actionBar-toggledBackground) !important;
|
||||
}
|
||||
|
||||
.action-widget .monaco-list .monaco-list-row .description {
|
||||
opacity: 0.7;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as dom from '../../../base/browser/dom.js';
|
||||
import { ActionBar } from '../../../base/browser/ui/actionbar/actionbar.js';
|
||||
import { Disposable, DisposableStore, MutableDisposable } from '../../../base/common/lifecycle.js';
|
||||
import './actionWidget.css';
|
||||
import { localize, localize2 } from '../../../nls.js';
|
||||
import { acceptSelectedActionCommand, ActionList, previewSelectedActionCommand } from './actionList.js';
|
||||
import { Action2, registerAction2 } from '../../actions/common/actions.js';
|
||||
import { IContextKeyService, RawContextKey } from '../../contextkey/common/contextkey.js';
|
||||
import { IContextViewService } from '../../contextview/browser/contextView.js';
|
||||
import { registerSingleton } from '../../instantiation/common/extensions.js';
|
||||
import { createDecorator, IInstantiationService } from '../../instantiation/common/instantiation.js';
|
||||
import { inputActiveOptionBackground, registerColor } from '../../theme/common/colorRegistry.js';
|
||||
registerColor('actionBar.toggledBackground', inputActiveOptionBackground, localize(1642, 'Background color for toggled action items in action bar.'));
|
||||
const ActionWidgetContextKeys = {
|
||||
Visible: new RawContextKey('codeActionMenuVisible', false, localize(1643, "Whether the action widget list is visible"))
|
||||
};
|
||||
export const IActionWidgetService = createDecorator('actionWidgetService');
|
||||
let ActionWidgetService = class ActionWidgetService extends Disposable {
|
||||
get isVisible() {
|
||||
return ActionWidgetContextKeys.Visible.getValue(this._contextKeyService) || false;
|
||||
}
|
||||
constructor(_contextViewService, _contextKeyService, _instantiationService) {
|
||||
super();
|
||||
this._contextViewService = _contextViewService;
|
||||
this._contextKeyService = _contextKeyService;
|
||||
this._instantiationService = _instantiationService;
|
||||
this._list = this._register(new MutableDisposable());
|
||||
}
|
||||
show(user, supportsPreview, items, delegate, anchor, container, actionBarActions, accessibilityProvider) {
|
||||
const visibleContext = ActionWidgetContextKeys.Visible.bindTo(this._contextKeyService);
|
||||
const list = this._instantiationService.createInstance(ActionList, user, supportsPreview, items, delegate, accessibilityProvider);
|
||||
this._contextViewService.showContextView({
|
||||
getAnchor: () => anchor,
|
||||
render: (container) => {
|
||||
visibleContext.set(true);
|
||||
return this._renderWidget(container, list, actionBarActions ?? []);
|
||||
},
|
||||
onHide: (didCancel) => {
|
||||
visibleContext.reset();
|
||||
this._onWidgetClosed(didCancel);
|
||||
},
|
||||
}, container, false);
|
||||
}
|
||||
acceptSelected(preview) {
|
||||
this._list.value?.acceptSelected(preview);
|
||||
}
|
||||
focusPrevious() {
|
||||
this._list?.value?.focusPrevious();
|
||||
}
|
||||
focusNext() {
|
||||
this._list?.value?.focusNext();
|
||||
}
|
||||
hide(didCancel) {
|
||||
this._list.value?.hide(didCancel);
|
||||
this._list.clear();
|
||||
}
|
||||
_renderWidget(element, list, actionBarActions) {
|
||||
const widget = document.createElement('div');
|
||||
widget.classList.add('action-widget');
|
||||
element.appendChild(widget);
|
||||
this._list.value = list;
|
||||
if (this._list.value) {
|
||||
widget.appendChild(this._list.value.domNode);
|
||||
}
|
||||
else {
|
||||
throw new Error('List has no value');
|
||||
}
|
||||
const renderDisposables = new DisposableStore();
|
||||
// Invisible div to block mouse interaction in the rest of the UI
|
||||
const menuBlock = document.createElement('div');
|
||||
const block = element.appendChild(menuBlock);
|
||||
block.classList.add('context-view-block');
|
||||
renderDisposables.add(dom.addDisposableListener(block, dom.EventType.MOUSE_DOWN, e => e.stopPropagation()));
|
||||
// Invisible div to block mouse interaction with the menu
|
||||
const pointerBlockDiv = document.createElement('div');
|
||||
const pointerBlock = element.appendChild(pointerBlockDiv);
|
||||
pointerBlock.classList.add('context-view-pointerBlock');
|
||||
// Removes block on click INSIDE widget or ANY mouse movement
|
||||
renderDisposables.add(dom.addDisposableListener(pointerBlock, dom.EventType.POINTER_MOVE, () => pointerBlock.remove()));
|
||||
renderDisposables.add(dom.addDisposableListener(pointerBlock, dom.EventType.MOUSE_DOWN, () => pointerBlock.remove()));
|
||||
// Action bar
|
||||
let actionBarWidth = 0;
|
||||
if (actionBarActions.length) {
|
||||
const actionBar = this._createActionBar('.action-widget-action-bar', actionBarActions);
|
||||
if (actionBar) {
|
||||
widget.appendChild(actionBar.getContainer().parentElement);
|
||||
renderDisposables.add(actionBar);
|
||||
actionBarWidth = actionBar.getContainer().offsetWidth;
|
||||
}
|
||||
}
|
||||
const width = this._list.value?.layout(actionBarWidth);
|
||||
widget.style.width = `${width}px`;
|
||||
const focusTracker = renderDisposables.add(dom.trackFocus(element));
|
||||
renderDisposables.add(focusTracker.onDidBlur(() => this.hide(true)));
|
||||
return renderDisposables;
|
||||
}
|
||||
_createActionBar(className, actions) {
|
||||
if (!actions.length) {
|
||||
return undefined;
|
||||
}
|
||||
const container = dom.$(className);
|
||||
const actionBar = new ActionBar(container);
|
||||
actionBar.push(actions, { icon: false, label: true });
|
||||
return actionBar;
|
||||
}
|
||||
_onWidgetClosed(didCancel) {
|
||||
this._list.value?.hide(didCancel);
|
||||
}
|
||||
};
|
||||
ActionWidgetService = __decorate([
|
||||
__param(0, IContextViewService),
|
||||
__param(1, IContextKeyService),
|
||||
__param(2, IInstantiationService)
|
||||
], ActionWidgetService);
|
||||
registerSingleton(IActionWidgetService, ActionWidgetService, 1 /* InstantiationType.Delayed */);
|
||||
const weight = 100 /* KeybindingWeight.EditorContrib */ + 1000;
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'hideCodeActionWidget',
|
||||
title: localize2(1644, "Hide action widget"),
|
||||
precondition: ActionWidgetContextKeys.Visible,
|
||||
keybinding: {
|
||||
weight,
|
||||
primary: 9 /* KeyCode.Escape */,
|
||||
secondary: [1024 /* KeyMod.Shift */ | 9 /* KeyCode.Escape */]
|
||||
},
|
||||
});
|
||||
}
|
||||
run(accessor) {
|
||||
accessor.get(IActionWidgetService).hide(true);
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'selectPrevCodeAction',
|
||||
title: localize2(1645, "Select previous action"),
|
||||
precondition: ActionWidgetContextKeys.Visible,
|
||||
keybinding: {
|
||||
weight,
|
||||
primary: 16 /* KeyCode.UpArrow */,
|
||||
secondary: [2048 /* KeyMod.CtrlCmd */ | 16 /* KeyCode.UpArrow */],
|
||||
mac: { primary: 16 /* KeyCode.UpArrow */, secondary: [2048 /* KeyMod.CtrlCmd */ | 16 /* KeyCode.UpArrow */, 256 /* KeyMod.WinCtrl */ | 46 /* KeyCode.KeyP */] },
|
||||
}
|
||||
});
|
||||
}
|
||||
run(accessor) {
|
||||
const widgetService = accessor.get(IActionWidgetService);
|
||||
if (widgetService instanceof ActionWidgetService) {
|
||||
widgetService.focusPrevious();
|
||||
}
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'selectNextCodeAction',
|
||||
title: localize2(1646, "Select next action"),
|
||||
precondition: ActionWidgetContextKeys.Visible,
|
||||
keybinding: {
|
||||
weight,
|
||||
primary: 18 /* KeyCode.DownArrow */,
|
||||
secondary: [2048 /* KeyMod.CtrlCmd */ | 18 /* KeyCode.DownArrow */],
|
||||
mac: { primary: 18 /* KeyCode.DownArrow */, secondary: [2048 /* KeyMod.CtrlCmd */ | 18 /* KeyCode.DownArrow */, 256 /* KeyMod.WinCtrl */ | 44 /* KeyCode.KeyN */] }
|
||||
}
|
||||
});
|
||||
}
|
||||
run(accessor) {
|
||||
const widgetService = accessor.get(IActionWidgetService);
|
||||
if (widgetService instanceof ActionWidgetService) {
|
||||
widgetService.focusNext();
|
||||
}
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: acceptSelectedActionCommand,
|
||||
title: localize2(1647, "Accept selected action"),
|
||||
precondition: ActionWidgetContextKeys.Visible,
|
||||
keybinding: {
|
||||
weight,
|
||||
primary: 3 /* KeyCode.Enter */,
|
||||
secondary: [2048 /* KeyMod.CtrlCmd */ | 89 /* KeyCode.Period */],
|
||||
}
|
||||
});
|
||||
}
|
||||
run(accessor) {
|
||||
const widgetService = accessor.get(IActionWidgetService);
|
||||
if (widgetService instanceof ActionWidgetService) {
|
||||
widgetService.acceptSelected();
|
||||
}
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: previewSelectedActionCommand,
|
||||
title: localize2(1648, "Preview selected action"),
|
||||
precondition: ActionWidgetContextKeys.Visible,
|
||||
keybinding: {
|
||||
weight,
|
||||
primary: 2048 /* KeyMod.CtrlCmd */ | 3 /* KeyCode.Enter */,
|
||||
}
|
||||
});
|
||||
}
|
||||
run(accessor) {
|
||||
const widgetService = accessor.get(IActionWidgetService);
|
||||
if (widgetService instanceof ActionWidgetService) {
|
||||
widgetService.acceptSelected(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
//# sourceMappingURL=actionWidget.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export {};
|
||||
//# sourceMappingURL=actionWidget.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/actionWidget/common/actionWidget.ts","vs/platform/actionWidget/common/actionWidget.ts"],"names":[],"mappings":"AAAA;;;gGAGgG","file":"actionWidget.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IDisposable } from '../../../base/common/lifecycle.js';\n\nexport interface ActionSet<T> extends IDisposable {\n\treadonly hasAutoFix: boolean;\n\treadonly hasAIFix: boolean;\n\treadonly allAIFixes: boolean;\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IDisposable } from '../../../base/common/lifecycle.js';\n\nexport interface ActionSet<T> extends IDisposable {\n\treadonly hasAutoFix: boolean;\n\treadonly hasAIFix: boolean;\n\treadonly allAIFixes: boolean;\n}\n"]}
|
||||
Reference in New Issue
Block a user