SourceFile object; moved styles to css/codemirror.css

This commit is contained in:
Steven Hugg 2017-01-15 23:47:12 -05:00
parent 6f09dd9634
commit 0fca237979
4 changed files with 166 additions and 67 deletions

View File

@ -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; }

View File

@ -257,10 +257,11 @@ canvas.pixelated {
<script src="bootstrap/js/bootstrap-tour.min.js"></script>
<script src="codemirror/lib/codemirror.js"></script>
<script src="codemirror/mode/clike/clike.js"></script>
<script src="codemirror/mode/6502/6502.js"></script>
<script src="codemirror/mode/z80/z80.js"></script>
<link rel="stylesheet" href="css/codemirror.css">
<link rel="stylesheet" href="codemirror/theme/mbo.css">
<link rel="stylesheet" href="codemirror/theme/cobalt.css">
<script src="codemirror/addon/edit/matchbrackets.js"></script>
<script src="codemirror/addon/search/search.js"></script>
<script src="codemirror/addon/search/searchcursor.js"></script>
<script src="codemirror/addon/search/jumpToLine.js"></script>

119
src/ui.js
View File

@ -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<gutters.length; i++) {
var g = gutters[i];
if (g[0]) disasmview.setGutterMarker(i, "gutter-offset", hex(g[0]));
}
*/
disasmview.setCursor(selline, 0);
// TODO: need to refresh when viewport changes
var scrinfo = disasmview.getScrollInfo();
disasmview.scrollTo(0, (scrinfo.height-scrinfo.clientHeight)/2);
jumpToLine(disasmview, selline);
}
}

View File

@ -21,7 +21,6 @@ var document = noop();
document.documentElement = noop();
document.documentElement.style = noop();
// load filesystems for CC65 and others asynchronously
var fsMeta, fsBlob;
{
@ -210,7 +209,6 @@ function assembleDASM(code) {
var alst = FS.readFile("a.lst", {'encoding':'utf8'});
var listing = parseDASMListing(alst, unresolved);
return {
exitstatus:Module.EXITSTATUS,
output:aout.slice(2),
lines:listing.lines,
errors:listing.errors,
@ -251,7 +249,6 @@ function assembleACME(code) {
var asym = FS.readFile("a.sym", {'encoding':'utf8'});
var listing = parseDASMListing(alst, {}); // TODO
return {
exitstatus:Module.EXITSTATUS,
output:aout,
lines:listing.lines,
errors:listing.errors,
@ -369,7 +366,6 @@ function assemblelinkCA65(code, platform, warnings) {
var mapout = FS.readFile("main.map", {encoding:'utf8'});
var listing = parseCA65Listing(lstout, mapout);
return {
exitstatus:LD65.EXITSTATUS,
output:aout.slice(4),
lines:listing.lines,
errors:listing.errors,
@ -412,7 +408,7 @@ function compileCC65(code, platform) {
}
}
function assembleZ80ASM(code, platform, ccompile) {
function assembleZ80ASM(code, platform) {
load("z80asm");
var origin = 0; // TODO: configurable
var Module = z80asm({
@ -454,11 +450,10 @@ l_main00101 = 0003, L: test
var asmlines = parseListing(alst, /^(\d+)\s+([0-9A-F]+)\s+([0-9A-F][0-9A-F ]*[0-9A-F])\s+/i, 1, 2, 3, 4);
var srclines = parseListing(alst, /^(\d+)\s+([0-9A-F]+)\s+;[(]null[)]:(\d+)/i, 3, 2, 1);
return {
exitstatus:Module.EXITSTATUS,
output:aout,
errors:[],
lines:ccompile ? srclines : asmlines,
listing:ccompile ? asmlines : null,
lines:asmlines,
srclines:srclines,
intermediate:{listing:alst, mapfile:amap},
};
} catch (e) {
@ -504,7 +499,7 @@ function parseIHX(ihx, code_start, code_size) {
}
}
function assemblelinkSDASZ80(code, platform, ccompile) {
function assemblelinkSDASZ80(code, platform) {
load("sdasz80");
load("sdldz80");
var objout, lstout, symout;
@ -538,7 +533,7 @@ function assemblelinkSDASZ80(code, platform, ccompile) {
}
objout = FS.readFile("main.rel", {encoding:'utf8'});
lstout = FS.readFile("main.lst", {encoding:'utf8'});
symout = FS.readFile("main.sym", {encoding:'utf8'});
//symout = FS.readFile("main.sym", {encoding:'utf8'});
}{
var LDZ80 = sdldz80({
noInitialRun:true,
@ -557,19 +552,26 @@ function assemblelinkSDASZ80(code, platform, ccompile) {
'main.rel']);
var hexout = FS.readFile("main.ihx", {encoding:'utf8'});
var mapout = FS.readFile("main.noi", {encoding:'utf8'});
var dbgout = FS.readFile("main.cdb", {encoding:'utf8'});
//var dbgout = FS.readFile("main.cdb", {encoding:'utf8'});
// 0000 21 02 00 [10] 52 ld hl, #2
// TODO: offset by start address?
var asmlines = parseListing(lstout, /^\s*([0-9A-F]+)\s+([0-9A-F][0-9A-F r]*[0-9A-F])\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 4, 1, 2, 5, 3);
var srclines = parseSourceLines(lstout, /^\s+\d+ ;\(null\):(\d+):/i, /^\s*([0-9A-F]{4})/i);
console.log(lstout); // TODO
// parse symbol map
var symbolmap = {};
for (var s of mapout.split("\n")) {
var toks = s.split(" ");
if (s[0] == 'DEF') {
symbolmap[s[1]] = s[2];
}
}
return {
exitstatus:LDZ80.EXITSTATUS,
output:parseIHX(hexout, params.code_start, params.code_size),
lines:ccompile ? srclines : asmlines,
listing:ccompile ? asmlines : null,
lines:asmlines,
srclines:srclines,
errors:msvc_errors, // TODO?
intermediate:{listing:lstout, map:mapout, symbols:symout, debug:dbgout},
symbolmap:symbolmap,
intermediate:{listing:lstout},
};
}
}
@ -589,7 +591,7 @@ function compileSDCC(code, platform) {
setupFS(FS);
//FS.writeFile("main.c", code, {encoding:'utf8'});
msvc_errors = [];
SDCC.callMain(['--vc', '--c1mode', '--std-sdcc99', '-mz80',
SDCC.callMain(['--vc', '--c1mode', '--std-sdcc99', '-mz80', '-Wall',
'--debug',
//'--asm=z80asm',
'--fomit-frame-pointer', '--opt-code-speed',
@ -599,8 +601,12 @@ function compileSDCC(code, platform) {
} catch(e) {
return {errors:msvc_errors};
}
var warnings = msvc_errors;
var result = assemblelinkSDASZ80(asmout, platform, true);
result.errors = result.errors.concat(msvc_errors);
result.asmlines = result.lines;
result.lines = result.srclines;
result.srclines = null;
result.errors = result.errors.concat(warnings);
return result;
}