debug-server-next
Version:
Dev server for hippy-core.
195 lines (194 loc) • 8.68 kB
JavaScript
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as i18n from '../../../core/i18n/i18n.js';
import * as LitHtml from '../../lit-html/lit-html.js';
import * as ComponentHelpers from '../helpers/helpers.js';
import * as IconButton from '../icon_button/icon_button.js';
import valueInterpreterDisplayStyles from './valueInterpreterDisplay.css.js';
import { format, getDefaultValueTypeMapping, getPointerAddress, isNumber, isPointer, isValidMode, VALUE_TYPE_MODE_LIST } from './ValueInterpreterDisplayUtils.js';
const UIStrings = {
/**
*@description Tooltip text that appears when hovering over an unsigned interpretation of the memory under the Value Interpreter
*/
unsignedValue: '`Unsigned` value',
/**
*@description Tooltip text that appears when hovering over the element to change value type modes of under the Value Interpreter. Value type modes
* are different ways of viewing a certain value, e.g.: 10 (decimal) can be 0xa in hexadecimal mode, or 12 in octal mode.
*/
changeValueTypeMode: 'Change mode',
/**
*@description Tooltip text that appears when hovering over a signed interpretation of the memory under the Value Interpreter
*/
signedValue: '`Signed` value',
/**
*@description Tooltip text that appears when hovering over a 'jump-to-address' button that is next to a pointer (32-bit or 64-bit) under the Value Interpreter
*/
jumpToPointer: 'Jump to address',
/**
*@description Tooltip text that appears when hovering over a 'jump-to-address' button that is next to a pointer (32-bit or 64-bit) with an invalid address under the Value Interpreter.
*/
addressOutOfRange: 'Address out of memory range',
};
const str_ = i18n.i18n.registerUIStrings('ui/components/linear_memory_inspector/ValueInterpreterDisplay.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
const { render, html } = LitHtml;
const getStyleSheets = ComponentHelpers.GetStylesheet.getStyleSheets;
const SORTED_VALUE_TYPES = Array.from(getDefaultValueTypeMapping().keys());
export class ValueTypeModeChangedEvent extends Event {
data;
constructor(type, mode) {
super('valuetypemodechanged', {
composed: true,
});
this.data = { type, mode };
}
}
export class JumpToPointerAddressEvent extends Event {
data;
constructor(address) {
super('jumptopointeraddress', {
composed: true,
});
this.data = address;
}
}
export class ValueInterpreterDisplay extends HTMLElement {
static litTagName = LitHtml.literal `devtools-linear-memory-inspector-interpreter-display`;
shadow = this.attachShadow({ mode: 'open' });
endianness = "Little Endian" /* Little */;
buffer = new ArrayBuffer(0);
valueTypes = new Set();
valueTypeModeConfig = getDefaultValueTypeMapping();
memoryLength = 0;
constructor() {
super();
this.shadow.adoptedStyleSheets = [
...getStyleSheets('ui/legacy/inspectorCommon.css'),
];
}
connectedCallback() {
this.shadow.adoptedStyleSheets = [valueInterpreterDisplayStyles];
}
set data(data) {
this.buffer = data.buffer;
this.endianness = data.endianness;
this.valueTypes = data.valueTypes;
this.memoryLength = data.memoryLength;
if (data.valueTypeModes) {
data.valueTypeModes.forEach((mode, valueType) => {
if (isValidMode(valueType, mode)) {
this.valueTypeModeConfig.set(valueType, mode);
}
});
}
this.render();
}
render() {
// Disabled until https://crbug.com/1079231 is fixed.
// clang-format off
render(html `
<div class="value-types">
${SORTED_VALUE_TYPES.map(type => this.valueTypes.has(type) ? this.showValue(type) : '')}
</div>
`, this.shadow, { host: this });
// clang-format on
}
showValue(type) {
if (isNumber(type)) {
return this.renderNumberValues(type);
}
if (isPointer(type)) {
return this.renderPointerValue(type);
}
throw new Error(`No known way to format ${type}`);
}
renderPointerValue(type) {
const unsignedValue = this.parse({ type, signed: false });
const address = getPointerAddress(type, this.buffer, this.endianness);
const jumpDisabled = Number.isNaN(address) || BigInt(address) >= BigInt(this.memoryLength);
const buttonTitle = jumpDisabled ? i18nString(UIStrings.addressOutOfRange) : i18nString(UIStrings.jumpToPointer);
const iconColor = jumpDisabled ? 'var(--color-text-secondary)' : 'var(--color-primary)';
// Disabled until https://crbug.com/1079231 is fixed.
// clang-format off
return html `
<span class="value-type-cell-no-mode value-type-cell">${i18n.i18n.lockedString(type)}</span>
<div class="value-type-cell">
<div class="value-type-value-with-link" data-value="true">
<span>${unsignedValue}</span>
${html `
<button class="jump-to-button" data-jump="true" title=${buttonTitle} ?disabled=${jumpDisabled}
=${this.onJumpToAddressClicked.bind(this, Number(address))}>
<${IconButton.Icon.Icon.litTagName} .data=${{ iconName: 'link_icon', color: iconColor, width: '14px' }}>
</${IconButton.Icon.Icon.litTagName}>
</button>`}
</div>
</div>
`;
// clang-format on
}
onJumpToAddressClicked(address) {
this.dispatchEvent(new JumpToPointerAddressEvent(address));
}
renderNumberValues(type) {
// Disabled until https://crbug.com/1079231 is fixed.
// clang-format off
return html `
<span class="value-type-cell">${i18n.i18n.lockedString(type)}</span>
<div>
<select title=${i18nString(UIStrings.changeValueTypeMode)}
data-mode-settings="true"
class="chrome-select"
style="border: none; background-color: transparent; cursor: pointer; color: var(--color-text-secondary);"
=${this.onValueTypeModeChange.bind(this, type)}>
${VALUE_TYPE_MODE_LIST.filter(x => isValidMode(type, x)).map(mode => {
return html `
<option value=${mode} .selected=${this.valueTypeModeConfig.get(type) === mode}>${i18n.i18n.lockedString(mode)}
</option>`;
})}
</select>
</div>
${this.renderSignedAndUnsigned(type)}
`;
// clang-format on
}
renderSignedAndUnsigned(type) {
const unsignedValue = this.parse({ type, signed: false });
const signedValue = this.parse({ type, signed: true });
const mode = this.valueTypeModeConfig.get(type);
const showSignedAndUnsigned = signedValue !== unsignedValue && mode !== "hex" /* Hexadecimal */ && mode !== "oct" /* Octal */;
const unsignedRendered = html `<span class="value-type-cell" title=${i18nString(UIStrings.unsignedValue)} data-value="true">${unsignedValue}</span>`;
if (!showSignedAndUnsigned) {
return unsignedRendered;
}
// Some values are too long to show in one line, we're putting them into the next line.
const showInMultipleLines = type === "Integer 32-bit" /* Int32 */ || type === "Integer 64-bit" /* Int64 */;
const signedRendered = html `<span data-value="true" title=${i18nString(UIStrings.signedValue)}>${signedValue}</span>`;
if (showInMultipleLines) {
return html `
<div class="value-type-cell">
${unsignedRendered}
${signedRendered}
</div>
`;
}
return html `
<div class="value-type-cell" style="flex-direction: row;">
${unsignedRendered}
<span class="signed-divider"></span>
${signedRendered}
</div>
`;
}
onValueTypeModeChange(type, event) {
event.preventDefault();
const select = event.target;
const mode = select.value;
this.dispatchEvent(new ValueTypeModeChangedEvent(type, mode));
}
parse(data) {
const mode = this.valueTypeModeConfig.get(data.type);
return format({ buffer: this.buffer, type: data.type, endianness: this.endianness, signed: data.signed || false, mode });
}
}
ComponentHelpers.CustomElements.defineComponent('devtools-linear-memory-inspector-interpreter-display', ValueInterpreterDisplay);