Browse Source

First stab at using monaco. Lots TODO

dev/git-series/gccdum
Matt Godbolt 6 years ago
parent
commit
d3017c617d
  1. 16
      .idea/libraries/Cargo__rustfilt_.xml
  2. 4
      bower.json
  3. 67
      static/asm-mode.js
  4. 28
      static/colour.js
  5. 49
      static/compiler.js
  6. 84
      static/editor.js
  7. 1
      static/explorer.css
  8. 4
      static/index.html
  9. 8
      static/main.js
  10. 30
      static/monaco.js

16
.idea/libraries/Cargo__rustfilt_.xml

@ -1,19 +1,19 @@
<component name="libraryTable">
<library name="Cargo &lt;rustfilt&gt;">
<CLASSES>
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-syntax-0.3.9" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/memchr-0.1.11" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/aho-corasick-0.5.3" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-0.1.80" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/kernel32-sys-0.2.2" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/rustc-demangle-0.1.3" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-0.2.2" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/utf8-ranges-0.1.3" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/winapi-build-0.1.1" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/winapi-0.2.8" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/thread-id-2.0.0" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/aho-corasick-0.5.3" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/utf8-ranges-0.1.3" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/winapi-0.2.8" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/winapi-build-0.1.1" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-syntax-0.3.9" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/memchr-0.1.11" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/kernel32-sys-0.2.2" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.18" />
<root url="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-0.2.2" />
</CLASSES>
<JAVADOC />
<SOURCES />

4
bower.json

@ -16,7 +16,6 @@
"tests"
],
"dependencies": {
"codemirror": "^5.19.0",
"requirejs": "^2.3.2",
"underscore": "^1.8.3",
"golden-layout": "^1.5.6",
@ -28,6 +27,7 @@
"clipboard": "^1.5.12",
"raven-js": "^3.7.0",
"es6-promise": "^4.0.5",
"lru-cache": "2.7.3"
"lru-cache": "2.7.3",
"monaco-editor": "*"
}
}

67
static/asm-mode.js

@ -24,70 +24,5 @@
define(function (require) {
"use strict";
var CodeMirror = require('codemirror');
CodeMirror.defineMode("asm", function () {
function tokenString(quote) {
return function (stream) {
var escaped = false, next, end = false;
while ((next = stream.next()) !== null) {
if (next == quote && !escaped) {
end = true;
break;
}
escaped = !escaped && next == "\\";
}
return "string";
};
}
var x86_32regName = /\b[re]?(ax|bx|cx|dx|si|di|bp|ip|sp)\b/;
var x86_64regName = /r[\d]+[d]?/;
var x86_xregName = /[xy]mm\d+/;
var x86_keywords = /PTR|BYTE|[DQ]?WORD|XMMWORD|YMMWORD/;
var labelName = /\.L\w+/;
return {
token: function (stream) {
if (stream.match(/\/\*([^*]|[*][^\/])*\**\//)) {
return "comment";
}
if (stream.match(/^.+:$/)) {
return "variable-2";
}
if (stream.sol() && stream.match(/^\s*\.\w+/)) {
return "header";
}
if (stream.sol() && stream.match(/^\s+\w+/)) {
return "keyword";
}
if (stream.eatSpace()) return null;
if (stream.match(x86_32regName) || stream.match(x86_64regName) || stream.match(x86_xregName)) {
return "variable-3";
}
if (stream.match(x86_keywords)) return "keyword";
if (stream.match(labelName)) return "variable-2";
var ch = stream.next();
if (ch == '"' || ch == "'") {
return tokenString(ch)(stream);
}
if (/[\[\]{}\(\),;\:]/.test(ch)) return null;
if (/[\d$]/.test(ch) || (ch == '-' && stream.peek().match(/[0-9]/))) {
stream.eatWhile(/[\w\.]/);
return "number";
}
if (ch == '%') {
stream.eatWhile(/\w+/);
return "variable-3";
}
if (ch == '#') {
stream.eatWhile(/.*/);
return "comment";
}
stream.eatWhile(/[^\s]*/);
return "word";
}
};
});
CodeMirror.defineMIME("text/x-asm", "asm");
return;
});

28
static/colour.js

@ -27,27 +27,25 @@ define(function (require) {
"use strict";
var _ = require('underscore');
var monaco = require('monaco');
var NumRainbowColours = 12;
function clearBackground(editor) {
for (var i = 0; i < editor.lineCount(); ++i) {
editor.removeLineClass(i, "background", null);
}
}
function applyColours(editor, colours) {
editor.operation(function () {
clearBackground(editor);
_.each(colours, function (ordinal, line) {
editor.addLineClass(parseInt(line),
"background", "rainbow-" + (ordinal % NumRainbowColours));
});
function applyColours(editor, colours, prevDecorations) {
var newDecorations = _.map(colours, function (ordinal, line) {
line = parseInt(line) + 1;
return {
range: new monaco.Range(line, 1, line, 1),
options: {
isWholeLine: true,
className: "rainbow-" + (ordinal % NumRainbowColours)
}
};
});
return editor.deltaDecorations(prevDecorations, newDecorations);
}
return {
applyColours: applyColours,
clearBackground: clearBackground
applyColours: applyColours
};
});

49
static/compiler.js

@ -25,7 +25,6 @@
define(function (require) {
"use strict";
var CodeMirror = require('codemirror');
var $ = require('jquery');
var _ = require('underscore');
var ga = require('analytics').ga;
@ -35,8 +34,8 @@ define(function (require) {
var Promise = require('es6-promise').Promise;
var Components = require('components');
var LruCache = require('lru-cache');
var monaco = require('monaco');
require('asm-mode');
require('selectize');
var options = require('options');
@ -63,6 +62,7 @@ define(function (require) {
this.filters = new Toggles(this.domRoot.find(".filters"), state.filters);
this.source = "";
this.assembly = [];
this.colours = [];
this.lastResult = null;
this.pendingRequestSentAt = 0;
this.nextRequest = null;
@ -88,12 +88,9 @@ define(function (require) {
// Hide the binary option if the global options has it disabled.
this.domRoot.find("[data-bind='binary']").toggle(options.supportsBinary);
this.outputEditor = CodeMirror.fromTextArea(this.domRoot.find("textarea")[0], {
lineNumbers: true,
mode: "text/x-asm",
readOnly: true,
gutters: ['CodeMirror-linenumbers'],
lineWrapping: true
// TODO: everything here
this.outputEditor = monaco.editor.create(this.domRoot.find(".monaco-placeholder")[0], {
readOnly: true
});
this.fontScale = new FontScale(this.domRoot, state);
@ -109,7 +106,7 @@ define(function (require) {
self.eventHub.emit('compilerClose', self.id);
}, this);
container.on('resize', this.resize, this);
container.on('shown', this.refresh, this);
container.on('shown', this.resize, this);
container.on('open', function () {
self.eventHub.emit('compilerOpen', self.id);
self.updateFontScale();
@ -150,9 +147,6 @@ define(function (require) {
this.saveState();
}
Compiler.prototype.refresh = function () {
this.outputEditor.refresh();
};
// TODO: need to call resize if either .top-bar or .bottom-bar resizes, which needs some work.
// Issue manifests if you make a window where one compiler is small enough that the buttons spill onto two lines:
@ -160,8 +154,10 @@ define(function (require) {
Compiler.prototype.resize = function () {
var topBarHeight = this.domRoot.find(".top-bar").outerHeight(true);
var bottomBarHeight = this.domRoot.find(".bottom-bar").outerHeight(true);
this.outputEditor.setSize(this.domRoot.width(), this.domRoot.height() - topBarHeight - bottomBarHeight);
this.refresh();
this.outputEditor.layout({
width: this.domRoot.width(),
height: this.domRoot.height() - topBarHeight - bottomBarHeight
});
};
// Gets the filters that will actually be used (accounting for issues with binary
@ -235,8 +231,8 @@ define(function (require) {
Compiler.prototype.setAssembly = function (assembly) {
this.assembly = assembly;
this.outputEditor.setValue(_.pluck(assembly, 'text').join("\n"));
this.outputEditor.getModel().setValue(_.pluck(assembly, 'text').join("\n"));
return;
var addrToAddrDiv = {};
_.each(this.assembly, _.bind(function (obj, line) {
var address = obj.address ? obj.address.toString(16) : "";
@ -308,16 +304,15 @@ define(function (require) {
timingVar: request.compiler,
timingValue: timeTaken
});
this.outputEditor.operation(_.bind(function () {
this.setAssembly(result.asm || fakeAsm("<No output>"));
if (request.filters.binary) {
this.outputEditor.setOption('lineNumbers', false);
this.outputEditor.setOption('gutters', ['address', 'opcodes']);
} else {
this.outputEditor.setOption('lineNumbers', true);
this.outputEditor.setOption('gutters', ['CodeMirror-linenumbers']);
}
}, this));
this.setAssembly(result.asm || fakeAsm("<No output>"));
// TODO
// if (request.filters.binary) {
// this.outputEditor.setOption('lineNumbers', false);
// this.outputEditor.setOption('gutters', ['address', 'opcodes']);
// } else {
// this.outputEditor.setOption('lineNumbers', true);
// this.outputEditor.setOption('gutters', ['CodeMirror-linenumbers']);
// }
var status = this.domRoot.find(".status");
var allText = _.pluck((result.stdout || []).concat(result.stderr | []), 'text').join("\n");
var failed = result.code !== 0;
@ -444,7 +439,7 @@ define(function (require) {
_.each(this.assembly, function (x, index) {
if (x.source) asmColours[index] = colours[x.source - 1];
});
colour.applyColours(this.outputEditor, asmColours);
this.colours = colour.applyColours(this.outputEditor, asmColours, this.colours);
}
};

84
static/editor.js

@ -25,7 +25,6 @@
define(function (require) {
"use strict";
var CodeMirror = require('codemirror');
var _ = require('underscore');
var $ = require('jquery');
var colour = require('colour');
@ -34,12 +33,7 @@ define(function (require) {
var FontScale = require('fontscale');
var Sharing = require('sharing');
var Components = require('components');
require('codemirror/mode/clike/clike');
require('codemirror/mode/d/d');
require('codemirror/mode/go/go');
require('codemirror/mode/rust/rust');
require('codemirror/addon/comment/comment');
var monaco = require('monaco');
var loadSave = new loadSaveLib.LoadSave();
@ -54,18 +48,19 @@ define(function (require) {
this.widgetsByCompiler = {};
this.asmByCompiler = {};
this.busyCompilers = {};
this.colours = [];
this.options = new Toggles(this.domRoot.find('.options'), state.options);
this.options.on('change', _.bind(this.onOptionsChange, this));
var cmMode;
switch (lang.toLowerCase()) {
default:
cmMode = "text/x-c++src";
cmMode = "cpp";
break;
case "c":
cmMode = "text/x-c";
cmMode = "cpp";
break;
case "rust":
case "rust": // TODO
cmMode = "text/x-rustsrc";
break;
case "d":
@ -76,31 +71,24 @@ define(function (require) {
break;
}
this.editor = CodeMirror.fromTextArea(this.domRoot.find("textarea")[0], {
lineNumbers: true,
matchBrackets: true,
useCPP: true,
dragDrop: false,
readOnly: state.options ? !!state.options.readOnly : false,
extraKeys: {
"Alt-F": false, // see https://github.com/mattgodbolt/compiler-explorer/pull/131
"Ctrl-/": 'toggleComment',
"Ctrl-Enter": _.bind(function () {
this.maybeEmitChange();
}, this)
},
mode: cmMode
// TODOs!
// ctrl-enter
// other languages
// font scale
// check for other css styling
var root = this.domRoot.find(".monaco-placeholder");
this.editor = monaco.editor.create(root[0], {
value: state.source || defaultSrc || "",
language: cmMode
});
// TODO
// "Ctrl-Enter": _.bind(function () {
// this.maybeEmitChange();
// }, this)
this.fontScale = new FontScale(this.domRoot, state);
this.fontScale.on('change', _.bind(this.updateState, this));
if (state.source) {
this.editor.setValue(state.source);
} else if (defaultSrc) {
this.editor.setValue(defaultSrc);
}
// We suppress posting changes until the user has stopped typing by:
// * Using _.debounce() to run emitChange on any key event or change
// only after a delay.
@ -111,25 +99,20 @@ define(function (require) {
this.debouncedEmitChange = _.debounce(function () {
if (self.options.get().compileOnChange) self.maybeEmitChange();
}, ChangeDebounceMs);
this.editor.on("change", _.bind(function () {
this.editor.getModel().onDidChangeContent(_.bind(function () {
this.debouncedEmitChange();
this.updateState();
}, this));
this.editor.on("keydown", _.bind(function () {
// Not strictly a change; but this suppresses changes until some time
// after the last key down (be it an actual change or a just a cursor
// movement etc).
this.debouncedEmitChange();
}, this));
function refresh() {
self.editor.refresh();
}
function resize() {
// this.editor.on("keydown", _.bind(function () {
// // Not strictly a change; but this suppresses changes until some time
// // after the last key down (be it an actual change or a just a cursor
// // movement etc).
// this.debouncedEmitChange();
// }, this));
function layout() {
var topBarHeight = self.domRoot.find(".top-bar").outerHeight(true);
self.editor.setSize(self.domRoot.width(), self.domRoot.height() - topBarHeight);
refresh();
self.editor.layout({width: self.domRoot.width(), height: self.domRoot.height() - topBarHeight});
}
this.domRoot.find('.load-save').click(_.bind(function () {
@ -140,14 +123,15 @@ define(function (require) {
}, this));
}, this));
container.on('resize', resize);
container.on('shown', refresh);
container.on('resize', layout);
container.on('shown', layout);
container.on('open', function () {
self.eventHub.emit('editorOpen', self.id);
});
container.on('destroy', function () {
self.eventHub.unsubscribe();
self.eventHub.emit('editorClose', self.id);
self.editor.dispose();
});
container.setTitle(lang + " source #" + self.id);
this.container.layoutManager.on('initialised', function () {
@ -194,7 +178,7 @@ define(function (require) {
};
Editor.prototype.getSource = function () {
return this.editor.getValue();
return this.editor.getModel().getValue();
};
Editor.prototype.onOptionsChange = function (before, after) {
@ -250,7 +234,7 @@ define(function (require) {
};
Editor.prototype.updateColours = function (colours) {
colour.applyColours(this.editor, colours);
this.colours = colour.applyColours(this.editor, colours, this.colours);
this.eventHub.emit('colours', this.id, colours);
};
@ -267,7 +251,7 @@ define(function (require) {
this.maybeEmitChange(true);
};
Editor.prototype.onCompiling = function(compilerId) {
Editor.prototype.onCompiling = function (compilerId) {
this.busyCompilers[compilerId] = true;
};

1
static/explorer.css

@ -1,5 +1,4 @@
@import url("ext/bootstrap/dist/css/bootstrap.min.css");
@import url("ext/codemirror/lib/codemirror.css");
@import url("ext/golden-layout/src/css/goldenlayout-base.css");
@import url("ext/golden-layout/src/css/goldenlayout-light-theme.css");
@import url("ext/selectize/dist/css/selectize.bootstrap2.css");

4
static/index.html

@ -93,7 +93,7 @@
</button>
</div>
</div>
<textarea>// Type your code here, or load an example.</textarea>
<div class="monaco-placeholder"></div>
</div>
<div id="compiler">
@ -149,7 +149,7 @@
</button>
</div>
</div>
<textarea>[Waiting...]</textarea>
<div class="monaco-placeholder"></div>
<div class="bottom-bar">
<div class="btn-group btn-group-sm">
<button><span class="glyphicon glyphicon-alert status"></span></button>

8
static/main.js

@ -37,13 +37,9 @@ require.config({
clipboard: 'ext/clipboard/dist/clipboard',
'raven-js': 'ext/raven-js/dist/raven',
'es6-promise': 'ext/es6-promise/es6-promise',
'lru-cache': 'ext/lru-cache/lib/lru-cache'
'lru-cache': 'ext/lru-cache/lib/lru-cache',
vs: 'ext/monaco-editor/dev/vs'
},
packages: [{
name: "codemirror",
location: "ext/codemirror",
main: "lib/codemirror"
}],
shim: {
underscore: {exports: '_'},
'lru-cache': {exports: 'LRUCache'},

30
static/monaco.js

@ -0,0 +1,30 @@
// Copyright (c) 2012-2017, Matt Godbolt
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
define(function (require) {
require('vs/editor/editor.main');
return monaco;
});
Loading…
Cancel
Save