Skip to content

Commit 860dcd0

Browse files
committed
Highlight corresponding line numbers on bytes highlight
1 parent 2143f29 commit 860dcd0

4 files changed

Lines changed: 107 additions & 40 deletions

File tree

src/classes/FrameDetailsTree.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class FrameDetailsTree {
2828

2929
get byteGroups() {
3030
if (this.#core.byteGroups === null)
31-
this.#core.byteGroups = this.#parseByteGroups();
31+
this.#core.byteGroups = Object.freeze(this.#parseByteGroups());
3232
return this.#core.byteGroups;
3333
}
3434

@@ -73,9 +73,7 @@ class FrameDetailsTree {
7373

7474
// sort start asc, length desc
7575
for (const group of groups)
76-
group.sort((a, b) =>
77-
a.start == b.start ? b.length - a.length : a.start - b.start
78-
);
76+
group.sort((a, b) => a.start - b.start || b.length - a.length);
7977

8078
return groups;
8179
}

src/components/panes/PacketBytes/BytesDisplay.js

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ const spacers = {
1111
ebcdic: { every1: null, every8: " " },
1212
};
1313

14-
// TODO: possible reactivity issues here
14+
// TODO: highlighting only works for hierarchical groups.
15+
// this might become an issue later on when searching through packet
16+
// bytes and we can't really highlight an arbitrary range of bytes
1517

1618
export default {
1719
props: {
@@ -37,14 +39,7 @@ export default {
3739
props.sourceIndex
3840
);
3941

40-
const nodeStack = [{ end: Infinity, children: [], id: "default" }];
41-
42-
const buildCSSVarLadder = (prefix) =>
43-
nodeStack.reduce(
44-
(varLadder, { id }) =>
45-
`var(${prefix}${id}${varLadder ? ", " + varLadder : ""})`,
46-
""
47-
);
42+
const nodeStack = [{ end: Infinity, children: [] }];
4843

4944
let groupIdx = 0;
5045
for (const [idx, displayByte] of displayBytes.entries()) {
@@ -72,15 +67,13 @@ export default {
7267

7368
// end groups
7469
while (nodeStack.at(-1).end === idx + 1) {
75-
const style = {
76-
color: buildCSSVarLadder("--ws-detail-fg-"),
77-
backgroundColor: buildCSSVarLadder("--ws-detail-bg-"),
78-
};
79-
8070
const { id, children } = nodeStack.pop();
8171

82-
const nodeProps = { "data-detail-id": id, style };
83-
const vnode = h("span", nodeProps, children);
72+
const style = {
73+
color: `var(--ws-detail-fg-${id}, inherit)`,
74+
backgroundColor: `var(--ws-detail-bg-${id}, inherit)`,
75+
};
76+
const vnode = h("span", { "data-detail-id": id, style }, children);
8477

8578
nodes = nodeStack.at(-1).children;
8679
nodes.push(vnode);
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { h } from "vue";
2+
import { manager } from "../../../globals";
3+
4+
const spacers = {
5+
hexadecimal: { every1: " ", every8: " " },
6+
decimal: { every1: " ", every8: " " },
7+
octal: { every1: " ", every8: " " },
8+
bits: { every1: " ", every8: " " },
9+
ascii: { every1: null, every8: " " },
10+
ebcdic: { every1: null, every8: " " },
11+
};
12+
13+
// TODO: possible reactivity issues here
14+
15+
export default {
16+
props: {
17+
bytesPerLine: {
18+
type: Number,
19+
required: true,
20+
},
21+
sourceIndex: {
22+
type: Number,
23+
required: true,
24+
},
25+
},
26+
setup(props) {
27+
return () => {
28+
const bytes = manager.activeFrameDetails.getSourceData(props.sourceIndex);
29+
const lineCount = bytes.length / props.bytesPerLine;
30+
const groups = manager.activeFrameDetails.getGroupsForSource(
31+
props.sourceIndex
32+
);
33+
34+
const nodes = [];
35+
36+
const activeGroups = new Map();
37+
38+
let groupIdx = 0;
39+
let changed = true;
40+
for (let line = 0; line < lineCount; line++) {
41+
// start groups
42+
const till = (line + 1) * props.bytesPerLine;
43+
while (groupIdx < groups.length && groups[groupIdx].start < till) {
44+
const { start, length, id } = groups[groupIdx++];
45+
46+
const end = Math.floor((start + length - 1) / props.bytesPerLine);
47+
48+
if (!activeGroups.has(end)) activeGroups.set(end, []);
49+
activeGroups.get(end).push(id);
50+
changed = true;
51+
}
52+
53+
// line number (in hex)
54+
const lineNumber =
55+
(line * props.bytesPerLine).toString(16).padStart(4, "0") + "\n";
56+
57+
if (changed) {
58+
const ids = [...activeGroups.values()].flat();
59+
const color = ids.reduce(
60+
(colorVar, id) => `var(--ws-linenumber-fg-${id}, ${colorVar})`,
61+
"inherit"
62+
);
63+
nodes.push({ color, html: lineNumber });
64+
} else nodes.at(-1).html += lineNumber;
65+
66+
changed = false;
67+
68+
// end groups
69+
if (activeGroups.has(line)) {
70+
activeGroups.delete(line);
71+
changed = true;
72+
}
73+
}
74+
75+
const vnodes = nodes.map(({ html, color }) =>
76+
h("span", { style: { color } }, html)
77+
);
78+
return h("div", vnodes);
79+
};
80+
},
81+
};

src/components/panes/PacketBytes/SourceDisplay.vue

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup>
22
import { computed, reactive, watch } from "vue";
33
import BytesDisplay from "./BytesDisplay";
4+
import LineNumbers from "./LineNumbers";
45
import { manager } from "../../../globals";
56
67
const props = defineProps({
@@ -17,25 +18,17 @@ const state = reactive({
1718
1819
// computed
1920
bytesPerLine: 0,
20-
lineNumbers: [],
2121
containerStyles: {},
2222
});
2323
2424
state.bytesPerLine = computed(() =>
2525
state.bytesDisplayFormat === "bits" ? 8 : 16
2626
);
2727
28-
state.lineNumbers = computed(() => {
29-
const bytes = manager.activeFrameDetails?.getSourceData(props.sourceIndex);
30-
const lineCount = Math.ceil((bytes?.length ?? 0) / 16);
31-
return Array.from({ length: lineCount }, (_, i) =>
32-
(i * 16).toString(16).padStart(4, "0")
33-
);
34-
});
35-
3628
state.containerStyles = computed(() => {
3729
if (state.activeDetailId === null) return {};
3830
return {
31+
[`--ws-linenumber-fg-${state.activeDetailId}`]: "#666",
3932
[`--ws-detail-fg-${state.activeDetailId}`]: "white",
4033
[`--ws-detail-bg-${state.activeDetailId}`]: "#3f3f3f",
4134
};
@@ -64,9 +57,11 @@ watch(
6457
v-if="sourceIndex !== null"
6558
:style="state.containerStyles"
6659
>
67-
<div class="line-numbers">
68-
<div v-for="lineNumber in state.lineNumbers">{{ lineNumber }}</div>
69-
</div>
60+
<LineNumbers
61+
class="line-numbers"
62+
:bytesPerLine="state.bytesPerLine"
63+
:sourceIndex
64+
/>
7065
<BytesDisplay
7166
class="display bytes"
7267
:displayFormat="state.bytesDisplayFormat"
@@ -104,18 +99,18 @@ watch(
10499
overflow-y: auto;
105100
}
106101
.line-numbers {
107-
display: flex;
108-
flex-direction: column;
102+
color: var(--ws-darkest-gray);
103+
background-color: var(--ws-light-gray);
109104
width: 6ch;
110-
height: fit-content;
111-
min-height: 100%;
112105
padding: 0 1ch;
113-
background-color: var(--ws-light-gray);
114-
color: var(--ws-darkest-gray);
106+
min-height: 100%;
107+
white-space: pre-wrap;
108+
flex-shrink: 0;
109+
height: fit-content;
115110
}
116111
.display {
117-
--ws-detail-fg-default: black;
118-
--ws-detail-bg-default: transparent;
112+
color: black;
113+
background-color: transparent;
119114
white-space: pre-wrap;
120115
flex-shrink: 0;
121116
}

0 commit comments

Comments
 (0)