blob: db07811e533110ef4f92bf5e52f29bddf769821d [file] [log] [blame]
/*
* Copyright (C) 2008 Apple Inc. All Rights Reserved.
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @implements {UI.ContextFlavorListener}
* @unrestricted
*/
Sources.ScopeChainSidebarPane = class extends UI.VBox {
constructor() {
super(true);
this.registerRequiredCSS('sources/scopeChainSidebarPane.css');
this._treeOutline = new ObjectUI.ObjectPropertiesSectionsTreeOutline();
this._treeOutline.registerRequiredCSS('sources/scopeChainSidebarPane.css');
this._treeOutline.setShowSelectionOnKeyboardFocus(/* show */ true);
this._expandController = new ObjectUI.ObjectPropertiesSectionsTreeExpandController(this._treeOutline);
this._linkifier = new Components.Linkifier();
this._infoElement = createElement('div');
this._infoElement.className = 'gray-info-message';
this._infoElement.textContent = ls`Not paused`;
this._infoElement.tabIndex = -1;
this._update();
}
/**
* @override
* @param {?Object} object
*/
flavorChanged(object) {
this._update();
}
/**
* @override
*/
focus() {
if (this.hasFocus()) {
return;
}
if (UI.context.flavor(SDK.DebuggerPausedDetails)) {
this._treeOutline.forceSelect();
}
}
_update() {
const callFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame);
const details = UI.context.flavor(SDK.DebuggerPausedDetails);
this._linkifier.reset();
Sources.SourceMapNamesResolver.resolveThisObject(callFrame).then(this._innerUpdate.bind(this, details, callFrame));
}
/**
* @param {?SDK.DebuggerPausedDetails} details
* @param {?SDK.DebuggerModel.CallFrame} callFrame
* @param {?SDK.RemoteObject} thisObject
*/
_innerUpdate(details, callFrame, thisObject) {
this._treeOutline.removeChildren();
this.contentElement.removeChildren();
if (!details || !callFrame) {
this.contentElement.appendChild(this._infoElement);
return;
}
this.contentElement.appendChild(this._treeOutline.element);
let foundLocalScope = false;
const scopeChain = callFrame.scopeChain();
for (let i = 0; i < scopeChain.length; ++i) {
const scope = scopeChain[i];
const extraProperties = this._extraPropertiesForScope(scope, details, callFrame, thisObject, i === 0);
if (scope.type() === Protocol.Debugger.ScopeType.Local) {
foundLocalScope = true;
}
const section = this._createScopeSectionTreeElement(scope, extraProperties);
if (scope.type() === Protocol.Debugger.ScopeType.Global) {
section.collapse();
} else if (!foundLocalScope || scope.type() === Protocol.Debugger.ScopeType.Local) {
section.expand();
}
this._treeOutline.appendChild(section);
if (i === 0) {
section.select(/* omitFocus */ true);
}
}
this._sidebarPaneUpdatedForTest();
}
/**
* @param {!SDK.DebuggerModel.Scope} scope
* @param {!Array.<!SDK.RemoteObjectProperty>} extraProperties
* @return {!ObjectUI.ObjectPropertiesSection.RootElement}
*/
_createScopeSectionTreeElement(scope, extraProperties) {
let emptyPlaceholder = null;
if (scope.type() === Protocol.Debugger.ScopeType.Local || Protocol.Debugger.ScopeType.Closure) {
emptyPlaceholder = ls`No variables`;
}
let title = scope.typeName();
if (scope.type() === Protocol.Debugger.ScopeType.Closure) {
const scopeName = scope.name();
if (scopeName) {
title = ls`Closure (${UI.beautifyFunctionName(scopeName)})`;
} else {
title = ls`Closure`;
}
}
let subtitle = scope.description();
if (!title || title === subtitle) {
subtitle = undefined;
}
const titleElement = createElementWithClass('div', 'scope-chain-sidebar-pane-section-header tree-element-title');
titleElement.createChild('div', 'scope-chain-sidebar-pane-section-subtitle').textContent = subtitle;
titleElement.createChild('div', 'scope-chain-sidebar-pane-section-title').textContent = title;
const section = new ObjectUI.ObjectPropertiesSection.RootElement(
Sources.SourceMapNamesResolver.resolveScopeInObject(scope), this._linkifier, emptyPlaceholder,
/* ignoreHasOwnProperty */ true, extraProperties);
section.title = titleElement;
section.listItemElement.classList.add('scope-chain-sidebar-pane-section');
this._expandController.watchSection(title + (subtitle ? ':' + subtitle : ''), section);
return section;
}
/**
* @param {!SDK.DebuggerModel.Scope} scope
* @param {?SDK.DebuggerPausedDetails} details
* @param {?SDK.DebuggerModel.CallFrame} callFrame
* @param {?SDK.RemoteObject} thisObject
* @param {boolean} isFirstScope
* @return {!Array.<!SDK.RemoteObjectProperty>}
*/
_extraPropertiesForScope(scope, details, callFrame, thisObject, isFirstScope) {
if (scope.type() !== Protocol.Debugger.ScopeType.Local) {
return [];
}
const extraProperties = [];
if (thisObject) {
extraProperties.push(new SDK.RemoteObjectProperty('this', thisObject));
}
if (isFirstScope) {
const exception = details.exception();
if (exception) {
extraProperties.push(new SDK.RemoteObjectProperty(
Common.UIString('Exception'), exception, undefined, undefined, undefined, undefined, undefined,
/* synthetic */ true));
}
const returnValue = callFrame.returnValue();
if (returnValue) {
extraProperties.push(new SDK.RemoteObjectProperty(
Common.UIString('Return value'), returnValue, undefined, undefined, undefined, undefined, undefined,
/* synthetic */ true, callFrame.setReturnValue.bind(callFrame)));
}
}
return extraProperties;
}
_sidebarPaneUpdatedForTest() {
}
};
Sources.ScopeChainSidebarPane._pathSymbol = Symbol('path');