
10 changed files with 2 additions and 2906 deletions
@ -1,233 +0,0 @@
|
||||
var fs = require('fs'), |
||||
child_process = require('child_process'), |
||||
temp = require('temp'), |
||||
path = require('path'), |
||||
logger = require('./logger').logger, |
||||
Promise = require('promise') // jshint ignore:line
|
||||
; |
||||
|
||||
function cleanAndGetIndexes(text) { |
||||
var addRules = { |
||||
name: "add", |
||||
openTag: "{+", |
||||
replaceOpenTag: "", |
||||
closeTag: "+}", |
||||
replaceCloseTag: "" |
||||
}; |
||||
var delRules = { |
||||
name: "del", |
||||
openTag: "[-", |
||||
replaceOpenTag: "", |
||||
closeTag: "-]", |
||||
replaceCloseTag: "" |
||||
}; |
||||
var rules = [addRules, delRules]; |
||||
|
||||
var TagTypeEnum = { |
||||
OPENING: 1, |
||||
CLOSING: 2 |
||||
}; |
||||
|
||||
function tagLookup(rules, text, pos) { |
||||
var seen = false; |
||||
var type = null; |
||||
var rule = null; |
||||
for (var i = 0; i < rules.length; i++) { |
||||
var candidateTag = text.slice(pos, pos + rules[i].openTag.length); |
||||
if (rules[i].openTag == candidateTag) { |
||||
seen = true; |
||||
type = TagTypeEnum.OPENING; |
||||
rule = i; |
||||
break; |
||||
} |
||||
candidateTag = text.slice(pos, pos + rules[i].closeTag.length); |
||||
if (rules[i].closeTag == candidateTag) { |
||||
seen = true; |
||||
type = TagTypeEnum.CLOSING; |
||||
rule = i; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return { |
||||
seen: seen, |
||||
rule: rule, |
||||
type: type |
||||
}; |
||||
} |
||||
|
||||
var finalText = ""; |
||||
var posInFinalText = 0; // character that is going to be treated
|
||||
// The position in the original text:
|
||||
var posInText = 0; // character that is going to be treated
|
||||
var StateEnum = { |
||||
OUTSIDE_TAG: 1, |
||||
INSIDE_TAG: 2 |
||||
}; |
||||
var state = StateEnum.OUTSIDE_TAG; |
||||
var zones = [[], []]; |
||||
var currentTextBeginPos = 0; |
||||
var currentTextEndPos = null; |
||||
var currentTagBeginPos = null; |
||||
var currentTagEndPos = null; |
||||
var currentTag = null; |
||||
|
||||
function forward() { |
||||
posInFinalText = posInFinalText + 1; |
||||
posInText = posInText + 1; |
||||
} |
||||
|
||||
function seenOpeningTag() { |
||||
memorizeText(); |
||||
currentTagBeginPos = posInFinalText; |
||||
finalText = finalText.concat(rules[currentTag].replaceOpenTag); |
||||
posInFinalText = posInFinalText + rules[currentTag].replaceOpenTag.length; |
||||
posInText = posInText + rules[currentTag].openTag.length; |
||||
currentTextBeginPos = posInText; |
||||
} |
||||
|
||||
function seenClosingTag() { |
||||
memorizeText(); |
||||
finalText = finalText.concat(rules[currentTag].replaceCloseTag); |
||||
posInFinalText = posInFinalText + rules[currentTag].replaceCloseTag.length; |
||||
posInText = posInText + rules[currentTag].closeTag.length; |
||||
currentTagEndPos = posInFinalText - 1; |
||||
zones[currentTag].push({begin: currentTagBeginPos, end: currentTagEndPos}); |
||||
currentTextBeginPos = posInText; |
||||
} |
||||
|
||||
function memorizeText() { |
||||
currentTextEndPos = posInText - 1; |
||||
if (currentTextEndPos >= currentTextBeginPos) { |
||||
finalText = finalText.concat(text.slice(currentTextBeginPos, currentTextEndPos + 1)); |
||||
} |
||||
} |
||||
|
||||
function end() { |
||||
memorizeText(); |
||||
} |
||||
|
||||
while (posInText < text.length) { |
||||
var tag = tagLookup(rules, text, posInText); |
||||
if (tag.seen && tag.type == TagTypeEnum.OPENING) { |
||||
if (state != StateEnum.OUTSIDE_TAG) { |
||||
log.error("Opening tag while not outside tag (tags cannot be nested)"); |
||||
return null; |
||||
} |
||||
currentTag = tag.rule; |
||||
seenOpeningTag(); |
||||
state = StateEnum.INSIDE_TAG; |
||||
} else if (tag.seen && tag.type == TagTypeEnum.CLOSING) { |
||||
if (state != StateEnum.INSIDE_TAG) { |
||||
log.error("Closing tag while not inside tag."); |
||||
return null; |
||||
} |
||||
if (currentTag != tag.rule) { |
||||
log.error("Closing tag, but not of the same type as previously opened."); |
||||
return null; |
||||
} |
||||
seenClosingTag(); |
||||
state = StateEnum.OUTSIDE_TAG; |
||||
} else { |
||||
forward(); |
||||
} |
||||
} |
||||
end(); |
||||
|
||||
return {text: finalText, zones: zones}; |
||||
} |
||||
|
||||
function newTempDir() { |
||||
return new Promise(function (resolve, reject) { |
||||
temp.mkdir('compiler-explorer-diff', function (err, dirPath) { |
||||
if (err) |
||||
reject("Unable to open temp file: " + err); |
||||
else |
||||
resolve(dirPath); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
var writeFile = Promise.denodeify(fs.writeFile); |
||||
|
||||
function buildDiffHandler(config) { |
||||
var maxFileSize = config.maxOutput; |
||||
return function diffHandler(req, res) { |
||||
var before = req.body.before; |
||||
var after = req.body.after; |
||||
var error; |
||||
if (before === undefined) { |
||||
error = 'Warning : Bad request : wrong "before"'; |
||||
logger.error(error); |
||||
return next(new Error(error)); |
||||
} |
||||
if (after === undefined) { |
||||
error = 'Warning : Bad request : wrong "after"'; |
||||
logger.error(error); |
||||
return next(new Error(error)); |
||||
} |
||||
|
||||
var tempBeforePath, tempAfterPath; |
||||
newTempDir() |
||||
.then(function (tmpDir) { |
||||
tempBeforePath = path.join(tmpDir, "compiler-explorer-wdiff-before"); |
||||
tempAfterPath = path.join(tmpDir, "compiler-explorer-wdiff-after"); |
||||
return Promise.all( |
||||
writeFile(tempBeforePath, before), |
||||
writeFile(tempAfterPath, after) |
||||
); |
||||
}) |
||||
.then(function () { |
||||
var truncated = false; |
||||
var stdout = ""; |
||||
var child = child_process.spawn(config.wdiffExe, [tempBeforePath, tempAfterPath], |
||||
{maxBuffer: maxFileSize, detached: true}); |
||||
child.stdout.on('data', function (data) { |
||||
if (truncated) return; |
||||
if (stdout.length > maxFileSize) { |
||||
stdout += "\n[Truncated]"; |
||||
truncated = true; |
||||
child.kill(); |
||||
resolve(stdout); |
||||
} |
||||
stdout += data; |
||||
}); |
||||
return new Promise(function (resolve, reject) { |
||||
child.on('error', function (e) { |
||||
reject(e); |
||||
}); |
||||
child.on('exit', function () { |
||||
// See comment in compile-handler.js - seems needed if the child has immediately exited
|
||||
setTimeout(function () { |
||||
resolve(stdout); |
||||
}, 0); |
||||
}); |
||||
}); |
||||
}) |
||||
.then(function (output) { |
||||
var cleaned = cleanAndGetIndexes(output); |
||||
res.set('Content-Type', 'application/json'); |
||||
if (cleaned === null) { |
||||
res.end(JSON.stringify({ |
||||
computedDiff: "Failed to clean the diff", |
||||
zones: null |
||||
})); |
||||
} else { |
||||
res.end(JSON.stringify({ |
||||
computedDiff: cleaned.text, |
||||
zones: cleaned.zones |
||||
})); |
||||
} |
||||
}) |
||||
.catch(function (err) { |
||||
res.end(JSON.stringify({ |
||||
computedDiff: "Failed to diff: " + err, |
||||
zones: null |
||||
})); |
||||
}); |
||||
}; |
||||
} |
||||
|
||||
module.exports = { |
||||
buildDiffHandler: buildDiffHandler |
||||
}; |
@ -1,284 +0,0 @@
|
||||
body { |
||||
padding-top: 58px; |
||||
padding-bottom: 40px; |
||||
} |
||||
|
||||
/* Override the cursor that Bootstrap defines for readonly inputs, as it looks |
||||
* very odd on IE (and 'text' makes it clearer that it's copyable everywhere). |
||||
*/ |
||||
#permalink { |
||||
cursor: text; |
||||
width: 100%; |
||||
} |
||||
|
||||
.btn.active { |
||||
color: #fff; |
||||
border-color: #46b8da; |
||||
background-color: #5bc0de; |
||||
} |
||||
|
||||
.autocompile { |
||||
font-size: 18px; |
||||
height: 24px; |
||||
padding-top: 0; |
||||
} |
||||
|
||||
#changetip_tipme_button { |
||||
width: 80px; |
||||
} |
||||
|
||||
#flattr_button { |
||||
width: 120px; |
||||
} |
||||
|
||||
.output { |
||||
height: 80px; |
||||
overflow: auto; |
||||
font-family: monospace; |
||||
} |
||||
|
||||
.compilers-container { |
||||
} |
||||
|
||||
.compiler-options { |
||||
margin-left: 10px; // space between the scroll-down and the compiler's options |
||||
width: 100%; |
||||
} |
||||
|
||||
.options { |
||||
background: #ddf; |
||||
border-radius: 4px; |
||||
padding: 8px; |
||||
} |
||||
|
||||
.options label { |
||||
display: inline-block; |
||||
} |
||||
|
||||
.inline-msg { |
||||
font-family: arial; |
||||
font-size: 70%; |
||||
padding: 2px 5px 3px; |
||||
} |
||||
|
||||
span.icon { |
||||
border-radius: 50%; |
||||
padding: 0 3px; |
||||
margin-right: 7px; |
||||
} |
||||
|
||||
.error { |
||||
background: #faa !important; |
||||
color: #a00; |
||||
} |
||||
|
||||
.error span.icon { |
||||
color: white; |
||||
background-color: red; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.warning { |
||||
background: #ffa !important; |
||||
color: #440; |
||||
} |
||||
|
||||
.warning span.icon { |
||||
color: black; |
||||
background-color: yellow; |
||||
} |
||||
|
||||
.note { |
||||
background: #aaf !important; |
||||
color: #00a; |
||||
} |
||||
|
||||
.note span.icon { |
||||
color: white; |
||||
background-color: blue; |
||||
} |
||||
|
||||
.template { |
||||
display: none; |
||||
} |
||||
|
||||
li.social { |
||||
padding: 4px; |
||||
} |
||||
|
||||
.topbar { |
||||
margin-top: 10px; |
||||
padding: 6px; |
||||
background: #eee; |
||||
border-top-right-radius: 10px; |
||||
border-top-left-radius: 10px; |
||||
} |
||||
|
||||
.indented { |
||||
margin-left: 36px; |
||||
} |
||||
|
||||
/* These colours from Cynthia Brewer's excellent page at |
||||
* http://colorbrewer2.org/ |
||||
*/ |
||||
.rainbow-0 { |
||||
background: rgb(141, 211, 199) !important; |
||||
} |
||||
|
||||
.rainbow-1 { |
||||
background: rgb(255, 255, 179) !important; |
||||
} |
||||
|
||||
.rainbow-2 { |
||||
background: rgb(190, 186, 218) !important; |
||||
} |
||||
|
||||
.rainbow-3 { |
||||
background: rgb(251, 128, 114) !important; |
||||
} |
||||
|
||||
.rainbow-4 { |
||||
background: rgb(128, 177, 211) !important; |
||||
} |
||||
|
||||
.rainbow-5 { |
||||
background: rgb(253, 180, 98) !important; |
||||
} |
||||
|
||||
.rainbow-6 { |
||||
background: rgb(179, 222, 105) !important; |
||||
} |
||||
|
||||
.rainbow-7 { |
||||
background: rgb(252, 205, 229) !important; |
||||
} |
||||
|
||||
.rainbow-8 { |
||||
background: rgb(217, 217, 217) !important; |
||||
} |
||||
|
||||
.rainbow-9 { |
||||
background: rgb(188, 128, 189) !important; |
||||
} |
||||
|
||||
.rainbow-10 { |
||||
background: rgb(204, 234, 197) !important; |
||||
} |
||||
|
||||
.rainbow-11 { |
||||
background: rgb(255, 237, 111) !important; |
||||
} |
||||
|
||||
.address { |
||||
width: 4em; |
||||
font-size: smaller; |
||||
} |
||||
|
||||
.opcodes { |
||||
width: 7em; |
||||
overflow: hidden; |
||||
font-size: smaller; |
||||
} |
||||
|
||||
.opcode { |
||||
color: #066; |
||||
margin-right: 0.2em; |
||||
} |
||||
|
||||
.opcode:nth-child(odd) { |
||||
color: #060; |
||||
} |
||||
|
||||
.highlighted { |
||||
background-color: rgba(255, 0, 0, 0.2); |
||||
color: #0000b0; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
|
||||
/* Only one of these class is currently used on index.html but just in case |
||||
* we change it, it is already tuned */ |
||||
.col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, |
||||
.col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-md-1, .col-md-10, |
||||
.col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, |
||||
.col-md-7, .col-md-8, .col-md-9, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, |
||||
.col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, |
||||
.col-sm-9, .col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, |
||||
.col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 { |
||||
position: relative; |
||||
min-height: 1px; |
||||
padding-right: 0; |
||||
padding-left: 0; |
||||
} |
||||
|
||||
.panel-primary { |
||||
border-color: #000; |
||||
} |
||||
|
||||
.panel-body { |
||||
padding-top: 15px; |
||||
padding-right: 5px; |
||||
padding-bottom: 5px; |
||||
padding-left: 5px; |
||||
} |
||||
|
||||
/* show the move cursor as the user moves the mouse over the panel header.*/ |
||||
#draggablePanelList .panel-heading { |
||||
cursor: move; |
||||
} |
||||
|
||||
.panel-modest, |
||||
.panel-modest .panel-body { |
||||
display: inline-block; |
||||
} |
||||
|
||||
.unselectable{ |
||||
/* disable text selection on character icons |
||||
* source : http://stackoverflow.com/a/9314458/4669135 */ |
||||
-webkit-touch-callout: none; |
||||
-webkit-user-select: none; |
||||
-khtml-user-select: none; |
||||
-moz-user-select: none; |
||||
-ms-user-select: none; |
||||
user-select: none; |
||||
} |
||||
|
||||
.characterIcon { |
||||
/* Show classical cursor when hovering */ |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.selectedCharacterIcon { |
||||
color: #01DF01; |
||||
font-size: 25px; |
||||
margin-top: 0.4em; |
||||
margin-right: 0.2em; |
||||
} |
||||
|
||||
.unselectedCharacterIcon { |
||||
color: #BDBDBD; |
||||
font-size: 25px; |
||||
margin-top: 0.4em; |
||||
margin-right: 0.2em; |
||||
} |
||||
|
||||
.unicode-arrow { |
||||
font-size: 25px; |
||||
} |
||||
|
||||
.unicodeCross { |
||||
overflow: visible; |
||||
font-weight: bold; |
||||
color: #B90000; |
||||
font-size: 20px; /* problem : it makes the panel header (title zone) bigger*/ |
||||
float: right; |
||||
} |
||||
|
||||
|
||||
.diff-before-button { |
||||
background-color: rgba(251,175,175,.7); |
||||
} |
||||
|
||||
.diff-after-button { |
||||
background-color: rgba(151,234,151,.6); |
||||
} |
@ -1,486 +0,0 @@
|
||||
// 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.
|
||||
|
||||
var currentCompiler = null; |
||||
var allCompilers = []; |
||||
|
||||
function getSource() { |
||||
var source = $('.source').val(); |
||||
if (source == "browser") { |
||||
if (window.localStorage.files === undefined) window.localStorage.files = "{}"; |
||||
return { |
||||
list: function (callback) { |
||||
var files = JSON.parse(window.localStorage.files); |
||||
callback($.map(files, function (val, key) { |
||||
return val; |
||||
})); |
||||
}, |
||||
load: function (name, callback) { |
||||
var files = JSON.parse(window.localStorage.files); |
||||
callback(files[name]); |
||||
}, |
||||
save: function (obj, callback) { |
||||
var files = JSON.parse(window.localStorage.files); |
||||
files[obj.name] = obj; |
||||
window.localStorage.files = JSON.stringify(files); |
||||
callback(true); |
||||
} |
||||
}; |
||||
} else { |
||||
var base = "/source/" + source; |
||||
return { |
||||
list: function (callback) { |
||||
$.getJSON(base + "/list", callback); |
||||
}, |
||||
load: function (name, callback) { |
||||
$.getJSON(base + "/load/" + name, callback); |
||||
}, |
||||
save: function (obj, callback) { |
||||
alert("Coming soon..."); |
||||
} |
||||
}; |
||||
} |
||||
} |
||||
|
||||
var currentFileList = {}; |
||||
function updateFileList() { |
||||
getSource().list(function (results) { |
||||
currentFileList = {}; |
||||
$('.filename option').remove(); |
||||
$.each(results, function (index, arg) { |
||||
currentFileList[arg.name] = arg; |
||||
$('.filename').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>')); |
||||
if (window.localStorage.filename == arg.urlpart) $('.filename').val(arg.urlpart); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
function onSourceChange() { |
||||
updateFileList(); |
||||
window.localStorage.source = $('.source').val(); |
||||
} |
||||
|
||||
function loadFile() { |
||||
var name = $('.filename').val(); |
||||
window.localStorage.filename = name; |
||||
getSource().load(name, function (results) { |
||||
if (results.file) { |
||||
currentCompiler.setSource(results.file); |
||||
} else { |
||||
// TODO: error?
|
||||
console.log(results); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function saveFile() { |
||||
saveAs($('.files .filename').val()); |
||||
} |
||||
|
||||
function saveAs(filename) { |
||||
var prevFilename = window.localStorage.filename || ""; |
||||
if (filename != prevFilename && currentFileList[filename]) { |
||||
// TODO!
|
||||
alert("Coming soon - overwriting files"); |
||||
return; |
||||
} |
||||
var obj = {urlpart: filename, name: filename, file: currentCompiler.getSource()}; |
||||
getSource().save(obj, function (ok) { |
||||
if (ok) { |
||||
window.localStorage.filename = filename; |
||||
updateFileList(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function saveFileAs() { |
||||
$('#saveDialog').modal(); |
||||
$('#saveDialog .save-filename').val($('.files .filename').val()); |
||||
$('#saveDialog .save-filename').focus(); |
||||
function onSave() { |
||||
$('#saveDialog').modal('hide'); |
||||
saveAs($('#saveDialog .save-filename').val()); |
||||
} |
||||
|
||||
$('#saveDialog .save').click(onSave); |
||||
$('#saveDialog .save-filename').keyup(function (event) { |
||||
if (event.keyCode == 13) onSave(); |
||||
}); |
||||
} |
||||
|
||||
function hidePermalink() { |
||||
if ($('.files .permalink-collapse').hasClass('in')) { // do nothing if already hidden.
|
||||
$('.files .permalink-collapse').collapse('hide'); |
||||
} |
||||
} |
||||
|
||||
function showPermalink(short) { |
||||
if (!$('.files .permalink-collapse').hasClass('in')) { |
||||
$('.files .permalink-collapse').collapse('show'); |
||||
} |
||||
$('#permalink').val(''); |
||||
|
||||
var fullUrl = window.location.href.split('#')[0] + '#' + serialiseState(); |
||||
if (short) { |
||||
shortenURL(fullUrl, |
||||
function (shortUrl) { |
||||
$('#permalink').val(shortUrl); |
||||
}); |
||||
} else { |
||||
$('#permalink').val(fullUrl); |
||||
} |
||||
} |
||||
|
||||
function serialiseState() { |
||||
var compressed = rison.quote(rison.encode_object(getState(true))); |
||||
var uncompressed = rison.quote(rison.encode_object(getState(false))); |
||||
var MinimalSavings = 0.20; // at least this ratio smaller
|
||||
if (compressed.length < uncompressed.length * (1.0 - MinimalSavings)) { |
||||
return compressed; |
||||
} else { |
||||
return uncompressed; |
||||
} |
||||
} |
||||
|
||||
function getState(compress) { |
||||
return { |
||||
version: 3, |
||||
filterAsm: getAsmFilters(), |
||||
compilers: $.map(allCompilers, function (compiler) { |
||||
return compiler.serialiseState(compress); |
||||
}) |
||||
}; |
||||
} |
||||
|
||||
// Gist is a pastbin service operated by github
|
||||
function toGist(state) { |
||||
files = {}; |
||||
function nameFor(compiler) { |
||||
var addNum = 0; |
||||
var name, add; |
||||
for (; ;) { |
||||
add = addNum ? addNum.toString() : ""; |
||||
name = compiler + add + '.' + OPTIONS.sourceExtension; |
||||
if (files[name] === undefined) return name; |
||||
addNum++; |
||||
} |
||||
}; |
||||
state.compilers.forEach(function (s) { |
||||
var name = nameFor(s.compiler); |
||||
files[name] = { |
||||
content: s.source, |
||||
language: OPTIONS.language |
||||
}; |
||||
s.source = name; |
||||
}); |
||||
files['state.json'] = {content: JSON.stringify(state)}; |
||||
return JSON.stringify({ |
||||
description: "Compiler Explorer automatically generated files", |
||||
'public': false, |
||||
files: files |
||||
}); |
||||
} |
||||
|
||||
function isGithubLimitError(request) { |
||||
var remaining = parseInt(request.getResponseHeader('X-RateLimit-Remaining')); |
||||
var reset = parseInt(request.getResponseHeader('X-RateLimit-Reset')); |
||||
var limit = parseInt(request.getResponseHeader('X-RateLimit-Limit')); |
||||
if (remaining !== 0) return null; |
||||
var left = (new Date(reset * 1000) - Date.now()) / 1000; |
||||
return "Rate limit of " + limit + " exceeded: " + Math.round(left / 60) + " mins til reset"; |
||||
} |
||||
|
||||
function makeGist(onDone, onFail) { |
||||
var req = $.ajax('https://api.github.com/gists', { |
||||
type: 'POST', |
||||
accepts: 'application/vnd.github.v3+json', |
||||
dataType: 'json', |
||||
contentType: 'application/json', |
||||
data: toGist(getState()) |
||||
}); |
||||
req.done(function (msg) { |
||||
onDone(msg); |
||||
}); |
||||
req.fail(function (jqXHR, textStatus) { |
||||
var rateLimited = isGithubLimitError(jqXHR); |
||||
if (rateLimited) |
||||
onFail(rateLimited); |
||||
else |
||||
onFail(textStatus + " (" + jqXHR.statusText + ")"); |
||||
}); |
||||
} |
||||
|
||||
function fromGist(msg) { |
||||
var state = JSON.parse(msg.files['state.json'].content); |
||||
state.compilers.forEach(function (s) { |
||||
s.source = msg.files[s.source].content; |
||||
}); |
||||
return state; |
||||
} |
||||
function loadGist(gist) { |
||||
var req = $.ajax('https://api.github.com/gists/' + gist); |
||||
req.done(function (msg) { |
||||
loadState(fromGist(msg)); |
||||
}); |
||||
req.fail(function (jqXHR, textStatus) { |
||||
var err = isGithubLimitError(jqXHR); |
||||
if (!err) { |
||||
err = textStatus + " (" + jqXHR.statusText + ")"; |
||||
} |
||||
alert("Unable to load gist: " + err); |
||||
}); |
||||
} |
||||
|
||||
function deserialiseState(stateText) { |
||||
var state = null; |
||||
if (stateText.substr(0, 2) == "g=") { |
||||
loadGist(stateText.substr(2)); |
||||
return; |
||||
} |
||||
|
||||
try { |
||||
state = rison.decode_object(decodeURIComponent(stateText.replace(/\+/g, '%20'))); |
||||
} catch (ignored) { |
||||
} |
||||
|
||||
if (!state) { |
||||
try { |
||||
state = $.parseJSON(decodeURIComponent(stateText)); |
||||
} catch (ignored) { |
||||
} |
||||
} |
||||
if (state) { |
||||
return loadState(state); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
function loadState(state) { |
||||
if (!state || state['version'] === undefined) return false; |
||||
switch (state.version) { |
||||
case 1: |
||||
state.filterAsm = {}; |
||||
/* falls through */ |
||||
case 2: |
||||
state.compilers = [state]; |
||||
/* falls through */ |
||||
case 3: |
||||
break; |
||||
default: |
||||
return false; |
||||
} |
||||
setFilterUi(state.filterAsm); |
||||
for (var i = 0; i < Math.min(allCompilers.length, state.compilers.length); i++) { |
||||
allCompilers[i].setFilters(state.filterAsm); |
||||
allCompilers[i].deserialiseState(state.compilers[i],OPTIONS.compilers, OPTIONS.defaultCompiler); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
function resizeEditors() { |
||||
var windowHeight = $(window).height(); |
||||
_.each(allCompilers, function (compiler) { compiler.resize(windowHeight); }); |
||||
} |
||||
|
||||
function codeEditorFactory(container, state) { |
||||
var template = $('#codeEditor'); |
||||
var options = state.options; |
||||
container.getElement().html(template.html()); |
||||
return new Editor(container, options.language); |
||||
} |
||||
|
||||
function compilerOutputFactory(container, state) { |
||||
var template = $('#compiler'); |
||||
var options = state.options; |
||||
container.getElement().html(template.html()); |
||||
return new CompileToAsm(container); |
||||
} |
||||
|
||||
function initialise(options) { |
||||
var config = { |
||||
content: [{ |
||||
type: 'row', |
||||
content: [{ |
||||
type: 'component', |
||||
componentName: 'codeEditor', |
||||
componentState: { options: options } |
||||
}, { |
||||
type: 'column', |
||||
content: [{ |
||||
type: 'component', |
||||
componentName: 'compilerOutput', |
||||
componentState: { options: options } |
||||
}, { |
||||
type: 'component', |
||||
componentName: 'compilerOutput', |
||||
componentState: { options: options } |
||||
}] |
||||
}] |
||||
}] |
||||
}; |
||||
var myLayout = new GoldenLayout(config, $("#root")[0]); |
||||
myLayout.registerComponent('codeEditor', codeEditorFactory); |
||||
myLayout.registerComponent('compilerOutput', compilerOutputFactory); |
||||
myLayout.init(); |
||||
/* |
||||
var defaultFilters = JSON.stringify(getAsmFilters()); |
||||
var actualFilters = $.parseJSON(window.localStorage.filter || defaultFilters); |
||||
setFilterUi(actualFilters); |
||||
|
||||
$(".compiler-options").val(options.compileoptions); |
||||
$(".language-name").text(options.language); |
||||
|
||||
var compiler = new Compiler($('body'), actualFilters, "a", function () { |
||||
hidePermalink(); |
||||
}, options.language, options.compilers, options.defaultCompiler); |
||||
allCompilers.push(compiler); |
||||
currentCompiler = compiler; |
||||
|
||||
$('form').submit(function () { |
||||
return false; |
||||
}); |
||||
$('.files .source').change(onSourceChange); |
||||
// This initialization is moved inside var compiler = new Compiler ....
|
||||
// compiler.setCompilers(options.compilers, options.defaultCompiler);
|
||||
function setSources(sources, defaultSource) { |
||||
$('.source option').remove(); |
||||
$.each(sources, function (index, arg) { |
||||
$('.files .source').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>')); |
||||
if (defaultSource == arg.urlpart) { |
||||
$('.files .source').val(arg.urlpart); |
||||
} |
||||
}); |
||||
onSourceChange(); |
||||
} |
||||
|
||||
setSources(options.sources, window.localStorage.source || options.defaultSource); |
||||
$('.files .load').click(function () { |
||||
loadFile(); |
||||
return false; |
||||
}); |
||||
$('.files .save').click(function () { |
||||
saveFile(); |
||||
return false; |
||||
}); |
||||
$('.files .saveas').click(function () { |
||||
saveFileAs(); |
||||
return false; |
||||
}); |
||||
$('.files .fulllink').click(function (e) { |
||||
showPermalink(false); |
||||
return false; |
||||
}); |
||||
$('.files .shortlink').click(function (e) { |
||||
showPermalink(true); |
||||
return false; |
||||
}); |
||||
|
||||
new Clipboard('.btn.clippy'); |
||||
|
||||
$('.filter button.btn').click(function (e) { |
||||
$(e.target).toggleClass('active'); |
||||
var filters = getAsmFilters(); |
||||
window.localStorage.filter = JSON.stringify(filters); |
||||
currentCompiler.setFilters(filters); |
||||
}); |
||||
|
||||
function loadFromHash() { |
||||
deserialiseState(window.location.hash.substr(1)); |
||||
} |
||||
|
||||
$(window).bind('hashchange', function () { |
||||
loadFromHash(); |
||||
}); |
||||
loadFromHash(); |
||||
|
||||
$(window).on("resize", resizeEditors); |
||||
resizeEditors(); |
||||
*/ |
||||
} |
||||
|
||||
function getAsmFilters() { |
||||
var asmFilters = {}; |
||||
$('.filter button.btn.active').each(function () { |
||||
asmFilters[$(this).val()] = true; |
||||
}); |
||||
return asmFilters; |
||||
} |
||||
|
||||
function setFilterUi(asmFilters) { |
||||
$('.filter button.btn').each(function () { |
||||
$(this).toggleClass('active', !!asmFilters[$(this).val()]); |
||||
}); |
||||
} |
||||
|
||||
$(document).ready(function() { |
||||
$('#new-slot').on('click', function(e) { |
||||
console.log("[UI] User clicked on new-slot button."); |
||||
var newSlot = currentCompiler.createAndPlaceSlot( |
||||
OPTIONS.compilers, OPTIONS.defaultCompiler, null, true); |
||||
resizeEditors(); |
||||
currentCompiler.refreshSlot(newSlot); |
||||
}); |
||||
}); |
||||
|
||||
$(document).ready(function() { |
||||
$('#new-diff').on('click', function(e) { |
||||
console.log("[UI] User clicked on new-diff button."); |
||||
var newDiff = currentCompiler.createAndPlaceDiffUI(null, true); |
||||
resizeEditors(); |
||||
}); |
||||
}); |
||||
|
||||
$(function () { |
||||
initialise(OPTIONS); |
||||
}); |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Unit/Functional tests require:
|
||||
|
||||
function getSettingsList() { |
||||
// console.log(JSON.stringify(window.localStorage));
|
||||
var entries = Object.getOwnPropertyNames(window.localStorage); |
||||
return entries; |
||||
} |
||||
|
||||
function getSetting(settingName) { |
||||
return window.localStorage[settingName]; |
||||
} |
||||
|
||||
function wipeSettings() { |
||||
window.localStorage.clear(); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DEBUG :
|
||||
function listSettings() { |
||||
var entries = getSettingsList(); |
||||
for (var i = 0; i < entries.length; i++) { |
||||
console.log(entries[i]); |
||||
} |
||||
} |
||||
|
||||
function showSetting(settingName) { |
||||
console.log(JSON.stringify(getSetting(settingName, null, ' '))); |
||||
} |
@ -1,363 +0,0 @@
|
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<title>Compiler Explorer</title> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
<link href="ext/bootstrap/css/bootstrap.min.css" rel="stylesheet"> |
||||
<link href="ext/codemirror/codemirror.css" rel="stylesheet"> |
||||
<link href="ext/golden-layout/goldenlayout-base.css" rel="stylesheet"> |
||||
<link href="ext/golden-layout/goldenlayout-light-theme.css" rel="stylesheet"> |
||||
<link href="gcc.css" rel="stylesheet"> |
||||
<script src="client-options.js"></script> |
||||
<script src="ext/codemirror/codemirror.js"></script> |
||||
<script src="asm-mode.js"></script> |
||||
<script src="ext/jquery/jquery-2.2.2.min.js"></script> |
||||
<script src="ext/golden-layout/goldenlayout.min.js"></script> |
||||
<script src="ext/jquery-ui-1.11.4/jquery-ui.min.js"></script> |
||||
<script src="ext/rison.js"></script> |
||||
<script src="ext/underscore-min.js"></script> |
||||
<script src="ext/clipboard.min.js"></script> |
||||
<script src="compiler.js"></script> |
||||
<script src="gcc.js"></script> |
||||
<script src="ext/bootstrap/js/bootstrap.min.js"></script> |
||||
<script src="ext/lz-string/lz-string-1.3.3-min.js"></script> |
||||
<script type="text/javascript"> |
||||
var _gaq = _gaq || []; |
||||
_gaq.push(['_setAccount', OPTIONS.googleAnalyticsAccount]); |
||||
_gaq.push(['_trackPageview']); |
||||
|
||||
setTimeout(function () { |
||||
"use strict"; |
||||
function create_script_element(id, url) { |
||||
var el = document.createElement('script'); |
||||
el.type = 'text/javascript'; |
||||
el.async = true; |
||||
el.id = id; |
||||
el.src = url; |
||||
var s = document.getElementsByTagName('script')[0]; |
||||
s.parentNode.insertBefore(el, s); |
||||
} |
||||
|
||||
create_script_element('urlshortener', 'urlshorten-' + OPTIONS.urlshortener + ".js"); |
||||
if (OPTIONS.googleAnalyticsEnabled) |
||||
create_script_element('ga', ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'); |
||||
if (OPTIONS.sharingEnabled) { |
||||
create_script_element('gp', 'https://apis.google.com/js/plusone.js'); |
||||
create_script_element('twitter-wjs', '//platform.twitter.com/widgets.js'); |
||||
(function(document, i) { |
||||
var f,s=document.getElementById(i); |
||||
f=document.createElement('iframe'); |
||||
f.src='//api.flattr.com/button/view/?uid=mattgodbolt&button=compact&url='+encodeURIComponent(document.URL); |
||||
f.title='Flattr'; |
||||
f.height=20; |
||||
f.width=110; |
||||
f.style.borderWidth=0; |
||||
s.appendChild(f); |
||||
}(document, 'flattr_button')); |
||||
} |
||||
}, 0); |
||||
|
||||
</script> |
||||
</head> |
||||
<body> |
||||
<div class="navbar navbar-inverse"> |
||||
<div class="container-fluid"> |
||||
<div class="navbar-header"> |
||||
<a class="navbar-brand" href="#">Compiler Explorer - <span class="language-name"></span></a> |
||||
</div> |
||||
<div class="navbar-collapse collapse"> |
||||
<ul class="nav navbar-nav navbar-right"> |
||||
<li class="if-github-enabled"> |
||||
<a href="https://github.com/mattgodbolt/gcc-explorer">Source on GitHub</a> |
||||
</li> |
||||
<li class="dropdown if-share-enabled"> |
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Donate<b class="caret"></b></a> |
||||
<ul class="dropdown-menu"> |
||||
<li class="navbar-text"><a href="https://www.changetip.com/tipme/mattgodbolt">ChangeTip.Me</a></li> |
||||
<li class="navbar-text" id="flattr_button"></li> |
||||
</ul> |
||||
</li> |
||||
<li class="dropdown if-share-enabled"> |
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Share<b class="caret"></b></a> |
||||
<ul class="dropdown-menu"> |
||||
<li class="social"> |
||||
<g:plusone annotation="inline" width="150"></g:plusone> |
||||
</li> |
||||
<li class="social"><a href="https://twitter.com/share" class="twitter-share-button" |
||||
data-via="mattgodbolt">Tweet</a></li> |
||||
</ul> |
||||
</li> |
||||
<li class="dropdown"> |
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">About<b class="caret"></b></a> |
||||
<ul class="dropdown-menu"> |
||||
<li><a href="https://plus.google.com/112384289668860490877" rel="publisher">Google+ page</a> |
||||
</li> |
||||
<li><a href="https://plus.google.com/105166465490735292917" rel="author">About Matt</a></li> |
||||
<li><a href="mailto:matt@godbolt.org">Contact Matt</a></li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div id="codeEditor" class="template"> |
||||
<textarea>// Type your code here, or load an example.</textarea> |
||||
</div> |
||||
|
||||
<div id="compiler" class="template"> |
||||
<div class="panel-body"> |
||||
<div class="params"> |
||||
<form class="well well-sm form-inline"> |
||||
<table> |
||||
<tbody> |
||||
<tr> |
||||
<td class="dropdown compilers-container"> |
||||
<button type="button" title="Compiler to use" class="btn btn-default dropdown-toggle compiler-selection" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> |
||||
<span class="compiler">g++</span> |
||||
<span class="caret"></span> |
||||
</button> |
||||
<ul class="dropdown-menu compilers"> |
||||
</ul> |
||||
</td> |
||||
<td> |
||||
<input accesskey="" title="Options to pass to compiler" class="compiler-options" placeholder="compiler options" type="text" value="" style="width:90%"> |
||||
</td> |
||||
</tr> |
||||
</tbody> |
||||
</table> |
||||
</form> |
||||
</div> |
||||
<div class="asm"> |
||||
<textarea>Awaiting...</textarea> |
||||
</div> |
||||
<div class="output"> |
||||
<div class="result"> |
||||
<div class="topbar">Compiler output — <span class="compilerVersion"></span></div> |
||||
<div class="output"> |
||||
<div class="template"></div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="container-fluid" id="#root"><!-- |
||||
<ul id="draggablePanelList" class="list-unstyled"> |
||||
<li class="panel panel-primary col-md-3"> |
||||
<div class="panel-heading"><span class="title">Code editor</span></div> |
||||
<div class="panel-body"> |
||||
<div id="commonParams"> |
||||
<form class="well form-inline files"> |
||||
<div> |
||||
<label>Source: <select class="source"></select></label> |
||||
<label>Name: <select class="filename"></select></label> |
||||
<button id="new-slot" class="btn btn-sm" title="Open a new slot.">New slot</button> |
||||
<button id="new-diff" class="btn btn-sm" title="Open a new diff.">New diff</button> |
||||
</div> |
||||
<div class="btn-group btn-group-sm"> |
||||
<button class="btn btn-sm load">Load</button> |
||||
<button class="btn btn-sm save">Save</button> |
||||
<button class="btn btn-sm saveas">Save as...</button> |
||||
<button class="btn btn-sm fulllink" title="Permanent, full URL to this page">Full link</button> |
||||
<button class="btn btn-sm shortlink" title="Permanent link to this page as a short link">Short link</button> |
||||
</div> |
||||
<div class="btn-group btn-group-sm filter"> |
||||
<button class="btn btn-sm" type="button" value="binary" |
||||
title="Compile to binary and disassemble the output">Binary |
||||
</button> |
||||
<button class="btn btn-sm active nonbinary" type="button" |
||||
title="Filter unused labels from the output" value="labels">Unused labels |
||||
</button> |
||||
<button class="btn btn-sm active nonbinary" type="button" |
||||
title="Filter all assembler directives from the output" value="directives">Directives |
||||
</button> |
||||
<button class="btn btn-sm active nonbinary" type="button" |
||||
title="Remove all lines which are only comments from the output" value="commentOnly"> |
||||
Comment-only lines |
||||
</button> |
||||
<button class="btn btn-sm" type="button" title="Output disassembly in Intel syntax" |
||||
value="intel">Intel syntax |
||||
</button> |
||||
<button class="btn btn-sm" type="button" |
||||
title="Colourise lines so one can see how the source maps to the output" |
||||
value="colouriseAsm">Colourise |
||||
</button> |
||||
</div> |
||||
<div class="collapse permalink-collapse"> |
||||
<div class="input-group input-group-sm permalink"> |
||||
<input type="text" class="form-control input-sm" placeholder="Loading" readonly id="permalink" size="1024"> |
||||
<span class="input-group-btn"> |
||||
<button class="btn btn-sm btn-default clippy" type="button" data-clipboard-target="#permalink" |
||||
title="Copy to clipboard"> |
||||
<img src="ext/clippy.svg" class="clippy" width="13px" alt="Copy to clipboard"> |
||||
</button> |
||||
</span> |
||||
</div> |
||||
</div> |
||||
</form> |
||||
</div> |
||||
<div class="editor"> |
||||
<div class="topbar indented"> |
||||
Code editor |
||||
<span class="pull-right input-group input-group-sm"> |
||||
<button accesskey="a" title="Automatically build when you stop typing" |
||||
class="btn btn-default btn-sm autocompile active"> |
||||
<span class="glyphicon glyphicon-play-circle"></span> |
||||
</button> |
||||
</span> |
||||
</div> |
||||
<textarea>// Type your code here, or load an example.</textarea> |
||||
</div> |
||||
|
||||
<div class="modal fade" id="saveDialog"> |
||||
<div class="modal-dialog"> |
||||
<div class="modal-content"> |
||||
<div class="modal-header"> |
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
||||
aria-hidden="true">×</span></button> |
||||
<h4>Save as...</h4> |
||||
</div> |
||||
<div class="modal-body"> |
||||
<label>Filename: <input class="save-filename" style="width: 30em;" type="text"></label> |
||||
</div> |
||||
<div class="modal-footer"> |
||||
<a href="#" data-dismiss="modal" class="btn btn-default">Cancel</a> |
||||
<a href="#" class="btn btn-primary save">Save</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</li> |
||||
|
||||
<li class="panel panel-primary col-md-3 template slot" id="slotTemplate"> |
||||
<div class="panel-heading"> |
||||
<span class="title">Slot template (should *not* be visible)</span> |
||||
<span class="closeButton unicodeCross unselectable characterIcon">✖</span> |
||||
</div> |
||||
<div class="panel-body"> |
||||
<div class="params"> |
||||
<form class="well well-sm form-inline"> |
||||
<table> |
||||
<tbody> |
||||
<tr> |
||||
<td> |
||||
<p class="leaderSlotIcon unselectable characterIcon unselectedCharacterIcon">☆</p> |
||||
<td class="dropdown compilers-container"> |
||||
<!– the accesskey is set in static/compiler.js –> |
||||
<button accesskey="" type="button" title="Compiler to use (alt-C)" class="btn btn-default dropdown-toggle compiler-selection" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> |
||||
<span class="compiler">g++</span> |
||||
<span class="caret"></span> |
||||
</button> |
||||
<ul class="dropdown-menu compilers"> |
||||
</ul> |
||||
</td> |
||||
<td> |
||||
<!– the accesskey is set in static/compiler.js –> |
||||
<input accesskey="" title="Options to pass to compiler (alt-O)" class="compiler-options" placeholder="compiler options" type="text" value="" style="width:90%"> |
||||
</td> |
||||
</tr> |
||||
</tbody> |
||||
</table> |
||||
<div class="btn-group btn-group-sm filter"> |
||||
<!– Place slot-specific buttons here. –> |
||||
</div> |
||||
</form> |
||||
</div> |
||||
<div class="asm"> |
||||
<div class="topbar indented">Assembly output</div> |
||||
<textarea>Awaiting...</textarea> |
||||
</div> |
||||
<div class="output"> |
||||
<div class="result"> |
||||
<div class="topbar">Compiler output — <span class="compilerVersion"></span></div> |
||||
<div class="output"> |
||||
<div class="template"></div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<li class="panel panel-primary col-md-3 template diff" id="diffTemplate"> |
||||
<div class="panel-heading"><span class="title">Diff template (should *not* be visible)</span><span class="closeButton unicodeCross unselectable characterIcon">✖</span></div> |
||||
<div class="panel-body"> |
||||
<div class="params"> |
||||
<form class="well well-sm form-inline"> |
||||
<table> |
||||
<tbody> |
||||
<tr> |
||||
<td class="dropdown compilers-container before"> |
||||
<button type="button" |
||||
title="Slot before" class="btn btn-default dropdown-toggle diff-before-button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> |
||||
<span class="slotName">before</span> |
||||
<span class="caret"></span> |
||||
</button> |
||||
<ul class="dropdown-menu slotNameList"> |
||||