[turbolizer] Make instructions clickable in sequence view

This is work towards making instructions in the sequence view
selectable. For now, they are clickable and will select the
corresponding instructions in the disassembly view.

Bug: v8:7327
Notry: true
Change-Id: I8850efeec7f94487bd80c11a7ad250a959062393
Reviewed-on: https://chromium-review.googlesource.com/c/1386112
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58397}
This commit is contained in:
Sigurd Schneider 2018-12-20 11:25:08 +01:00 committed by Commit Bot
parent cd5f5937cd
commit d2b96f1b16
7 changed files with 91 additions and 16 deletions

View File

@ -6,6 +6,8 @@ import { PROF_COLS, UNICODE_BLOCK } from "../src/constants"
import { SelectionBroker } from "../src/selection-broker"
import { TextView } from "../src/text-view"
import { SourceResolver } from "./source-resolver";
import { MySelection } from "./selection";
import { anyToString } from "./util";
export class DisassemblyView extends TextView {
SOURCE_POSITION_HEADER_REGEX: any;
@ -13,6 +15,8 @@ export class DisassemblyView extends TextView {
total_event_counts: any;
max_event_counts: any;
pos_lines: Array<any>;
instructionSelectionHandler: InstructionSelectionHandler;
offsetSelection: MySelection;
createViewElement() {
const pane = document.createElement('div');
@ -144,6 +148,32 @@ export class DisassemblyView extends TextView {
};
}
view.divNode.addEventListener('click', linkHandlerBlock);
this.offsetSelection = new MySelection(anyToString);
const instructionSelectionHandler = {
clear: function () {
view.offsetSelection.clear();
view.updateSelection();
broker.broadcastClear(instructionSelectionHandler);
},
select: function (instructionIds, selected) {
view.offsetSelection.select(instructionIds, selected);
view.updateSelection();
broker.broadcastBlockSelect(instructionSelectionHandler, instructionIds, selected);
},
brokeredInstructionSelect: function (instructionIds, selected) {
const firstSelect = view.offsetSelection.isEmpty();
const keyPcOffsets = view.sourceResolver.instructionsToKeyPcOffsets(instructionIds);
view.offsetSelection.select(keyPcOffsets, selected);
view.updateSelection(firstSelect);
},
brokeredClear: function () {
view.offsetSelection.clear();
view.updateSelection();
}
};
this.instructionSelectionHandler = instructionSelectionHandler;
broker.addInstructionHandler(instructionSelectionHandler);
}
initializeCode(sourceText, sourcePosition) {

View File

@ -6,29 +6,47 @@ import {SourceResolver, sourcePositionValid} from "../src/source-resolver"
export class SelectionBroker {
sourceResolver: SourceResolver;
allHandlers: Array<ClearableHandler>;
sourcePositionHandlers: Array<SelectionHandler>;
nodeHandlers: Array<NodeSelectionHandler>;
blockHandlers: Array<BlockSelectionHandler>;
instructionHandlers: Array<InstructionSelectionHandler>;
constructor(sourceResolver) {
this.allHandlers = [];
this.sourcePositionHandlers = [];
this.nodeHandlers = [];
this.blockHandlers = [];
this.instructionHandlers = [];
this.sourceResolver = sourceResolver;
};
addSourcePositionHandler(handler) {
addSourcePositionHandler(handler: SelectionHandler&ClearableHandler) {
this.allHandlers.push(handler);
this.sourcePositionHandlers.push(handler);
}
addNodeHandler(handler) {
addNodeHandler(handler: NodeSelectionHandler&ClearableHandler) {
this.allHandlers.push(handler);
this.nodeHandlers.push(handler);
}
addBlockHandler(handler) {
addBlockHandler(handler: BlockSelectionHandler&ClearableHandler) {
this.allHandlers.push(handler);
this.blockHandlers.push(handler);
}
addInstructionHandler(handler: InstructionSelectionHandler&ClearableHandler) {
this.allHandlers.push(handler);
this.instructionHandlers.push(handler);
}
broadcastInstructionSelect(from, instructionOffsets, selected) {
for (const b of this.instructionHandlers) {
if (b != from) b.brokeredInstructionSelect(instructionOffsets, selected);
}
}
broadcastSourcePositionSelect(from, sourcePositions, selected) {
let broker = this;
sourcePositions = sourcePositions.filter((l) => {
@ -66,13 +84,7 @@ export class SelectionBroker {
}
broadcastClear(from) {
this.sourcePositionHandlers.forEach(function (b) {
if (b != from) b.brokeredClear();
});
this.nodeHandlers.forEach(function (b) {
if (b != from) b.brokeredClear();
});
this.blockHandlers.forEach(function (b) {
this.allHandlers.forEach(function (b) {
if (b != from) b.brokeredClear();
});
}

View File

@ -2,23 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
interface ClearableHandler {
brokeredClear(): void;
}
interface SelectionHandler {
clear(): void;
select(nodeIds: any, selected: any): void;
brokeredClear(): void;
brokeredSourcePositionSelect(sourcePositions: any, selected: any): void;
};
interface NodeSelectionHandler {
clear(): void;
select(nodeIds: any, selected: any): void;
brokeredClear(): void;
brokeredNodeSelect(nodeIds: any, selected: any): void;
};
interface BlockSelectionHandler {
clear(): void;
select(nodeIds: any, selected: any): void;
brokeredClear(): void;
brokeredBlockSelect(blockIds: any, selected: any): void;
};
interface InstructionSelectionHandler {
clear(): void;
select(instructionIds: any, selected: any): void;
brokeredInstructionSelect(instructionIds: any, selected: any): void;
};

View File

@ -6,6 +6,7 @@ import {Sequence} from "../src/source-resolver"
import {isIterable} from "../src/util"
import {PhaseView} from "../src/view"
import {TextView} from "../src/text-view"
import { MySelection } from "./selection";
export class SequenceView extends TextView implements PhaseView {
sequence: Sequence;
@ -40,6 +41,13 @@ export class SequenceView extends TextView implements PhaseView {
this.divNode.innerHTML = '';
this.sequence = data.sequence;
this.search_info = [];
this.divNode.addEventListener('click', (e:MouseEvent) => {
if (!(e.target instanceof HTMLElement)) return;
const instructionId = e.target.dataset.instructionId;
if (!instructionId) return;
if (!e.shiftKey) this.broker.broadcastClear(null);
this.broker.broadcastInstructionSelect(null, [instructionId], true);
});
this.addBlocks(this.sequence.blocks);
this.attachSelection(rememberedSelection);
}
@ -91,6 +99,8 @@ export class SequenceView extends TextView implements PhaseView {
const instNodeEl = createElement("div", "instruction-node");
const inst_id = createElement("div", "instruction-id", instruction.id);
inst_id.classList.add("clickable");
inst_id.dataset.instructionId = instruction.id;
instNodeEl.appendChild(inst_id);
const instContentsEl = createElement("div", "instruction-contents");

View File

@ -372,6 +372,14 @@ export class SourceResolver {
return this.instructionToPCOffset.slice(start, end);
}
instructionsToKeyPcOffsets(instructionIds) {
const keyPcOffsets = [];
for (const instructionId of instructionIds) {
keyPcOffsets.push(this.instructionToPCOffset[instructionId]);
}
return keyPcOffsets;
}
nodesToKeyPcOffsets(nodes) {
let offsets = [];
for (const node of nodes) {

View File

@ -6,6 +6,7 @@ import { View } from "../src/view"
import { anyToString, ViewElements, isIterable } from "../src/util"
import { MySelection } from "../src/selection"
import { SourceResolver } from "./source-resolver";
import { SelectionBroker } from "./selection-broker";
export abstract class TextView extends View {
selectionHandler: NodeSelectionHandler;
@ -20,6 +21,7 @@ export abstract class TextView extends View {
nodeIdToBlockId: Array<string>;
patterns: any;
sourceResolver: SourceResolver;
broker: SelectionBroker;
constructor(id, broker, patterns) {
super(id);
@ -32,6 +34,7 @@ export abstract class TextView extends View {
view.nodeIdToBlockId = [];
view.selection = new MySelection(anyToString);
view.blockSelection = new MySelection(anyToString);
view.broker = broker;
view.sourceResolver = broker.sourceResolver;
const selectionHandler = {
clear: function () {
@ -136,7 +139,12 @@ export abstract class TextView extends View {
for (const el of elementsToSelect) {
el.classList.toggle("selected", false);
}
const keyPcOffsets = view.sourceResolver.nodesToKeyPcOffsets(view.selection.selectedKeys());
let keyPcOffsets = view.sourceResolver.nodesToKeyPcOffsets(view.selection.selectedKeys());
if (view.offsetSelection) {
for (const key of view.offsetSelection.selectedKeys()) {
keyPcOffsets.push(Number(key))
}
}
for (const keyPcOffset of keyPcOffsets) {
const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset='${keyPcOffset}']`)
for (const el of elementsToSelect) {

View File

@ -289,11 +289,11 @@ input:hover, .collapse-pane:hover input {
cursor: pointer;
}
span.linkable-text {
.linkable-text {
text-decoration: underline;
}
span.linkable-text:hover {
.linkable-text:hover {
cursor: pointer;
font-weight: bold;
}