diff --git a/css/codemirror.css b/css/codemirror.css
index df7de562..f49af69d 100644
--- a/css/codemirror.css
+++ b/css/codemirror.css
@@ -347,3 +347,70 @@ div.CodeMirror-dragcursors {
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }
+
+/****************************************************************/
+/* Based on mbonaci's Brackets mbo theme */
+/* https://github.com/mbonaci/global/blob/master/Mbo.tmTheme */
+/* Create your own: http://tmtheme-editor.herokuapp.com */
+/****************************************************************/
+
+.cm-s-mbo.CodeMirror { background: #2c2c2c; color: #ffffec; }
+.cm-s-mbo div.CodeMirror-selected { background: #716C62; }
+.cm-s-mbo .CodeMirror-line::selection, .cm-s-mbo .CodeMirror-line > span::selection, .cm-s-mbo .CodeMirror-line > span > span::selection { background: rgba(113, 108, 98, .99); }
+.cm-s-mbo .CodeMirror-line::-moz-selection, .cm-s-mbo .CodeMirror-line > span::-moz-selection, .cm-s-mbo .CodeMirror-line > span > span::-moz-selection { background: rgba(113, 108, 98, .99); }
+.cm-s-mbo .CodeMirror-gutters { background: #4e4e4e; border-right: 0px; }
+.cm-s-mbo .CodeMirror-guttermarker { color: white; }
+.cm-s-mbo .CodeMirror-guttermarker-subtle { color: grey; }
+.cm-s-mbo .CodeMirror-linenumber { color: #dadada; }
+.cm-s-mbo .CodeMirror-cursor { border-left: 1px solid #ffffec; }
+
+.cm-s-mbo span.cm-comment { color: #95958a; }
+.cm-s-mbo span.cm-atom { color: #00a8c6; }
+.cm-s-mbo span.cm-number { color: #00a8c6; }
+
+.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute { color: #9ddfe9; }
+.cm-s-mbo span.cm-keyword { color: #ffb928; }
+.cm-s-mbo span.cm-string { color: #ffcf6c; }
+.cm-s-mbo span.cm-string.cm-property { color: #ffffec; }
+
+.cm-s-mbo span.cm-variable { color: #ffffec; }
+.cm-s-mbo span.cm-variable-2 { color: #00a8c6; }
+.cm-s-mbo span.cm-variable-3 { color: #ffb928; }
+.cm-s-mbo span.cm-def { color: #ffff88; }
+.cm-s-mbo span.cm-bracket { color: #fffffc; font-weight: bold; }
+.cm-s-mbo span.cm-tag { color: #9ddfe9; }
+.cm-s-mbo span.cm-link { color: #f54b07; }
+.cm-s-mbo span.cm-error { border-bottom: #636363; color: #ffffec; }
+.cm-s-mbo span.cm-qualifier { color: #ffffec; }
+
+.cm-s-mbo .CodeMirror-activeline-background { background: #494b41; }
+.cm-s-mbo .CodeMirror-matchingbracket { color: #33ff33 !important; }
+.cm-s-mbo .CodeMirror-matchingtag { background: rgba(255, 255, 255, .37); }
+
+/****************************************************************/
+
+.cm-s-cobalt.CodeMirror { background: #002240; color: white; }
+.cm-s-cobalt div.CodeMirror-selected { background: #b36539; }
+.cm-s-cobalt .CodeMirror-line::selection, .cm-s-cobalt .CodeMirror-line > span::selection, .cm-s-cobalt .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); }
+.cm-s-cobalt .CodeMirror-line::-moz-selection, .cm-s-cobalt .CodeMirror-line > span::-moz-selection, .cm-s-cobalt .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); }
+.cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }
+.cm-s-cobalt .CodeMirror-guttermarker { color: #ffee80; }
+.cm-s-cobalt .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
+.cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; }
+.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white; }
+
+.cm-s-cobalt span.cm-comment { color: #ccc; }
+.cm-s-cobalt span.cm-atom { color: #845dc4; }
+.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; }
+.cm-s-cobalt span.cm-keyword { color: #ffee80; }
+.cm-s-cobalt span.cm-string { color: #3ad900; }
+.cm-s-cobalt span.cm-meta { color: #ff9d00; }
+.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }
+.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; }
+.cm-s-cobalt span.cm-bracket { color: #d8d8d8; }
+.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }
+.cm-s-cobalt span.cm-link { color: #845dc4; }
+.cm-s-cobalt span.cm-error { color: #9d1e15; }
+
+.cm-s-cobalt .CodeMirror-activeline-background { background: #003399; }
+.cm-s-cobalt .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; }
diff --git a/index.html b/index.html
index b8a4f792..bf283dc9 100644
--- a/index.html
+++ b/index.html
@@ -257,10 +257,11 @@ canvas.pixelated {
+
+
-
-
+
diff --git a/src/ui.js b/src/ui.js
index 3a99936e..8abbc776 100644
--- a/src/ui.js
+++ b/src/ui.js
@@ -61,31 +61,64 @@ var FileStore = function(storage, prefix) {
}
}
+var SourceFile = function(lines, text) {
+ lines = lines || [];
+ this.text = text;
+ this.offset2line = {};
+ this.line2offset = {};
+ for (var info of lines) {
+ if (info.offset >= 0) {
+ this.offset2line[info.offset] = info.line;
+ this.line2offset[info.line] = info.offset;
+ }
+ }
+ this.findLineForOffset = function(PC) {
+ if (this.offset2line) {
+ for (var i=0; i<256; i++) {
+ var line = this.offset2line[PC];
+ if (line >= 0) {
+ return line;
+ }
+ PC--;
+ }
+ }
+ return 0;
+ }
+}
+
+var TOOL_TO_SOURCE_STYLE = {
+ 'dasm': '6502',
+ 'acme': '6502',
+ 'cc65': 'text/x-csrc',
+ 'ca65': '6502',
+ 'z80asm': 'z80',
+ 'sdasz80': 'z80',
+ 'sdcc': 'text/x-csrc',
+}
+
var worker = new Worker("./src/worker/workermain.js");
var current_output = null;
var current_preset_index = -1; // TODO: use URL
var current_preset_id = null;
-var offset2line = null;
-var line2offset = null;
+var assemblyfile = null;
+var sourcefile = null;
var pcvisits;
var trace_pending_at_pc;
var store;
-var CODE = 'code1';
var editor = CodeMirror(document.getElementById('editor'), {
- mode: '6502',
theme: 'mbo',
lineNumbers: true,
+ matchBrackets: true,
tabSize: 8,
gutters: ["CodeMirror-linenumbers", "gutter-offset", "gutter-bytes", "gutter-clock", "gutter-info"],
});
var disasmview = CodeMirror(document.getElementById('disassembly'), {
- mode: '6502',
+ mode: 'z80',
theme: 'cobalt',
tabSize: 8,
readOnly: true,
- styleActiveLine: true,
- gutters: ["gutter-offset", "gutter-bytes", "gutter-clock", "gutter-info"],
+ styleActiveLine: true
});
editor.on('changes', function(ed, changeobj) {
@@ -111,10 +144,13 @@ function updatePreset(current_preset_id, text) {
}
}
-function loadCode(text) {
+function loadCode(text, fileid) {
editor.setValue(text);
current_output = null;
setCode(text);
+ setLastPreset(fileid);
+ var tool = platform.getToolForFilename(fileid);
+ editor.setOption("mode", tool && TOOL_TO_SOURCE_STYLE[tool]);
}
function loadFile(fileid, filename, index) {
@@ -122,8 +158,7 @@ function loadFile(fileid, filename, index) {
current_preset_index = index;
var text = store.loadFile(fileid)|| "";
if (text) {
- loadCode(text);
- setLastPreset(fileid);
+ loadCode(text, fileid);
} else if (!text && index >= 0) {
filename += ".a";
console.log("Loading preset", fileid, filename, index, PRESETS[index]);
@@ -131,14 +166,12 @@ function loadFile(fileid, filename, index) {
console.log("Fetching", filename);
$.get( filename, function( text ) {
console.log("GET",text.length,'bytes');
- loadCode(text);
- setLastPreset(fileid);
+ loadCode(text, fileid);
}, 'text');
}
} else {
$.get( "presets/"+platform_id+"/skeleton.a", function( text ) {
- loadCode(text);
- setLastPreset(fileid);
+ loadCode(text, fileid);
updatePreset(fileid, text);
}, 'text');
}
@@ -294,6 +327,10 @@ function arrayCompare(a,b) {
worker.onmessage = function(e) {
// errors?
var toolbar = $("#controls_top");
+ sourcefile = new SourceFile(e.data.lines);
+ if (e.data.asmlines) {
+ assemblyfile = new SourceFile(e.data.asmlines, e.data.intermediate.listing);
+ }
if (e.data.errors.length > 0) {
toolbar.addClass("has-errors");
editor.clearGutter("gutter-info");
@@ -333,14 +370,10 @@ worker.onmessage = function(e) {
editor.clearGutter("gutter-bytes");
editor.clearGutter("gutter-offset");
editor.clearGutter("gutter-clock");
- offset2line = {};
- line2offset = {};
for (var info of e.data.lines) {
if (info.offset >= 0) {
var textel = document.createTextNode(hex(info.offset,4));
editor.setGutterMarker(info.line-1, "gutter-offset", textel);
- offset2line[info.offset] = info.line;
- line2offset[info.line] = info.offset;
}
if (info.insns) {
var insnstr = info.insns.length > 8 ? ("...") : info.insns;
@@ -363,19 +396,6 @@ worker.onmessage = function(e) {
trace_pending_at_pc = null;
}
-function findLineForOffset(PC) {
- if (offset2line) {
- for (var i=0; i<256; i++) {
- var line = offset2line[PC];
- if (line >= 0) {
- return line;
- }
- PC--;
- }
- }
- return 0;
-}
-
function setCurrentLine(line) {
editor.setSelection({line:line,ch:0}, {line:line-1,ch:0}, {scroll:true});
}
@@ -437,7 +457,7 @@ function setupBreakpoint() {
platform.setupDebug(function(state) {
lastDebugState = state;
var PC = state.c.PC;
- var line = findLineForOffset(PC);
+ var line = sourcefile.findLineForOffset(PC);
if (line >= 0) {
console.log("BREAKPOINT", hex(PC), line);
setCurrentLine(line);
@@ -477,7 +497,7 @@ function getCurrentLine() {
function runToCursor() {
setupBreakpoint();
- var line = getCurrentLine();
+ var line = sourcefile.getCurrentLine();
var pc = line2offset[line];
if (pc >= 0) {
console.log("Run to", line, pc.toString(16));
@@ -691,16 +711,29 @@ function showLoopTimingForCurrentLine() {
}
*/
+function jumpToLine(ed, i) {
+ var t = ed.charCoords({line: i, ch: 0}, "local").top;
+ var middleHeight = ed.getScrollerElement().offsetHeight / 2;
+ ed.scrollTo(null, t - middleHeight - 5);
+}
+
function updateDisassembly() {
var div = $("#disassembly");
if (div.is(':visible')) {
- disasmview.clearGutter("gutter-info");
- disasmview.clearGutter("gutter-bytes");
- disasmview.clearGutter("gutter-offset");
- disasmview.clearGutter("gutter-clock");
var state = lastDebugState || platform.saveState();
var mem = state.b;
var pc = state.c.PC;
+ if (assemblyfile && assemblyfile.text) {
+ disasmview.setValue(assemblyfile.text);
+ if (platform.getDebugCallback()) {
+ var lineno = assemblyfile.findLineForOffset(pc);
+ if (lineno) {
+ disasmview.setCursor(lineno-1, 0);
+ jumpToLine(disasmview, lineno-1);
+ }
+ }
+ return;
+ }
var gutters = [];
var selline = 0;
// TODO: not perfect disassembler
@@ -711,7 +744,7 @@ function updateDisassembly() {
var disasm = platform.disassemble(mem, start, end, pcvisits);
var s = "";
for (a in disasm) {
- var srclinenum = offset2line[a];
+ var srclinenum = sourcefile.offset2line[a];
if (srclinenum) {
var srcline = editor.getLine(srclinenum-1);
if (srcline && srcline.trim().length) {
@@ -728,16 +761,8 @@ function updateDisassembly() {
}
var text = disassemble(pc-96, pc) + disassemble(pc, pc+96);
disasmview.setValue(text);
- /*
- for (var i=0; i