"use strict"; // 8bitworkshop IDE user interface // make sure VCS doesn't start if (window.Javatari) Javatari.AUTO_START = false; var PRESETS; // presets array var platform_id; // platform ID string var platform; // platform object var toolbar = $("#controls_top"); var current_project; // current CodeProject object var projectWindows; // window manager // TODO: codemirror multiplex support? var TOOL_TO_SOURCE_STYLE = { 'dasm': '6502', 'acme': '6502', 'cc65': 'text/x-csrc', 'ca65': '6502', 'z80asm': 'z80', 'sdasz80': 'z80', 'sdcc': 'text/x-csrc', 'verilator': 'verilog', 'jsasm': 'z80' } function newWorker() { return new Worker("./src/worker/workermain.js"); } var userPaused; // did user explicitly pause? var current_output; // current ROM var current_preset_entry; // current preset object (if selected) var main_file_id; // main file ID var symbolmap; // symbol map var addr2symbol; // address to symbol name map var compparams; // received build params from worker var store; // persistent store var lastDebugInfo; // last debug info (CPU text) var lastDebugState; // last debug state (object) function inspectVariable(ed, name) { var val; if (platform.inspect) { platform.inspect(name); } } function getCurrentPresetTitle() { if (!current_preset_entry) return "ROM"; else return current_preset_entry.title || current_preset_entry.name || "ROM"; } function setLastPreset(id) { if (platform_id != 'base_z80') { // TODO localStorage.setItem("__lastplatform", platform_id); localStorage.setItem("__lastid_"+platform_id, id); } } function initProject() { current_project = new CodeProject(newWorker(), platform_id, platform, store); projectWindows = new ProjectWindows($("#workspace")[0], current_project); current_project.callbackGetRemote = $.get; current_project.callbackBuildResult = function(result) { setCompileOutput(result); refreshWindowList(); }; current_project.callbackBuildStatus = function(busy) { if (busy) { toolbar.addClass("is-busy"); } else { toolbar.removeClass("is-busy"); toolbar.removeClass("has-errors"); // may be added in next callback projectWindows.setErrors(null); } $('#compile_spinner').css('visibility', busy ? 'visible' : 'hidden'); }; } function refreshWindowList() { var ul = $("#windowMenuList").empty(); var separate = false; function addWindowItem(id, name, createfn) { if (separate) { ul.append(document.createElement("hr")); separate = false; } var li = document.createElement("li"); var a = document.createElement("a"); a.setAttribute("class", "dropdown-item"); a.setAttribute("href", "#"); a.appendChild(document.createTextNode(name)); li.appendChild(a); ul.append(li); if (createfn) { projectWindows.setCreateFunc(id, createfn); $(a).click(function() { projectWindows.createOrShow(id); }); } } function loadEditor(path) { var tool = platform.getToolForFilename(path); var mode = tool && TOOL_TO_SOURCE_STYLE[tool]; return new SourceEditor(path, mode, current_project.getFile(path)); } // add main file editor var id = main_file_id; addWindowItem(id, getFilenameForPath(id), loadEditor); // add other source files separate = true; current_project.iterateFiles(function(id, text) { if (id != main_file_id) addWindowItem(id, getFilenameForPath(id), loadEditor); }); // add listings var listings = current_project.getListings(); if (listings) { for (var lstfn in listings) { var lst = listings[lstfn]; if (lst.assemblyfile) { addWindowItem(lstfn, getFilenameForPath(lstfn), function(path) { return new ListingView(lst.assemblyfile); }); } } } // add other tools separate = true; if (platform.disassemble) { addWindowItem("#disasm", "Disassembly", function() { return new DisassemblerView(); }); } if (platform.readAddress && platform_id != 'vcs') { addWindowItem("#memory", "Memory Browser", function() { return new MemoryView(); }); } } // can pass integer or string id function loadProject(preset_id) { var index = parseInt(preset_id+""); // might fail -1 for (var i=0; i= 0) { // load the preset current_preset_entry = PRESETS[index]; preset_id = current_preset_entry.id; } // set current file ID main_file_id = preset_id; setLastPreset(preset_id); current_project.mainPath = preset_id; // load files from storage or web URLs current_project.loadFiles([preset_id], function(err, result) { if (err) { alert(err); } else if (result && result.length) { // we need this to build create functions for the editor (TODO?) refreshWindowList(); // show main file projectWindows.createOrShow(preset_id); } }); } function reloadPresetNamed(id) { qs['platform'] = platform_id; qs['file'] = id; gotoNewLocation(); } function getSkeletonFile(fileid, callback) { var ext = platform.getToolForFilename(fileid); $.get( "presets/"+platform_id+"/skeleton."+ext, function( text ) { callback(null, text); }, 'text') .fail(function() { alert("Could not load skeleton for " + platform_id + "/" + ext + "; using blank file"); callback(null, '\n'); }); } function _createNewFile(e) { var filename = prompt("Create New File", "newfile" + platform.getDefaultExtension()); if (filename && filename.length) { if (filename.indexOf(".") < 0) { filename += platform.getDefaultExtension(); } var path = "local/" + filename; getSkeletonFile(path, function(err, result) { if (result) { store.setItem(path, result, function(err, result) { if (err) alert(err+""); if (result != null) reloadPresetNamed("local/" + filename); }); } }); } return true; } function _uploadNewFile(e) { $("#uploadFileElem").click(); } function handleFileUpload(files) { console.log(files); var index = 0; function uploadNextFile() { var f = files[index++]; if (!f) { console.log("Done uploading"); gotoNewLocation(); } else { var path = "local/" + f.name; var reader = new FileReader(); reader.onload = function(e) { var data = e.target.result; store.setItem(path, data, function(err, result) { if (err) console.log(err); else { console.log("Uploaded " + path + " " + data.length + " bytes"); if (index == 1) qs['file'] = path; uploadNextFile(); } }); } reader.readAsText(f); } } if (files) uploadNextFile(); } function getCurrentFilename() { var toks = main_file_id.split("/"); return toks[toks.length-1]; } function _shareFile(e) { if (current_output == null) { // TODO alert("Please fix errors before sharing."); return true; } var text = projectWindows.getCurrentText(); if (!text) return false; var github = new Octokat(); var files = {}; files[getCurrentFilename()] = {"content": text}; var gistdata = { "description": '8bitworkshop.com {"platform":"' + platform_id + '"}', "public": true, "files": files }; var gist = github.gists.create(gistdata).done(function(val) { var url = "http://8bitworkshop.com/?sharekey=" + val.id; window.prompt("Copy link to clipboard (Ctrl+C, Enter)", url); }).fail(function(err) { alert("Error sharing file: " + err.message); }); return true; } function _resetPreset(e) { if (!current_preset_entry) { alert("Can only reset built-in file examples.") } else if (confirm("Reset '" + current_preset_entry.name + "' to default?")) { qs['reset'] = '1'; gotoNewLocation(); } return true; } function _downloadROMImage(e) { if (current_output == null) { // TODO alert("Please fix errors before downloading ROM."); return true; } var blob = new Blob([current_output], {type: "application/octet-stream"}); saveAs(blob, getCurrentFilename()+".rom"); } function _downloadSourceFile(e) { var text = projectWindows.getCurrentText(); if (!text) return false; var blob = new Blob([text], {type: "text/plain;charset=utf-8"}); saveAs(blob, getCurrentFilename()); } function populateExamples(sel) { // make sure to use callback so it follows other sections store.length(function(err, len) { sel.append($("