Renable session saving to fragment (using bson)
Signed-off-by: Rachel <508861+Ryex@users.noreply.github.com>
This commit is contained in:
@@ -8,62 +8,6 @@ import { IC10EditorUI } from './ui.js';
|
||||
import _ace_ext_langue_tools from "ace-code/src/ext/language_tools";
|
||||
|
||||
|
||||
const demoCode = `# Highlighting Demo
|
||||
# This is a comment
|
||||
|
||||
# Hover a define id anywhere to see it's definition
|
||||
define a_def 10
|
||||
|
||||
# Hover HASH("String")'s to see computed crc32
|
||||
# hover here vvvvvvvvvvvvvvvv
|
||||
define a_hash HASH("This is a String")
|
||||
|
||||
# hover over an alias anywhere in the code
|
||||
# to see it's definition
|
||||
alias a_var r0
|
||||
alias a_device d0
|
||||
|
||||
# instructions have Auto Completion,
|
||||
# numeric logic types are identified on hover
|
||||
s db 12 0
|
||||
# ^^
|
||||
# hover here
|
||||
|
||||
# Enums and their values are Known, Hover them!
|
||||
# vvvvvvvvvvvvvvvvvv
|
||||
move r2 LogicType.Temperature
|
||||
|
||||
# same with constants
|
||||
# vvvv
|
||||
move r3 pinf
|
||||
|
||||
# Labels are known
|
||||
main:
|
||||
l r1 dr15 RatioWater
|
||||
move r2 100000.001
|
||||
|
||||
# Hover Hash Strings of Known prefab names
|
||||
# to get their documentation
|
||||
# vvvvvvvvvvvvvvv
|
||||
move r0 HASH("AccessCardBlack")
|
||||
beqz r1 test
|
||||
|
||||
# -2045627372 is the crc32 hash of a SolarPanel,
|
||||
# hover it to see the documentation!
|
||||
# vvvvvvvvvv
|
||||
move r1 -2045627372
|
||||
jal test
|
||||
move r1 $FF
|
||||
beqz 0 test
|
||||
move r1 %1000
|
||||
yield
|
||||
j main
|
||||
|
||||
test:
|
||||
add r15 r15 1
|
||||
j ra
|
||||
|
||||
`
|
||||
async function setupLspWorker() {
|
||||
// Create a web worker
|
||||
let worker = new Worker(new URL('./lspWorker.js', import.meta.url));
|
||||
@@ -80,8 +24,6 @@ async function setupLspWorker() {
|
||||
function IC10Editor(session_id) {
|
||||
this.mode = new IC10Mode()
|
||||
|
||||
|
||||
|
||||
this.settings = {
|
||||
keyboard: "ace",
|
||||
cursor: "ace",
|
||||
@@ -104,11 +46,35 @@ function IC10Editor(session_id) {
|
||||
this.sessions = {};
|
||||
this.sessions[session_id] = this.editor.getSession();
|
||||
this.active_session = session_id;
|
||||
this.editor.session.setValue(demoCode)
|
||||
this.bindSession(session_id, this.sessions[session_id]);
|
||||
|
||||
this.languageProvider = null;
|
||||
|
||||
this.ui = new IC10EditorUI(this);
|
||||
|
||||
const self = this;
|
||||
|
||||
App.session.onLoad((session) => {
|
||||
const updated_ids = [];
|
||||
for (const id in session.programs) {
|
||||
updated_ids.push(id);
|
||||
self.createOrSetSession(id, session.programs[id]);
|
||||
}
|
||||
for (const id in self.sessions) {
|
||||
if (!updated_ids.includes(id)) {
|
||||
self.destroySession(id);
|
||||
}
|
||||
}
|
||||
})
|
||||
App.session.loadFromFragment();
|
||||
|
||||
}
|
||||
|
||||
IC10Editor.prototype.createOrSetSession = function(session_id, content) {
|
||||
if (!this.sessions.hasOwnProperty(session_id)) {
|
||||
this.newSession(session_id);
|
||||
}
|
||||
this.sessions[session_id].setValue(content);
|
||||
}
|
||||
|
||||
IC10Editor.prototype.newSession = function(session_id) {
|
||||
@@ -116,6 +82,7 @@ IC10Editor.prototype.newSession = function(session_id) {
|
||||
return false;
|
||||
}
|
||||
this.sessions[session_id] = ace.createEditSession("", this.mode);
|
||||
this.bindSession(session_id, this.sessions[session_id]);
|
||||
}
|
||||
|
||||
IC10Editor.prototype.setupLsp = function(lsp_worker) {
|
||||
@@ -136,17 +103,19 @@ IC10Editor.prototype.setupLsp = function(lsp_worker) {
|
||||
|
||||
}
|
||||
|
||||
IC10Editor.prototype.activateSession = function (session_id) {
|
||||
IC10Editor.prototype.activateSession = function(session_id) {
|
||||
if (!this.sessions.hasOwnProperty(session_id)) {
|
||||
return false;
|
||||
}
|
||||
this.editor.setSession(this.sessions[session_id]);
|
||||
let options = this.mode.options ?? {};
|
||||
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
|
||||
if (this.languageProvider !== null) {
|
||||
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IC10Editor.prototype.loadEditorSettings = function () {
|
||||
IC10Editor.prototype.loadEditorSettings = function() {
|
||||
const saved_settings = window.localStorage.getItem("editorSettings");
|
||||
if (saved_settings !== null && saved_settings.length > 0) {
|
||||
try {
|
||||
@@ -159,7 +128,7 @@ IC10Editor.prototype.loadEditorSettings = function () {
|
||||
}
|
||||
}
|
||||
|
||||
IC10Editor.prototype.saveEditorSettings = function () {
|
||||
IC10Editor.prototype.saveEditorSettings = function() {
|
||||
const toSave = JSON.stringify(this.settings);
|
||||
window.localStorage.setItem("editorSettings", toSave);
|
||||
}
|
||||
@@ -171,9 +140,20 @@ IC10Editor.prototype.destroySession = function(session_id) {
|
||||
if (!(Object.keys(this.sessions).length > 1)) {
|
||||
return false;
|
||||
}
|
||||
this.sessions[session_id].destroy();
|
||||
const session = this.sessions[session_id];
|
||||
delete this.sessions[session_id];
|
||||
if (this.active_session = session_id) {
|
||||
this.activateSession(Object.keys(this.sessions)[0]);
|
||||
}
|
||||
session.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
IC10Editor.prototype.bindSession = function(session_id, session) {
|
||||
session.on('change', () => {
|
||||
var val = session.getValue();
|
||||
window.App.session.setProgramCode(session_id, val);
|
||||
});
|
||||
}
|
||||
|
||||
export { IC10Editor, setupLspWorker };
|
||||
|
||||
@@ -56,37 +56,16 @@ function IC10EditorUI(ic10editor) {
|
||||
|
||||
console.log(self.ic10editor.editor.getOption('keyboardHandler'));
|
||||
|
||||
// let sessionChangeTimeout = 0;
|
||||
// editor.getSession().on('change', () => {
|
||||
// if (sessionChangeTimeout) clearTimeout(sessionChangeTimeout);
|
||||
// sessionChangeTimeout = setTimeout(() => {
|
||||
// var val = editor.getSession().getValue();
|
||||
// setDocFragment(val);
|
||||
// sessionChangeTimeout = 0;
|
||||
// }, 1000);
|
||||
// });
|
||||
|
||||
self.ic10editor.editor.setTheme("ace/theme/one_dark");
|
||||
ace.config.loadModule("ace/ext/statusbar", function(module) {
|
||||
const statusBar = new module.StatusBar(self.ic10editor.editor, document.getElementById("statusBar"));
|
||||
statusBar.updateStatus(self.ic10editor.editor);
|
||||
})
|
||||
|
||||
// ace_ext_keybinding_menu.init(editor);
|
||||
// editor.setOption("keyboardHandler", "ace/keyboard/vim");
|
||||
self.ic10editor.editor.setAutoScrollEditorIntoView(true);
|
||||
|
||||
|
||||
|
||||
// getContentFromFragment(editor, demoCode);
|
||||
|
||||
// window.addEventListener('hashchange', (_event) => {
|
||||
// getContentFromFragment(editor, "");
|
||||
// });
|
||||
|
||||
}
|
||||
|
||||
IC10EditorUI.prototype.updateEditorSettings = function () {
|
||||
IC10EditorUI.prototype.updateEditorSettings = function() {
|
||||
const settings = this.ic10editor.settings;
|
||||
const editor = this.ic10editor.editor;
|
||||
if (settings.keyboard === 'ace') {
|
||||
@@ -99,7 +78,7 @@ IC10EditorUI.prototype.updateEditorSettings = function () {
|
||||
editor.setOption('relativeLineNumbers', settings.relativeLineNumbers);
|
||||
}
|
||||
|
||||
IC10EditorUI.prototype.displayEditorSettings = function () {
|
||||
IC10EditorUI.prototype.displayEditorSettings = function() {
|
||||
const settings = this.ic10editor.settings;
|
||||
document.getElementsByName("editorKeybindRadio").forEach((el) => {
|
||||
el.checked = el.value === settings.keyboard;
|
||||
@@ -111,7 +90,7 @@ IC10EditorUI.prototype.displayEditorSettings = function () {
|
||||
document.getElementById("editorSettingsRelativeLineNumbers").checked = settings.relativeLineNumbers;
|
||||
}
|
||||
|
||||
IC10EditorUI.prototype.reCalcEditorSize = function () {
|
||||
IC10EditorUI.prototype.reCalcEditorSize = function() {
|
||||
const editor = this.ic10editor.editor;
|
||||
const navBar = document.getElementById("navBar");
|
||||
const statusBarContainer = document.getElementById("statusBarContainer");
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { init } from "ic10emu_wasm";
|
||||
|
||||
import { IC10Editor, setupLspWorker } from "./editor";
|
||||
import { Session } from './session';
|
||||
|
||||
const App = {
|
||||
editor: null,
|
||||
sessions: [],
|
||||
languageProvider: null,
|
||||
editorSettings: {
|
||||
}
|
||||
session: new Session()
|
||||
};
|
||||
|
||||
window.App = App;
|
||||
|
||||
@@ -1,65 +1,155 @@
|
||||
|
||||
import { BSON } from 'bson';
|
||||
|
||||
async function setDocFragment(content) {
|
||||
const obj = JSON.stringify({ sessions: [{ content }] })
|
||||
const bytes = new TextEncoder().encode(obj);
|
||||
try {
|
||||
const c_bytes = await compress(bytes);
|
||||
const fragment = base64url_encode(c_bytes);
|
||||
window.history.replaceState(null, "", `#${fragment}`);
|
||||
} catch (e) {
|
||||
console.log("Error compressing content fragment:", e);
|
||||
return;
|
||||
const demoCode = `# Highlighting Demo
|
||||
# This is a comment
|
||||
|
||||
# Hover a define id anywhere to see it's definition
|
||||
define a_def 10
|
||||
|
||||
# Hover HASH("String")'s to see computed crc32
|
||||
# hover here vvvvvvvvvvvvvvvv
|
||||
define a_hash HASH("This is a String")
|
||||
|
||||
# hover over an alias anywhere in the code
|
||||
# to see it's definition
|
||||
alias a_var r0
|
||||
alias a_device d0
|
||||
|
||||
# instructions have Auto Completion,
|
||||
# numeric logic types are identified on hover
|
||||
s db 12 0
|
||||
# ^^
|
||||
# hover here
|
||||
|
||||
# Enums and their values are Known, Hover them!
|
||||
# vvvvvvvvvvvvvvvvvv
|
||||
move r2 LogicType.Temperature
|
||||
|
||||
# same with constants
|
||||
# vvvv
|
||||
move r3 pinf
|
||||
|
||||
# Labels are known
|
||||
main:
|
||||
l r1 dr15 RatioWater
|
||||
move r2 100000.001
|
||||
|
||||
# Hover Hash Strings of Known prefab names
|
||||
# to get their documentation
|
||||
# vvvvvvvvvvvvvvv
|
||||
move r0 HASH("AccessCardBlack")
|
||||
beqz r1 test
|
||||
|
||||
# -2045627372 is the crc32 hash of a SolarPanel,
|
||||
# hover it to see the documentation!
|
||||
# vvvvvvvvvv
|
||||
move r1 -2045627372
|
||||
jal test
|
||||
move r1 $FF
|
||||
beqz 0 test
|
||||
move r1 %1000
|
||||
yield
|
||||
j main
|
||||
|
||||
test:
|
||||
add r15 r15 1
|
||||
j ra
|
||||
|
||||
`
|
||||
|
||||
class Session {
|
||||
constructor() {
|
||||
this._programs = {};
|
||||
this._save_timeout = 0;
|
||||
this._onLoadCallbacks = [];
|
||||
this.loadFromFragment();
|
||||
|
||||
const self = this;
|
||||
window.addEventListener('hashchange', (_event) => {
|
||||
self.loadFromFragment();
|
||||
});
|
||||
}
|
||||
|
||||
get programs() {
|
||||
return this._programs;
|
||||
}
|
||||
|
||||
set programs(programs) {
|
||||
Object.assign(this._programs, programs);
|
||||
}
|
||||
|
||||
setProgramCode(id, code) {
|
||||
this._programs[id] = code;
|
||||
this.save();
|
||||
}
|
||||
|
||||
onLoad(callback) {
|
||||
this._onLoadCallbacks.push(callback);
|
||||
}
|
||||
|
||||
_fireOnLoad() {
|
||||
for (const i in this._onLoadCallbacks) {
|
||||
const callback = this._onLoadCallbacks[i];
|
||||
callback(this);
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this._save_timeout) clearTimeout(this._save_timeout);
|
||||
this._save_timeout = setTimeout(() => {
|
||||
this.saveToFragment();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async saveToFragment() {
|
||||
const toSave = { programs: this._programs };
|
||||
const bytes = BSON.serialize(toSave);
|
||||
try {
|
||||
const c_bytes = await compress(bytes);
|
||||
const fragment = base64url_encode(c_bytes);
|
||||
window.history.replaceState(null, "", `#${fragment}`);
|
||||
} catch (e) {
|
||||
console.log("Error compressing content fragment:", e);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async loadFromFragment() {
|
||||
const fragment = window.location.hash.slice(1);
|
||||
if (fragment === "demo") {
|
||||
this._programs = { 0: demoCode };
|
||||
this._fireOnLoad();
|
||||
return;
|
||||
}
|
||||
if (fragment.length > 0) {
|
||||
const c_bytes = base64url_decode(fragment);
|
||||
const bytes = await decompressFragment(c_bytes);
|
||||
if (bytes !== null) {
|
||||
const data = BSON.deserialize(bytes);
|
||||
try {
|
||||
this._programs = Object.assign({}, data.programs);
|
||||
this._fireOnLoad();
|
||||
return;
|
||||
} catch (e) {
|
||||
console.log("Bad session data:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function decompressFragment(c_bytes) {
|
||||
async function decompressFragment(c_bytes) {
|
||||
try {
|
||||
const bytes = await decompress(c_bytes);
|
||||
const content = new TextDecoder().decode(bytes);
|
||||
return content;
|
||||
return bytes;
|
||||
} catch (e) {
|
||||
console.log("Error decompressing content fragment:", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function isJsonContent(content) {
|
||||
try {
|
||||
const obj = JSON.parse(content);
|
||||
return [true, obj];
|
||||
} catch (_) {
|
||||
return [false, null];
|
||||
}
|
||||
}
|
||||
|
||||
async function getContentFromFragment() {
|
||||
const fragment = window.location.hash.slice(1);
|
||||
if (fragment.length > 0) {
|
||||
const c_bytes = base64url_decode(fragment);
|
||||
const data = await decompressFragment(c_bytes);
|
||||
if (data !== null) {
|
||||
const [is_json, session] = isJsonContent(data);
|
||||
if (is_json) {
|
||||
try {
|
||||
const content = session.sessions[0].content
|
||||
editor.getSession().setValue(content);
|
||||
return;
|
||||
} catch (e) {
|
||||
console.log("Bad session data:", e);
|
||||
}
|
||||
} else {
|
||||
editor.getSession().setValue(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
editor.getSession().setValue(default_content);
|
||||
}
|
||||
|
||||
|
||||
async function* streamAsyncIterator(stream) {
|
||||
// Get a lock on the stream
|
||||
const reader = stream.getReader();
|
||||
@@ -122,3 +212,5 @@ async function decompress(bytes) {
|
||||
}
|
||||
return await concatUintArrays(chunks);
|
||||
}
|
||||
|
||||
export { Session };
|
||||
|
||||
Reference in New Issue
Block a user