Skip to content

Commit feec6b0

Browse files
committed
keep track of source
1 parent e0279f8 commit feec6b0

File tree

7 files changed

+127
-24
lines changed

7 files changed

+127
-24
lines changed

src/webpage/assembler/assembler.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ function assemble(files: [string, string][]) {
145145
const globalDataLabels: linkerInfo = new Map();
146146
const globalLabelMap: labelMap = new Map();
147147

148+
const asmMap = new Map<number, {file: string; line: number}>();
149+
148150
function link(labelMap: labelMap, dataLables: linkerInfo, globalRun = false, macro = false) {
149151
const ram = new Ram(dataView, textView, [dataIndex, textIndex, 1 << 22]);
150152

@@ -293,6 +295,10 @@ function assemble(files: [string, string][]) {
293295
file,
294296
);
295297
}
298+
asmMap.set(place === "text" ? textIndex + 0x00400000 : dataIndex + 0x10010000, {
299+
file,
300+
line: i,
301+
});
296302
if ((directive === "ascii" || directive === "asciz") && place === "data") {
297303
if (data.type !== "string") {
298304
throw new AssemblError(I18n.errors.notAString(i + 1 + "", data.type), i, file);
@@ -1204,6 +1210,6 @@ function assemble(files: [string, string][]) {
12041210
console.warn("global linking");
12051211
const ram = link(globalLabelMap, globalDataLabels, true);
12061212
const main = globalLabelMap.get("main");
1207-
return [ram, main || 0x00400000] as [Ram, number];
1213+
return [ram, main || 0x00400000, asmMap] as [Ram, number, typeof asmMap];
12081214
}
12091215
export {assemble, AssemblError};

src/webpage/editor/editor.ts

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,26 +82,42 @@ class Editor extends EventTarget {
8282
height = 18;
8383
charWidth = 18;
8484
postDraw: (() => void)[] = [];
85+
focusedLine?: number;
86+
focusLine(index?: number) {
87+
this.focusedLine = index;
88+
const linedown = Math.floor(this.scroll.linedown);
89+
if (index !== undefined) {
90+
console.log(index, linedown, this.height);
91+
if (index < linedown) {
92+
this.scroll.linedown = index;
93+
}
94+
if (index > linedown + this.height) {
95+
this.scroll.linedown = this.height + index;
96+
}
97+
}
98+
99+
this.forceCanvasUpdate();
100+
}
85101
renderToCanvas(ctx: CanvasRenderingContext2D) {
86102
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
87103
const fontSize = this.fontSize;
88104
const height = Math.floor(ctx.canvas.height / this.fontSize);
89-
this.height = height;
105+
this.height = height || this.height;
90106
ctx.font = `${fontSize}px monospace`;
91107
const charWidth = ctx.measureText("a").width;
92108
this.charWidth = charWidth;
93109
ctx.textBaseline = "hanging";
94110
const linedown = Math.floor(this.scroll.linedown);
95111
const widthNeeded = this.widthNeeded();
112+
const theme = (localStorage.getItem("theme") || "dark") as "light" | "dark";
96113
for (let i = linedown; i < height + linedown; i++) {
97114
const line = this.lines[i];
98-
if (line && line.errored) {
99-
ctx.fillStyle = "lemonchiffon";
115+
if ((line && line.errored) || this.focusedLine === i) {
116+
ctx.fillStyle = theme == "light" ? "lemonchiffon" : "yellowgreen";
100117
const y = (i - linedown) * fontSize;
101118
ctx.fillRect(widthNeeded + 10, y, ctx.canvas.width, this.fontSize);
102119
}
103120
}
104-
const theme = (localStorage.getItem("theme") || "dark") as "light" | "dark";
105121

106122
if ("highlights" in this.cursor) {
107123
ctx.fillStyle = theme == "light" ? "LightBlue" : "darkblue";
@@ -538,10 +554,14 @@ class Editor extends EventTarget {
538554
}
539555
return strings;
540556
}
557+
forceCanvasUpdate = () => {};
541558
ownCanvas(c: HTMLCanvasElement) {
542559
let lastClicked = 0;
543560
const ctx = c.getContext("2d");
544561
if (!ctx) throw Error("Unable to get canvas context 2d");
562+
this.forceCanvasUpdate = () => {
563+
this.renderToCanvas(ctx);
564+
};
545565
const mut = new ResizeObserver((e) => {
546566
for (const _ of e) {
547567
}
@@ -943,34 +963,33 @@ class Editor extends EventTarget {
943963
try {
944964
this.console.addMessage("\n" + I18n.startingAssembly() + "\n\n");
945965
let emu: Symstem;
966+
const asm: [string, string][] = [];
946967
if (this.dir && this.fileDir) {
947968
const dirL = this.fileDir.split("/");
948969
dirL.pop();
949970
const dir = dirL.join("/") + "/";
950-
const build: [string, string][] = [[this.string(), this.fileDir]];
971+
asm.push([this.string(), this.fileDir]);
951972
for await (const [name, thing] of this.dir.getAllInDir()) {
952973
if (thing instanceof Directory) continue;
953974
if (!name.endsWith(".asm")) continue;
954975
const thisDir = dir + name;
955976
if (thisDir === this.fileDir) continue;
956977
const editor = Editor.editMap.get(thisDir);
957978
if (editor) {
958-
build.push([editor.string(), thisDir]);
979+
asm.push([editor.string(), thisDir]);
959980
} else {
960-
build.push([await thing.text(), thisDir]);
981+
asm.push([await thing.text(), thisDir]);
961982
}
962983
}
963-
const [ram, pc] = assemble(build);
964-
emu = new Symstem(ram, this.console);
965-
emu.pc = pc;
966984
} else {
967-
const [ram, pc] = assemble([[this.string(), this.fileDir || this.fileName]]);
968-
emu = new Symstem(ram, this.console);
969-
emu.pc = pc;
985+
asm.push([this.string(), this.fileDir || this.fileName]);
970986
}
987+
const [ram, pc, instMap] = assemble(asm);
988+
emu = new Symstem(ram, this.console);
989+
emu.pc = pc;
971990
emu.intRegis[2] = 0x7fffeffcn;
972991
this.console.addMessage("\n" + I18n.finishedAssembly() + "\n\n");
973-
this.dispatchEvent(new AssembleEvent("Assemble", emu));
992+
this.dispatchEvent(new AssembleEvent("Assemble", {emu, instMap, asm}));
974993
} catch (e) {
975994
if (e instanceof AssemblError) {
976995
this.dispatchEvent(new AssembleEvent("Assemble", e));
@@ -989,8 +1008,15 @@ class Editor extends EventTarget {
9891008
}
9901009
}
9911010
class AssembleEvent extends Event {
992-
sys: Symstem | AssemblError;
993-
constructor(code: string, sys: Symstem | AssemblError) {
1011+
sys:
1012+
| {emu: Symstem; instMap: Map<number, {file: string; line: number}>; asm: [string, string][]}
1013+
| AssemblError;
1014+
constructor(
1015+
code: string,
1016+
sys:
1017+
| {emu: Symstem; instMap: Map<number, {file: string; line: number}>; asm: [string, string][]}
1018+
| AssemblError,
1019+
) {
9941020
super(code);
9951021
this.sys = sys;
9961022
}

src/webpage/editor/line.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ class Line {
196196
charWidth: number,
197197
tips: string[],
198198
) {
199+
if (this.owner.focusedLine !== undefined) return;
199200
y += this.owner.fontSize + 6;
200201
x -= 5;
201202
if (ctx.canvas.width - x <= charWidth * 40) {

src/webpage/executeTab/etab.ts

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,19 @@ class Etab {
120120
this.updateMemCell(addr, false);
121121
}
122122
}
123-
handSystem(sys: Symstem) {
123+
instMap?: Map<number, {file: string; line: number}>;
124+
asm?: [string, string][];
125+
handSystem(sys: {
126+
emu: Symstem;
127+
instMap: Map<number, {file: string; line: number}>;
128+
asm: [string, string][];
129+
}) {
124130
this.csysQue = new Array(1000);
125-
this.sys = sys;
131+
this.sys = sys.emu;
132+
this.instMap = sys.instMap;
133+
this.asm = sys.asm;
126134
this.systemReg();
127-
this.csys = sys.compact();
135+
this.csys = sys.emu.compact();
128136
}
129137
systemReg() {
130138
if (!this.sys) return;
@@ -255,6 +263,7 @@ class Etab {
255263
this.started = false;
256264
this.csysQue = new Array(1000);
257265
this.changeButtonStates();
266+
this.onLine(undefined);
258267
}
259268
updateLastUsed() {
260269
try {
@@ -285,6 +294,8 @@ class Etab {
285294
}
286295
}
287296
}
297+
298+
onLine: (line: {line: number; file: string} | undefined) => void = () => {};
288299
async start() {
289300
if (this.sys) {
290301
if (this.running) await this.running;
@@ -303,6 +314,7 @@ class Etab {
303314
console.log("waitStep");
304315
await this.waitStep();
305316
} else {
317+
this.onLine(undefined);
306318
this.enque();
307319
if (i >= 1000) {
308320
i = 0;
@@ -326,6 +338,7 @@ class Etab {
326338
if (elm && !sys.done) {
327339
elm.classList.add("running");
328340
}
341+
if (sys.done) this.onLine(undefined);
329342
res();
330343
this.running = undefined;
331344
this.stopped = true;
@@ -358,11 +371,13 @@ class Etab {
358371
console.error(e);
359372
}
360373
}
374+
this.onLine(this.getCurrentIndex());
361375
elm = this.htmlMap.get(this.sys.pc);
362376
if (elm && !sys.done) {
363377
elm.classList.add("running");
364378
elm.scrollIntoView({behavior: "instant", block: "center"});
365379
}
380+
if (sys.done) this.onLine(undefined);
366381
this.updateRegis();
367382
}
368383
this.changeButtonStates();
@@ -372,6 +387,24 @@ class Etab {
372387
}
373388
});
374389
}
390+
getFileLine(line: {file: string; line: number}): string {
391+
if (Number.isNaN(line.line)) return "";
392+
if (!this.asm) return "";
393+
for (const [contents, file] of this.asm) {
394+
if (file === line.file) {
395+
return (
396+
(this.asm.length === 1 ? "" : line.file.replace(/.*:\//m, "") + ", ") +
397+
line.line +
398+
": " +
399+
contents.split("\n")[line.line]
400+
);
401+
}
402+
}
403+
return "";
404+
}
405+
getCurrentIndex() {
406+
return this.instMap?.get(this.sys?.pc as number);
407+
}
375408
createHTML() {
376409
this.htmlMap = new Map();
377410
const div = document.createElement("div");
@@ -394,6 +427,12 @@ class Etab {
394427
const basic = document.createElement("th");
395428
basic.textContent = I18n.basic();
396429
tr.append(basic);
430+
431+
if (this.instMap) {
432+
const source = document.createElement("th");
433+
source.textContent = I18n.source();
434+
tr.append(source);
435+
}
397436
table.append(tr);
398437
if (this.sys) {
399438
this.enableButtons();
@@ -416,6 +455,15 @@ class Etab {
416455
const basic = document.createElement("td");
417456
basic.textContent = toAsm(val);
418457
tr.append(basic);
458+
459+
if (this.instMap) {
460+
const code = document.createElement("td");
461+
const val = this.instMap.get(i);
462+
if (val) {
463+
code.textContent = this.getFileLine(val);
464+
}
465+
tr.append(code);
466+
}
419467
table.append(tr);
420468
}
421469
}

src/webpage/index.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,13 +362,35 @@ assemble.onclick = () => {
362362

363363
const editButton = document.getElementById("EditButton") as HTMLButtonElement;
364364
const executeButton = document.getElementById("ExecuteButton") as HTMLButtonElement;
365+
let inEdit = true;
365366
editButton.onclick = () => {
367+
inEdit = true;
366368
editArea();
369+
console.log(inEdit);
367370
};
368371
executeButton.onclick = () => {
369-
if (system.isReady()) executeArea();
372+
if (system.isReady()) {
373+
executeArea();
374+
inEdit = false;
375+
console.log(inEdit);
376+
}
370377
};
371378
let system = new Etab();
379+
system.onLine = (line) => {
380+
for (const editor of editors) {
381+
if (editor.fileDir === line?.file) {
382+
editor.focusLine(line?.line);
383+
} else {
384+
editor.focusLine(undefined);
385+
}
386+
}
387+
console.log(inEdit);
388+
if (inEdit) {
389+
const editor = editors.find((editor) => editor.fileDir === line?.file);
390+
if (!editor) return;
391+
buttons.get(editor)?.click();
392+
}
393+
};
372394

373395
const buttons = new Map<Editor, HTMLButtonElement>();
374396
const saved = new Map<Editor, boolean>();
@@ -439,9 +461,6 @@ async function editArea() {
439461
});
440462

441463
button.addEventListener("click", () => {
442-
if (focusedEditor !== editor) {
443-
system.disable();
444-
}
445464
focusedEditor = editor;
446465
if (selectedTab) {
447466
selectedTab.classList.remove("selected");
@@ -677,6 +696,7 @@ async function openProject(proj: Project) {
677696
const consoleElm = document.getElementById("console") as HTMLDivElement;
678697
consoleElm.append(cons.makeHtml());
679698
function executeArea() {
699+
inEdit = false;
680700
area.innerHTML = "";
681701

682702
editButton.classList.remove("selected");

src/webpage/style.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ body {
99
-webkit-text-size-adjust: 100%;
1010
}
1111
.dark-theme {
12+
color-scheme: dark;
1213
background: #1b1b1b;
1314
color: #ffffff;
1415
#mainRow {

translations/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"memvalue":"Value (+$1)",
9494
"code": "Code",
9595
"basic": "Basic",
96+
"source":"Source",
9697
"startScreen": "Open a file or start a project!",
9798
"startProject": "Start a new project",
9899
"openFile": "Open a file!",

0 commit comments

Comments
 (0)