diff --git a/app.js b/app.js index 1f67afa3..b9773817 100755 --- a/app.js +++ b/app.js @@ -516,7 +516,6 @@ findCompilers() webServer .set('trust proxy', true) .set('view engine', 'pug') - .set('view cache', true) .use(morgan('combined', {stream: logger.stream})) .use(compression()) .get('/', function (req, res) { diff --git a/static/compiler.js b/static/compiler.js index d2b7f448..865733df 100644 --- a/static/compiler.js +++ b/static/compiler.js @@ -159,6 +159,7 @@ define(function (require) { container.on('destroy', function () { self.eventHub.unsubscribe(); self.eventHub.emit('compilerClose', self.id); + self.outputEditor.dispose(); }, this); container.on('resize', this.resize, this); container.on('shown', this.resize, this); @@ -472,12 +473,16 @@ define(function (require) { }; Compiler.prototype.sendCompiler = function () { - this.eventHub.emit('compiler', this.id, this.compiler, this.options); + this.eventHub.emit('compiler', this.id, this.compiler, this.options, this.sourceEditorId); }; Compiler.prototype.onEditorClose = function (editor) { if (editor === this.sourceEditorId) { - this.container.close(); + // We can't immediately close as an outer loop somewhere in GoldenLayout is iterating over + // the hierarchy. We can't modify while it's being iterated over. + _.defer(function (self) { + self.container.close(); + }, this); } }; @@ -519,7 +524,7 @@ define(function (require) { Compiler.prototype.updateCompilerName = function () { var compilerName = this.compiler ? this.compiler.name : "no compiler set"; var compilerVersion = this.compiler ? this.compiler.version : ""; - this.container.setTitle("#" + this.sourceEditorId + " with " + compilerName); + this.container.setTitle(compilerName + " (Editor #" + this.sourceEditorId + ", Compiler #" + this.id + ")"); this.domRoot.find(".full-compiler-name").text(compilerVersion); }; diff --git a/static/diff.js b/static/diff.js index 118365ef..1e540a81 100644 --- a/static/diff.js +++ b/static/diff.js @@ -72,7 +72,18 @@ define(function (require) { labelField: 'name', searchField: ['name'], options: [], - items: [] + items: [], + render: { + option: function (item, escape) { + return '
' + + '' + escape(item.compiler.name) + '' + + '' + escape(item.options) + '' + + '
'; + } + } }).on('change', function () { var compiler = self.compilers[$(this).val()]; if (!compiler) return; @@ -83,9 +94,7 @@ define(function (require) { self.rhs.compiler = compiler; self.rhs.id = compiler.id; } - self.eventHub.emit('resendCompilation', compiler.id); - self.updateCompilerNames(); - self.updateState(); + self.onDiffSelect(compiler.id); }); this.selectize = {lhs: selectize[0].selectize, rhs: selectize[1].selectize}; @@ -98,6 +107,7 @@ define(function (require) { this.container.on('destroy', function () { this.eventHub.unsubscribe(); + this.outputEditor.dispose(); }, this); container.on('resize', this.resize, this); container.on('shown', this.resize, this); @@ -119,6 +129,12 @@ define(function (require) { }); }; + Diff.prototype.onDiffSelect = function (id) { + this.eventHub.emit('resendCompilation', id); + this.updateCompilerNames(); + this.updateState(); + }; + Diff.prototype.onCompileResult = function (id, compiler, result) { // both sides must be updated, don't be tempted to rewrite this as // var changes = lhs.update() || rhs.update(); @@ -129,10 +145,31 @@ define(function (require) { } }; - Diff.prototype.onCompiler = function (id, compiler, options) { + Diff.prototype.onCompiler = function (id, compiler, options, editorId) { if (!compiler) return; options = options || ""; - this.compilers[id] = {id: id, name: compiler.name + " " + options}; + var name = compiler.name + " " + options; + // TODO: selectize doesn't play nicely with CSS tricks for truncation; this is the best I can do + // There's a plugin at: http://www.benbybenjacobs.com/blog/2014/04/09/no-wrap-plugin-for-selectize-dot-js + // but it doesn't look easy to integrate. + var maxLength = 30; + if (name.length > maxLength - 3) name = name.substr(0, maxLength - 3) + "..."; + this.compilers[id] = { + id: id, + name: name, + options: options, + editorId: editorId, + compiler: compiler + }; + if (!this.lhs.id) { + this.lhs.compiler = this.compilers[id]; + this.lhs.id = id; + this.onDiffSelect(id); + } else if (!this.rhs.id) { + this.rhs.compiler = this.compilers[id]; + this.rhs.id = id; + this.onDiffSelect(id); + } this.updateCompilers(); }; diff --git a/static/editor.js b/static/editor.js index 639485ab..75bc0d6f 100644 --- a/static/editor.js +++ b/static/editor.js @@ -98,6 +98,18 @@ define(function (require) { }, this) }); + this.editor.addAction({ + id: 'toggleCompileOnChange', + label: 'Toggle compile on change', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.Enter], + keybindingContext: null, + run: _.bind(function () { + this.eventHub.emit('modifySettings', { + compileOnChange: !this.settings.compileOnChange + }); + }, this) + }); + function tryCompilerSelectLine(thisLineNumber) { _.each(self.asmByCompiler, function (asms, compilerId) { var targetLines = []; @@ -242,8 +254,10 @@ define(function (require) { // * Turn off auto. // * edit code // * change compiler or compiler options (out of date code is used) - if (before.delayAfterChange !== after.delayAfterChange || !this.debouncedEmitChange) { - if (after.delayAfterChange) { + var bDac = before.compileOnChange ? before.delayAfterChange : 0; + var aDac = after.compileOnChange ? after.delayAfterChange : 0; + if (bDac !== aDac || !this.debouncedEmitChange) { + if (aDac) { this.debouncedEmitChange = _.debounce(_.bind(function () { this.maybeEmitChange(); }, this), after.delayAfterChange); diff --git a/static/explorer.css b/static/explorer.css index 8f50462d..2efda59a 100644 --- a/static/explorer.css +++ b/static/explorer.css @@ -55,9 +55,33 @@ } .diff-picker { + max-width: 20em; width: 20em; } +.diff-picker .compiler { + font-weight: bold; +} + +.diff-picker .options { + padding-left: 0.5em; + font-size: small; +} + +.diff-picker .meta { + text-align: right; + list-style: none; + margin: 0; + padding: 0; + font-size: x-small; +} + +.diff-picker .meta li { + padding: 0; + display: inline; + margin: 0 10px 0 0; +} + input.options { width: 98%; margin-left: 0.25em; @@ -164,11 +188,11 @@ pre.content { } .font-option-active { - background: #226699!important; + background: #226699 !important; } .font-option-active:hover { - background: #4477AA!important; + background: #4477AA !important; } .notification { diff --git a/static/main.js b/static/main.js index ab197cef..b05bf5a6 100644 --- a/static/main.js +++ b/static/main.js @@ -65,6 +65,7 @@ define(function (require) { var Raven = require('raven-js'); var settings = require('./settings'); var local = require('./local'); + var Alert = require('./alert'); function setupSettings(eventHub) { var currentSettings = JSON.parse(local.get('settings', '{}')); @@ -79,7 +80,10 @@ define(function (require) { eventHub.emit('settingsChange', currentSettings); }); - settings($('#settings'), currentSettings, onChange); + var setSettings = settings($('#settings'), currentSettings, onChange); + eventHub.on('modifySettings', function (newSettings) { + setSettings(_.extend(currentSettings, newSettings)); + }); } function start() { @@ -178,6 +182,11 @@ define(function (require) { local.remove('gl'); window.location.reload(); }); + $('#thanks-to').click(function () { + $.get('thanks.html', function (result) { + new Alert().alert("Special thanks to", $(result)); + }); + }); } $(start); diff --git a/static/output.js b/static/output.js index 0dd0d8da..156a9dc3 100644 --- a/static/output.js +++ b/static/output.js @@ -44,6 +44,7 @@ define(function (require) { this.eventHub.on('compileResult', this.onCompileResult, this); this.eventHub.emit('resendCompilation', this.compilerId); this.eventHub.on('compilerFontScale', this.onFontScale, this); + this.eventHub.on('compilerClose', this.onCompilerClose, this); this.updateCompilerName(); } @@ -88,6 +89,16 @@ define(function (require) { this.container.setTitle(name); }; + Output.prototype.onCompilerClose = function (id) { + if (id === this.compilerId) { + // We can't immediately close as an outer loop somewhere in GoldenLayout is iterating over + // the hierarchy. We can't modify while it's being iterated over. + _.defer(function (self) { + self.container.close(); + }, this); + } + }; + return { Output: Output }; diff --git a/static/settings.js b/static/settings.js index b78c2cdb..ec378227 100644 --- a/static/settings.js +++ b/static/settings.js @@ -108,19 +108,30 @@ define(function (require) { _.map(colour.schemes, function (scheme) { return {label: scheme.name, desc: scheme.desc}; })); - add(root.find('.slider'), 'delayAfterChange', 750, Slider, { + // Handle older settings + if (settings.delayAfterChange === 0) { + settings.delayAfterChange = 750; + settings.compileOnChange = false; + } + add(root.find('.compileOnChange'), 'compileOnChange', true, Checkbox); + add(root.find('.delay'), 'delayAfterChange', 750, Slider, { max: 3000, step: 250, + min: 250, formatter: function (x) { - if (x === 0) return "Disabled"; return (x / 1000.0).toFixed(2) + "s"; } }); add(root.find('.hoverShowSource'), 'hoverShowSource', true, Checkbox); add(root.find('.hoverShowAsmDoc'), 'hoverShowAsmDoc', true, Checkbox); - onSettingsChange(settings); - onChange(settings); + function setSettings(settings) { + onSettingsChange(settings); + onChange(settings); + } + + setSettings(settings); + return setSettings; } return setupSettings; diff --git a/views/embed.pug b/views/embed.pug index c42ed040..cc3fa2b6 100644 --- a/views/embed.pug +++ b/views/embed.pug @@ -4,9 +4,7 @@ html(lang="en") include head.pug body.embedded a.float-link.link(href="/" target="_blank") - | Edit on - span.lanugage-name - | Compiler Explorer + | Edit on #{language} Compiler Explorer span.glyphicon.glyphicon-new-window br diff --git a/views/popups.pug b/views/popups.pug index c60fa28b..dc648684 100644 --- a/views/popups.pug +++ b/views/popups.pug @@ -57,38 +57,44 @@ button.close(type="button" data-dismiss="modal" aria-hidden="true") × h3.modal-title Compiler Explorer Settings .modal-body - div + .well.well-sm | These settings control how Compiler Explorer acts for you. They are not | preserved as part of shared URLs, and are persisted locally using browser | local storage. + .well.well-sm h4 Editor .form-group(role="group") - .form-control.checkbox + .checkbox label input.autoCloseBrackets(type="checkbox") | Automatically insert matching brackets and parentheses - .form-control Delay before compiling:  - b Disabled - .slider.slider-horizontal.delay - b 3s - .form-control.checkbox + div + .checkbox + label + input.compileOnChange(type="checkbox") + | Compile automatically when source changes + div Delay before compiling:  + b 0.25s  + .slider.slider-horizontal.delay + b  3s + .checkbox label input.hoverShowSource(type="checkbox") | Highlight linked code lines on hover - .form-control.checkbox + .checkbox label input.hoverShowAsmDoc(type="checkbox") | Show asm description on hover + .well.well-sm h4 Compilation - .form-group(role="group") - .form-control.checkbox - label - input.colourise(type="checkbox") - | Colourise lines so one can see how the source maps to the output - .form-control - label - | Colour scheme: - select.colourScheme + .form-group(role="group") + .checkbox + label + input.colourise(type="checkbox") + | Colourise lines to show how the source maps to the output + label + | Colour scheme: + select.colourScheme .modal-footer button.btn.btn-default(type="button" data-dismiss="modal") Close