mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-12 02:58:31 -05:00
Vscode merge (#4582)
* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd * fix issues with merges * bump node version in azpipe * replace license headers * remove duplicate launch task * fix build errors * fix build errors * fix tslint issues * working through package and linux build issues * more work * wip * fix packaged builds * working through linux build errors * wip * wip * wip * fix mac and linux file limits * iterate linux pipeline * disable editor typing * revert series to parallel * remove optimize vscode from linux * fix linting issues * revert testing change * add work round for new node * readd packaging for extensions * fix issue with angular not resolving decorator dependencies
This commit is contained in:
302
src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts
Normal file
302
src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts
Normal file
@@ -0,0 +1,302 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { CollapseAction } from 'vs/workbench/browser/viewlet';
|
||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { IDebugService, IExpression, CONTEXT_WATCH_EXPRESSIONS_FOCUSED } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Expression, Variable } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { AddWatchExpressionAction, RemoveAllWatchExpressionsAction, EditWatchExpressionAction, RemoveWatchExpressionAction, CopyValueAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
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 } from 'vs/base/common/actions';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { renderExpressionValue, renderViewTree, IInputBoxOptions, AbstractExpressionsRenderer, IExpressionTemplateData } from 'vs/workbench/contrib/debug/browser/baseDebugView';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { IAsyncDataSource, ITreeMouseEvent, ITreeContextMenuEvent, ITreeDragAndDrop, ITreeDragOverReaction } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IDragAndDropData } from 'vs/base/browser/dnd';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
|
||||
import { FuzzyScore } from 'vs/base/common/filters';
|
||||
import { IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { variableSetEmitter, VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView';
|
||||
|
||||
const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
|
||||
|
||||
export class WatchExpressionsView extends ViewletPanel {
|
||||
|
||||
private onWatchExpressionsUpdatedScheduler: RunOnceScheduler;
|
||||
private needsRefresh: boolean;
|
||||
private tree: WorkbenchAsyncDataTree<IDebugService | IExpression, IExpression, FuzzyScore>;
|
||||
|
||||
constructor(
|
||||
options: IViewletViewOptions,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
) {
|
||||
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('watchExpressionsSection', "Watch Expressions Section") }, keybindingService, contextMenuService, configurationService);
|
||||
|
||||
this.onWatchExpressionsUpdatedScheduler = new RunOnceScheduler(() => {
|
||||
this.needsRefresh = false;
|
||||
this.tree.updateChildren();
|
||||
}, 50);
|
||||
}
|
||||
|
||||
renderBody(container: HTMLElement): void {
|
||||
dom.addClass(container, 'debug-watch');
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
const expressionsRenderer = this.instantiationService.createInstance(WatchExpressionsRenderer);
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new WatchExpressionsDelegate(), [expressionsRenderer, this.instantiationService.createInstance(VariablesRenderer)],
|
||||
new WatchExpressionsDataSource(), {
|
||||
ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'watchAriaTreeLabel' }, "Debug Watch Expressions"),
|
||||
accessibilityProvider: new WatchExpressionsAccessibilityProvider(),
|
||||
identityProvider: { getId: element => (<IExpression>element).getId() },
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: e => e },
|
||||
dnd: new WatchExpressionsDragAndDrop(this.debugService),
|
||||
}) as WorkbenchAsyncDataTree<IDebugService | IExpression, IExpression, FuzzyScore>;
|
||||
|
||||
this.tree.setInput(this.debugService).then(undefined, onUnexpectedError);
|
||||
CONTEXT_WATCH_EXPRESSIONS_FOCUSED.bindTo(this.tree.contextKeyService);
|
||||
|
||||
const addWatchExpressionAction = new AddWatchExpressionAction(AddWatchExpressionAction.ID, AddWatchExpressionAction.LABEL, this.debugService, this.keybindingService);
|
||||
const collapseAction = new CollapseAction(this.tree, true, 'explorer-action collapse-explorer');
|
||||
const removeAllWatchExpressionsAction = new RemoveAllWatchExpressionsAction(RemoveAllWatchExpressionsAction.ID, RemoveAllWatchExpressionsAction.LABEL, this.debugService, this.keybindingService);
|
||||
this.toolbar.setActions([addWatchExpressionAction, collapseAction, removeAllWatchExpressionsAction])();
|
||||
|
||||
this.disposables.push(this.tree.onContextMenu(e => this.onContextMenu(e)));
|
||||
this.disposables.push(this.tree.onMouseDblClick(e => this.onMouseDblClick(e)));
|
||||
this.disposables.push(this.debugService.getModel().onDidChangeWatchExpressions(we => {
|
||||
if (!this.isBodyVisible()) {
|
||||
this.needsRefresh = true;
|
||||
} else {
|
||||
this.tree.updateChildren();
|
||||
}
|
||||
}));
|
||||
this.disposables.push(this.debugService.getViewModel().onDidFocusStackFrame(() => {
|
||||
if (!this.isBodyVisible()) {
|
||||
this.needsRefresh = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.onWatchExpressionsUpdatedScheduler.isScheduled()) {
|
||||
this.onWatchExpressionsUpdatedScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
this.disposables.push(variableSetEmitter.event(() => this.tree.updateChildren()));
|
||||
|
||||
this.disposables.push(this.onDidChangeBodyVisibility(visible => {
|
||||
if (visible && this.needsRefresh) {
|
||||
this.onWatchExpressionsUpdatedScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
this.disposables.push(this.debugService.getViewModel().onDidSelectExpression(e => {
|
||||
if (e instanceof Expression && e.name) {
|
||||
this.tree.rerender(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
layoutBody(height: number, width: number): void {
|
||||
this.tree.layout(height, width);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this.tree.domFocus();
|
||||
}
|
||||
|
||||
private onMouseDblClick(e: ITreeMouseEvent<IExpression>): void {
|
||||
if ((e.browserEvent.target as HTMLElement).className.indexOf('twistie') >= 0) {
|
||||
// Ignore double click events on twistie
|
||||
return;
|
||||
}
|
||||
|
||||
const element = e.element;
|
||||
// double click on primitive value: open input box to be able to select and copy value.
|
||||
if (element instanceof Expression && element !== this.debugService.getViewModel().getSelectedExpression()) {
|
||||
this.debugService.getViewModel().setSelectedExpression(element);
|
||||
} else if (!element) {
|
||||
// Double click in watch panel triggers to add a new watch expression
|
||||
this.debugService.addWatchExpression();
|
||||
}
|
||||
}
|
||||
|
||||
private onContextMenu(e: ITreeContextMenuEvent<IExpression>): void {
|
||||
const element = e.element;
|
||||
const anchor = e.anchor;
|
||||
if (!anchor) {
|
||||
return;
|
||||
}
|
||||
const actions: IAction[] = [];
|
||||
|
||||
if (element instanceof Expression) {
|
||||
const expression = <Expression>element;
|
||||
actions.push(new AddWatchExpressionAction(AddWatchExpressionAction.ID, AddWatchExpressionAction.LABEL, this.debugService, this.keybindingService));
|
||||
actions.push(new EditWatchExpressionAction(EditWatchExpressionAction.ID, EditWatchExpressionAction.LABEL, this.debugService, this.keybindingService));
|
||||
if (!expression.hasChildren) {
|
||||
actions.push(this.instantiationService.createInstance(CopyValueAction, CopyValueAction.ID, CopyValueAction.LABEL, expression.value, 'watch', this.debugService));
|
||||
}
|
||||
actions.push(new Separator());
|
||||
|
||||
actions.push(new RemoveWatchExpressionAction(RemoveWatchExpressionAction.ID, RemoveWatchExpressionAction.LABEL, this.debugService, this.keybindingService));
|
||||
actions.push(new RemoveAllWatchExpressionsAction(RemoveAllWatchExpressionsAction.ID, RemoveAllWatchExpressionsAction.LABEL, this.debugService, this.keybindingService));
|
||||
} else {
|
||||
actions.push(new AddWatchExpressionAction(AddWatchExpressionAction.ID, AddWatchExpressionAction.LABEL, this.debugService, this.keybindingService));
|
||||
if (element instanceof Variable) {
|
||||
const variable = element as Variable;
|
||||
if (!variable.hasChildren) {
|
||||
actions.push(this.instantiationService.createInstance(CopyValueAction, CopyValueAction.ID, CopyValueAction.LABEL, variable, 'watch', this.debugService));
|
||||
}
|
||||
actions.push(new Separator());
|
||||
}
|
||||
actions.push(new RemoveAllWatchExpressionsAction(RemoveAllWatchExpressionsAction.ID, RemoveAllWatchExpressionsAction.LABEL, this.debugService, this.keybindingService));
|
||||
}
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => element
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class WatchExpressionsDelegate implements IListVirtualDelegate<IExpression> {
|
||||
|
||||
getHeight(element: IExpression): number {
|
||||
return 22;
|
||||
}
|
||||
|
||||
getTemplateId(element: IExpression): string {
|
||||
if (element instanceof Expression) {
|
||||
return WatchExpressionsRenderer.ID;
|
||||
}
|
||||
|
||||
// Variable
|
||||
return VariablesRenderer.ID;
|
||||
}
|
||||
}
|
||||
|
||||
function isDebugService(element: any): element is IDebugService {
|
||||
return typeof element.getConfigurationManager === 'function';
|
||||
}
|
||||
|
||||
class WatchExpressionsDataSource implements IAsyncDataSource<IDebugService, IExpression> {
|
||||
|
||||
hasChildren(element: IExpression | IDebugService): boolean {
|
||||
return isDebugService(element) || element.hasChildren;
|
||||
}
|
||||
|
||||
getChildren(element: IDebugService | IExpression): Promise<Array<IExpression>> {
|
||||
if (isDebugService(element)) {
|
||||
const debugService = element as IDebugService;
|
||||
const watchExpressions = debugService.getModel().getWatchExpressions();
|
||||
const viewModel = debugService.getViewModel();
|
||||
return Promise.all(watchExpressions.map(we => !!we.name
|
||||
? we.evaluate(viewModel.focusedSession!, viewModel.focusedStackFrame!, 'watch').then(() => we)
|
||||
: Promise.resolve(we)));
|
||||
}
|
||||
|
||||
return element.getChildren();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class WatchExpressionsRenderer extends AbstractExpressionsRenderer {
|
||||
|
||||
static readonly ID = 'watchexpression';
|
||||
|
||||
get templateId() {
|
||||
return WatchExpressionsRenderer.ID;
|
||||
}
|
||||
|
||||
protected renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void {
|
||||
const text = typeof expression.value === 'string' ? `${expression.name}:` : expression.name;
|
||||
data.label.set(text, highlights, expression.type ? expression.type : expression.value);
|
||||
renderExpressionValue(expression, data.value, {
|
||||
showChanged: true,
|
||||
maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET,
|
||||
preserveWhitespace: false,
|
||||
showHover: true,
|
||||
colorize: true
|
||||
});
|
||||
}
|
||||
|
||||
protected getInputBoxOptions(expression: IExpression): IInputBoxOptions {
|
||||
return {
|
||||
initialValue: expression.name ? expression.name : '',
|
||||
ariaLabel: nls.localize('watchExpressionInputAriaLabel', "Type watch expression"),
|
||||
placeholder: nls.localize('watchExpressionPlaceholder', "Expression to watch"),
|
||||
onFinish: (value: string, success: boolean) => {
|
||||
if (success && value) {
|
||||
this.debugService.renameWatchExpression(expression.getId(), value);
|
||||
} else if (!expression.name) {
|
||||
this.debugService.removeWatchExpressions(expression.getId());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class WatchExpressionsAccessibilityProvider implements IAccessibilityProvider<IExpression> {
|
||||
getAriaLabel(element: IExpression): string {
|
||||
if (element instanceof Expression) {
|
||||
return nls.localize('watchExpressionAriaLabel', "{0} value {1}, watch, debug", (<Expression>element).name, (<Expression>element).value);
|
||||
}
|
||||
|
||||
// Variable
|
||||
return nls.localize('watchVariableAriaLabel', "{0} value {1}, watch, debug", (<Variable>element).name, (<Variable>element).value);
|
||||
}
|
||||
}
|
||||
|
||||
class WatchExpressionsDragAndDrop implements ITreeDragAndDrop<IExpression> {
|
||||
|
||||
constructor(private debugService: IDebugService) { }
|
||||
|
||||
onDragOver(data: IDragAndDropData): boolean | ITreeDragOverReaction {
|
||||
if (!(data instanceof ElementsDragAndDropData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const expressions = (data as ElementsDragAndDropData<IExpression>).elements;
|
||||
return expressions.length > 0 && expressions[0] instanceof Expression;
|
||||
}
|
||||
|
||||
getDragURI(element: IExpression): string | null {
|
||||
if (!(element instanceof Expression) || element === this.debugService.getViewModel().getSelectedExpression()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return element.getId();
|
||||
}
|
||||
|
||||
getDragLabel(elements: IExpression[]): string | undefined {
|
||||
if (elements.length === 1) {
|
||||
return elements[0].name;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
drop(data: IDragAndDropData, targetElement: IExpression): void {
|
||||
if (!(data instanceof ElementsDragAndDropData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const draggedElement = (data as ElementsDragAndDropData<IExpression>).elements[0];
|
||||
const watches = this.debugService.getModel().getWatchExpressions();
|
||||
const position = targetElement instanceof Expression ? watches.indexOf(targetElement) : watches.length - 1;
|
||||
this.debugService.moveWatchExpression(draggedElement.getId(), position);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user