Commit d2b96f1b authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[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: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58397}
parent cd5f5937
...@@ -6,6 +6,8 @@ import { PROF_COLS, UNICODE_BLOCK } from "../src/constants" ...@@ -6,6 +6,8 @@ import { PROF_COLS, UNICODE_BLOCK } from "../src/constants"
import { SelectionBroker } from "../src/selection-broker" import { SelectionBroker } from "../src/selection-broker"
import { TextView } from "../src/text-view" import { TextView } from "../src/text-view"
import { SourceResolver } from "./source-resolver"; import { SourceResolver } from "./source-resolver";
import { MySelection } from "./selection";
import { anyToString } from "./util";
export class DisassemblyView extends TextView { export class DisassemblyView extends TextView {
SOURCE_POSITION_HEADER_REGEX: any; SOURCE_POSITION_HEADER_REGEX: any;
...@@ -13,6 +15,8 @@ export class DisassemblyView extends TextView { ...@@ -13,6 +15,8 @@ export class DisassemblyView extends TextView {
total_event_counts: any; total_event_counts: any;
max_event_counts: any; max_event_counts: any;
pos_lines: Array<any>; pos_lines: Array<any>;
instructionSelectionHandler: InstructionSelectionHandler;
offsetSelection: MySelection;
createViewElement() { createViewElement() {
const pane = document.createElement('div'); const pane = document.createElement('div');
...@@ -144,6 +148,32 @@ export class DisassemblyView extends TextView { ...@@ -144,6 +148,32 @@ export class DisassemblyView extends TextView {
}; };
} }
view.divNode.addEventListener('click', linkHandlerBlock); 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) { initializeCode(sourceText, sourcePosition) {
......
...@@ -6,29 +6,47 @@ import {SourceResolver, sourcePositionValid} from "../src/source-resolver" ...@@ -6,29 +6,47 @@ import {SourceResolver, sourcePositionValid} from "../src/source-resolver"
export class SelectionBroker { export class SelectionBroker {
sourceResolver: SourceResolver; sourceResolver: SourceResolver;
allHandlers: Array<ClearableHandler>;
sourcePositionHandlers: Array<SelectionHandler>; sourcePositionHandlers: Array<SelectionHandler>;
nodeHandlers: Array<NodeSelectionHandler>; nodeHandlers: Array<NodeSelectionHandler>;
blockHandlers: Array<BlockSelectionHandler>; blockHandlers: Array<BlockSelectionHandler>;
instructionHandlers: Array<InstructionSelectionHandler>;
constructor(sourceResolver) { constructor(sourceResolver) {
this.allHandlers = [];
this.sourcePositionHandlers = []; this.sourcePositionHandlers = [];
this.nodeHandlers = []; this.nodeHandlers = [];
this.blockHandlers = []; this.blockHandlers = [];
this.instructionHandlers = [];
this.sourceResolver = sourceResolver; this.sourceResolver = sourceResolver;
}; };
addSourcePositionHandler(handler) { addSourcePositionHandler(handler: SelectionHandler&ClearableHandler) {
this.allHandlers.push(handler);
this.sourcePositionHandlers.push(handler); this.sourcePositionHandlers.push(handler);
} }
addNodeHandler(handler) { addNodeHandler(handler: NodeSelectionHandler&ClearableHandler) {
this.allHandlers.push(handler);
this.nodeHandlers.push(handler); this.nodeHandlers.push(handler);
} }
addBlockHandler(handler) { addBlockHandler(handler: BlockSelectionHandler&ClearableHandler) {
this.allHandlers.push(handler);
this.blockHandlers.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) { broadcastSourcePositionSelect(from, sourcePositions, selected) {
let broker = this; let broker = this;
sourcePositions = sourcePositions.filter((l) => { sourcePositions = sourcePositions.filter((l) => {
...@@ -66,13 +84,7 @@ export class SelectionBroker { ...@@ -66,13 +84,7 @@ export class SelectionBroker {
} }
broadcastClear(from) { broadcastClear(from) {
this.sourcePositionHandlers.forEach(function (b) { this.allHandlers.forEach(function (b) {
if (b != from) b.brokeredClear();
});
this.nodeHandlers.forEach(function (b) {
if (b != from) b.brokeredClear();
});
this.blockHandlers.forEach(function (b) {
if (b != from) b.brokeredClear(); if (b != from) b.brokeredClear();
}); });
} }
......
...@@ -2,23 +2,30 @@ ...@@ -2,23 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
interface ClearableHandler {
brokeredClear(): void;
}
interface SelectionHandler { interface SelectionHandler {
clear(): void; clear(): void;
select(nodeIds: any, selected: any): void; select(nodeIds: any, selected: any): void;
brokeredClear(): void;
brokeredSourcePositionSelect(sourcePositions: any, selected: any): void; brokeredSourcePositionSelect(sourcePositions: any, selected: any): void;
}; };
interface NodeSelectionHandler { interface NodeSelectionHandler {
clear(): void; clear(): void;
select(nodeIds: any, selected: any): void; select(nodeIds: any, selected: any): void;
brokeredClear(): void;
brokeredNodeSelect(nodeIds: any, selected: any): void; brokeredNodeSelect(nodeIds: any, selected: any): void;
}; };
interface BlockSelectionHandler { interface BlockSelectionHandler {
clear(): void; clear(): void;
select(nodeIds: any, selected: any): void; select(nodeIds: any, selected: any): void;
brokeredClear(): void;
brokeredBlockSelect(blockIds: any, selected: any): void; brokeredBlockSelect(blockIds: any, selected: any): void;
}; };
interface InstructionSelectionHandler {
clear(): void;
select(instructionIds: any, selected: any): void;
brokeredInstructionSelect(instructionIds: any, selected: any): void;
};
...@@ -6,6 +6,7 @@ import {Sequence} from "../src/source-resolver" ...@@ -6,6 +6,7 @@ import {Sequence} from "../src/source-resolver"
import {isIterable} from "../src/util" import {isIterable} from "../src/util"
import {PhaseView} from "../src/view" import {PhaseView} from "../src/view"
import {TextView} from "../src/text-view" import {TextView} from "../src/text-view"
import { MySelection } from "./selection";
export class SequenceView extends TextView implements PhaseView { export class SequenceView extends TextView implements PhaseView {
sequence: Sequence; sequence: Sequence;
...@@ -40,6 +41,13 @@ export class SequenceView extends TextView implements PhaseView { ...@@ -40,6 +41,13 @@ export class SequenceView extends TextView implements PhaseView {
this.divNode.innerHTML = ''; this.divNode.innerHTML = '';
this.sequence = data.sequence; this.sequence = data.sequence;
this.search_info = []; 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.addBlocks(this.sequence.blocks);
this.attachSelection(rememberedSelection); this.attachSelection(rememberedSelection);
} }
...@@ -91,6 +99,8 @@ export class SequenceView extends TextView implements PhaseView { ...@@ -91,6 +99,8 @@ export class SequenceView extends TextView implements PhaseView {
const instNodeEl = createElement("div", "instruction-node"); const instNodeEl = createElement("div", "instruction-node");
const inst_id = createElement("div", "instruction-id", instruction.id); const inst_id = createElement("div", "instruction-id", instruction.id);
inst_id.classList.add("clickable");
inst_id.dataset.instructionId = instruction.id;
instNodeEl.appendChild(inst_id); instNodeEl.appendChild(inst_id);
const instContentsEl = createElement("div", "instruction-contents"); const instContentsEl = createElement("div", "instruction-contents");
......
...@@ -372,6 +372,14 @@ export class SourceResolver { ...@@ -372,6 +372,14 @@ export class SourceResolver {
return this.instructionToPCOffset.slice(start, end); return this.instructionToPCOffset.slice(start, end);
} }
instructionsToKeyPcOffsets(instructionIds) {
const keyPcOffsets = [];
for (const instructionId of instructionIds) {
keyPcOffsets.push(this.instructionToPCOffset[instructionId]);
}
return keyPcOffsets;
}
nodesToKeyPcOffsets(nodes) { nodesToKeyPcOffsets(nodes) {
let offsets = []; let offsets = [];
for (const node of nodes) { for (const node of nodes) {
......
...@@ -6,6 +6,7 @@ import { View } from "../src/view" ...@@ -6,6 +6,7 @@ import { View } from "../src/view"
import { anyToString, ViewElements, isIterable } from "../src/util" import { anyToString, ViewElements, isIterable } from "../src/util"
import { MySelection } from "../src/selection" import { MySelection } from "../src/selection"
import { SourceResolver } from "./source-resolver"; import { SourceResolver } from "./source-resolver";
import { SelectionBroker } from "./selection-broker";
export abstract class TextView extends View { export abstract class TextView extends View {
selectionHandler: NodeSelectionHandler; selectionHandler: NodeSelectionHandler;
...@@ -20,6 +21,7 @@ export abstract class TextView extends View { ...@@ -20,6 +21,7 @@ export abstract class TextView extends View {
nodeIdToBlockId: Array<string>; nodeIdToBlockId: Array<string>;
patterns: any; patterns: any;
sourceResolver: SourceResolver; sourceResolver: SourceResolver;
broker: SelectionBroker;
constructor(id, broker, patterns) { constructor(id, broker, patterns) {
super(id); super(id);
...@@ -32,6 +34,7 @@ export abstract class TextView extends View { ...@@ -32,6 +34,7 @@ export abstract class TextView extends View {
view.nodeIdToBlockId = []; view.nodeIdToBlockId = [];
view.selection = new MySelection(anyToString); view.selection = new MySelection(anyToString);
view.blockSelection = new MySelection(anyToString); view.blockSelection = new MySelection(anyToString);
view.broker = broker;
view.sourceResolver = broker.sourceResolver; view.sourceResolver = broker.sourceResolver;
const selectionHandler = { const selectionHandler = {
clear: function () { clear: function () {
...@@ -136,7 +139,12 @@ export abstract class TextView extends View { ...@@ -136,7 +139,12 @@ export abstract class TextView extends View {
for (const el of elementsToSelect) { for (const el of elementsToSelect) {
el.classList.toggle("selected", false); 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) { for (const keyPcOffset of keyPcOffsets) {
const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset='${keyPcOffset}']`) const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset='${keyPcOffset}']`)
for (const el of elementsToSelect) { for (const el of elementsToSelect) {
......
...@@ -289,11 +289,11 @@ input:hover, .collapse-pane:hover input { ...@@ -289,11 +289,11 @@ input:hover, .collapse-pane:hover input {
cursor: pointer; cursor: pointer;
} }
span.linkable-text { .linkable-text {
text-decoration: underline; text-decoration: underline;
} }
span.linkable-text:hover { .linkable-text:hover {
cursor: pointer; cursor: pointer;
font-weight: bold; font-weight: bold;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment