From 4ac823a1bc9d3b572de713ac59a5aabd5f0ff599 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sun, 28 Apr 2024 10:56:45 -0700 Subject: [PATCH] fix: device id change UI event chain fixed; changing the Active IC's ID no longer breaks the UI --- ic10emu/src/vm.rs | 8 ++- www/src/ts/editor/index.ts | 88 +++++++++++------------ www/src/ts/session.ts | 27 +++++-- www/src/ts/virtual_machine/base_device.ts | 67 +++++++++++------ www/src/ts/virtual_machine/device/card.ts | 2 +- www/src/ts/virtual_machine/index.ts | 35 ++++++--- 6 files changed, 139 insertions(+), 88 deletions(-) diff --git a/ic10emu/src/vm.rs b/ic10emu/src/vm.rs index d7819ce..f95c5b9 100644 --- a/ic10emu/src/vm.rs +++ b/ic10emu/src/vm.rs @@ -285,11 +285,15 @@ impl VM { device.borrow_mut().id = new_id; self.devices.insert(new_id, device); self.ics.iter().for_each(|(_id, ic)| { - ic.borrow().pins.borrow_mut().iter_mut().for_each(|pin| { + let mut ic_ref = ic.borrow_mut(); + if ic_ref.device == old_id { + ic_ref.device = new_id; + } + ic_ref.pins.borrow_mut().iter_mut().for_each(|pin| { if pin.is_some_and(|d| d == old_id) { pin.replace(new_id); } - }) + }); }); self.networks.iter().for_each(|(_net_id, net)| { if let Ok(mut net_ref) = net.try_borrow_mut() { diff --git a/www/src/ts/editor/index.ts b/www/src/ts/editor/index.ts index 8f65c7c..f9b6660 100644 --- a/www/src/ts/editor/index.ts +++ b/www/src/ts/editor/index.ts @@ -35,9 +35,9 @@ export class IC10Editor extends BaseElement { }; sessions: Map; - @state() active_session: number = 1; + @state() activeSession: number = 1; - active_line_markers: Map = new Map(); + activeLineMarkers: Map = new Map(); languageProvider?: LanguageProvider; // ui: IC10EditorUI; @@ -78,56 +78,35 @@ export class IC10Editor extends BaseElement { }; this.sessions = new Map(); - this.active_line_markers = new Map(); + this.activeLineMarkers = new Map(); // this.ui = new IC10EditorUI(this); } protected render() { const result = html` -
-
+
+
+
- + Ace Vim Emacs Sublime VS Code - + Ace Slim Smooth Smooth And Slim Wide - - + + Relative Line Numbers @@ -230,12 +209,9 @@ export class IC10Editor extends BaseElement { // characterData: false, // }); - this.sessions.set(this.active_session, this.editor.getSession()); - this.bindSession( - this.active_session, - this.sessions.get(this.active_session), - ); - this.active_line_markers.set(this.active_session, null); + this.sessions.set(this.activeSession, this.editor.getSession()); + this.bindSession(this.activeSession, this.sessions.get(this.activeSession)); + this.activeLineMarkers.set(this.activeSession, null); const worker = await setupLspWorker(); this.setupLsp(worker); @@ -264,35 +240,35 @@ export class IC10Editor extends BaseElement { const that = this; const app = await window.App.get(); - app.session.onLoad(((e: CustomEvent) => { + app.session.onLoad((_e) => { const session = app.session; const updated_ids: number[] = []; for (const [id, code] of session.programs) { updated_ids.push(id); that.createOrSetSession(id, code); } - that.activateSession(that.active_session); + that.activateSession(that.activeSession); for (const [id, _] of that.sessions) { if (!updated_ids.includes(id)) { that.destroySession(id); } } - }) as EventListener); + }); app.session.loadFromFragment(); - app.session.onActiveLine(((e: CustomEvent) => { + app.session.onActiveLine((e) => { const session = app.session; const id: number = e.detail; const active_line = session.getActiveLine(id); if (typeof active_line !== "undefined") { - const marker = that.active_line_markers.get(id); + const marker = that.activeLineMarkers.get(id); if (marker) { that.sessions.get(id)?.removeMarker(marker); - that.active_line_markers.set(id, null); + that.activeLineMarkers.set(id, null); } const session = that.sessions.get(id); if (session) { - that.active_line_markers.set( + that.activeLineMarkers.set( id, session.addMarker( new Range(active_line, 0, active_line, 1), @@ -301,14 +277,30 @@ export class IC10Editor extends BaseElement { true, ), ); - if (that.active_session == id) { + if (that.activeSession == id) { // editor.resize(true); // TODO: Scroll to line if vm was stepped //that.editor.scrollToLine(active_line, true, true, ()=>{}) } } } - }) as EventListener); + }); + + app.session.onIDChange((e) => { + const oldID = e.detail.old; + const newID = e.detail.new; + if (this.sessions.has(oldID)) { + this.sessions.set(newID, this.sessions.get(oldID)); + this.sessions.delete(oldID); + } + if (this.activeLineMarkers.has(oldID)) { + this.activeLineMarkers.set(newID, this.activeLineMarkers.get(oldID)); + this.activeLineMarkers.delete(oldID); + } + if (this.activeSession === oldID) { + this.activeSession = newID; + } + }); // change -> possibility to allow saving the value without having to wait for blur editor.on("change", () => this.editorChangeAction()); @@ -521,7 +513,7 @@ export class IC10Editor extends BaseElement { const mode = ace.require(this.mode); const options = mode?.options ?? {}; this.languageProvider?.setSessionOptions(session, options); - this.active_session = session_id; + this.activeSession = session_id; return true; } @@ -569,7 +561,7 @@ export class IC10Editor extends BaseElement { } const session = this.sessions.get(session_id); this.sessions.delete(session_id); - if ((this.active_session = session_id)) { + if ((this.activeSession = session_id)) { this.activateSession(this.sessions.entries().next().value); } session?.destroy(); diff --git a/www/src/ts/session.ts b/www/src/ts/session.ts index 0523563..3037e3a 100644 --- a/www/src/ts/session.ts +++ b/www/src/ts/session.ts @@ -1,4 +1,3 @@ - import type { ICError, FrozenVM, SlotType } from "ic10emu_wasm"; import { App } from "./app"; @@ -57,7 +56,25 @@ export class Session extends EventTarget { ); } - onActiveIc(callback: EventListenerOrEventListenerObject) { + changeID(oldID: number, newID: number) { + if (this.programs.has(oldID)) { + this.programs.set(newID, this.programs.get(oldID)); + this.programs.delete(oldID); + } + this.dispatchEvent( + new CustomEvent("session-id-change", { + detail: { old: oldID, new: newID }, + }), + ); + } + + onIDChange( + callback: (e: CustomEvent<{ old: number; new: number }>) => any, + ) { + this.addEventListener("session-id-change", callback); + } + + onActiveIc(callback: (e: CustomEvent) => any,) { this.addEventListener("session-active-ic", callback); } @@ -98,11 +115,11 @@ export class Session extends EventTarget { ); } - onErrors(callback: EventListenerOrEventListenerObject) { + onErrors(callback: (e: CustomEvent) => any) { this.addEventListener("session-errors", callback); } - onLoad(callback: EventListenerOrEventListenerObject) { + onLoad(callback: (e: CustomEvent) => any) { this.addEventListener("session-load", callback); } @@ -114,7 +131,7 @@ export class Session extends EventTarget { ); } - onActiveLine(callback: EventListenerOrEventListenerObject) { + onActiveLine(callback: (e: CustomEvent) => any) { this.addEventListener("active-line", callback); } diff --git a/www/src/ts/virtual_machine/base_device.ts b/www/src/ts/virtual_machine/base_device.ts index 1a11cf8..a2626b9 100644 --- a/www/src/ts/virtual_machine/base_device.ts +++ b/www/src/ts/virtual_machine/base_device.ts @@ -111,60 +111,80 @@ export const VMDeviceMixin = >( connectedCallback(): void { const root = super.connectedCallback(); - window.VM.get().then((vm) => + window.VM.get().then((vm) => { vm.addEventListener( "vm-device-modified", this._handleDeviceModified.bind(this), - ), - ); - window.VM.get().then((vm) => + ); vm.addEventListener( "vm-devices-update", this._handleDevicesModified.bind(this), - ), - ); + ); + vm.addEventListener( + "vm-device-id-change", + this._handleDeviceIdChange.bind(this), + ); + }); this.updateDevice(); return root; } disconnectedCallback(): void { - window.VM.get().then((vm) => + window.VM.get().then((vm) => { vm.removeEventListener( "vm-device-modified", this._handleDeviceModified.bind(this), - ), - ); - window.VM.get().then((vm) => + ); vm.removeEventListener( "vm-devices-update", this._handleDevicesModified.bind(this), - ), - ); + ); + vm.removeEventListener( + "vm-device-id-change", + this._handleDeviceIdChange.bind(this), + ); + }); } _handleDeviceModified(e: CustomEvent) { const id = e.detail; - const activeIc = window.VM.vm.activeIC; + const activeIcId = window.App.app.session.activeIC; if (this.deviceID === id) { this.updateDevice(); - } else if (id === activeIc.id && this.deviceSubscriptions.includes("active-ic")) { + } else if ( + id === activeIcId && + this.deviceSubscriptions.includes("active-ic") + ) { this.updateDevice(); } } _handleDevicesModified(e: CustomEvent) { - const activeIc = window.VM.vm.activeIC; + const activeIcId = window.App.app.session.activeIC; const ids = e.detail; if (ids.includes(this.deviceID)) { - this.updateDevice() - } else if (ids.includes(activeIc.id) && this.deviceSubscriptions.includes("active-ic")) { this.updateDevice(); + } else if ( + ids.includes(activeIcId) && + this.deviceSubscriptions.includes("active-ic") + ) { + this.updateDevice(); + } + } + + _handleDeviceIdChange(e: CustomEvent<{ old: number; new: number }>) { + if (this.deviceID === e.detail.old) { + this.deviceID = e.detail.new; } } updateDevice() { this.device = window.VM.vm.devices.get(this.deviceID)!; + if (typeof this.device === "undefined") { + return; + } + for (const sub of this.deviceSubscriptions) { if (typeof sub === "string") { if (sub == "name") { @@ -220,16 +240,21 @@ export const VMDeviceMixin = >( } } } else { - if ( "field" in sub ) { + if ("field" in sub) { const fields = this.device.fields; if (this.fields.get(sub.field) !== fields.get(sub.field)) { this.fields = fields; } - } else if ( "slot" in sub) { + } else if ("slot" in sub) { const slots = this.device.slots; - if (typeof this.slots === "undefined" || this.slots.length < sub.slot) { + if ( + typeof this.slots === "undefined" || + this.slots.length < sub.slot + ) { this.slots = slots; - } else if (!structuralEqual(this.slots[sub.slot], slots[sub.slot])) { + } else if ( + !structuralEqual(this.slots[sub.slot], slots[sub.slot]) + ) { this.slots = slots; } } diff --git a/www/src/ts/virtual_machine/device/card.ts b/www/src/ts/virtual_machine/device/card.ts index 6d9a04d..c66a636 100644 --- a/www/src/ts/virtual_machine/device/card.ts +++ b/www/src/ts/virtual_machine/device/card.ts @@ -361,7 +361,7 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { const val = parseIntWithHexOrBinary(input.value); if (!isNaN(val)) { window.VM.get().then((vm) => { - if (!vm.changeDeviceId(this.deviceID, val)) { + if (!vm.changeDeviceID(this.deviceID, val)) { input.value = this.deviceID.toString(); } }); diff --git a/www/src/ts/virtual_machine/index.ts b/www/src/ts/virtual_machine/index.ts index 7bb335d..8e90d7c 100644 --- a/www/src/ts/virtual_machine/index.ts +++ b/www/src/ts/virtual_machine/index.ts @@ -22,7 +22,7 @@ export interface ToastMessage { } export interface CacheDeviceRef extends DeviceRef { - dirty: boolean + dirty: boolean; } function cachedDeviceRef(ref: DeviceRef) { @@ -43,12 +43,12 @@ function cachedDeviceRef(ref: DeviceRef) { }, set(target, prop, value) { if (prop === "dirty") { - slotsDirty = value + slotsDirty = value; return true; } - return Reflect.set(target, prop, value) - } - }) as CacheDeviceRef + return Reflect.set(target, prop, value); + }, + }) as CacheDeviceRef; } class VirtualMachine extends EventTarget { @@ -264,13 +264,22 @@ class VirtualMachine extends EventTarget { this.dispatchEvent(new CustomEvent("vm-message", { detail: message })); } - changeDeviceId(old_id: number, new_id: number): boolean { + changeDeviceID(oldID: number, newID: number): boolean { try { - this.ic10vm.changeDeviceId(old_id, new_id); - this.updateDevices(); - if (this.app.session.activeIC === old_id) { - this.app.session.activeIC = new_id; + this.ic10vm.changeDeviceId(oldID, newID); + if (this.app.session.activeIC === oldID) { + this.app.session.activeIC = newID; } + this.updateDevices(); + this.dispatchEvent( + new CustomEvent("vm-device-id-change", { + detail: { + old: oldID, + new: newID, + }, + }), + ); + this.app.session.changeID(oldID, newID); return true; } catch (err) { this.handleVmError(err); @@ -430,7 +439,11 @@ class VirtualMachine extends EventTarget { } } - setDeviceSlotOccupant(id: number, index: number, template: SlotOccupantTemplate): boolean { + setDeviceSlotOccupant( + id: number, + index: number, + template: SlotOccupantTemplate, + ): boolean { const device = this._devices.get(id); if (typeof device !== "undefined") { try {