blob: 3d4249dfca539b5303b0ee5122f808f3f55f177e [file] [log] [blame] [raw]
Matt Godbolt8610ec92016-03-28 08:22:49 -05001// Copyright (c) 2012-2016, Matt Godbolt
Gabriel Devillersac2338f2016-07-04 16:54:38 +02002//
Matt Godbolt5be62682012-06-20 14:46:45 -05003// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
8// * Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright
11// notice, this list of conditions and the following disclaimer in the
12// documentation and/or other materials provided with the distribution.
13//
14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24// POSSIBILITY OF SUCH DAMAGE.
25
26function parseLines(lines, callback) {
Matt Godbolt3f055622012-09-20 22:14:28 -050027 var re = /^\/tmp\/[^:]+:([0-9]+)(:([0-9]+))?:\s+(.*)/;
Matt Godboltc60cad22014-11-26 08:24:40 -060028 $.each(lines.split('\n'), function (_, line) {
Matt Godbolt5be62682012-06-20 14:46:45 -050029 line = line.trim();
Matt Godboltc60cad22014-11-26 08:24:40 -060030 if (line !== "") {
Matt Godbolt5be62682012-06-20 14:46:45 -050031 var match = line.match(re);
32 if (match) {
Matt Godbolt6dd61682013-02-06 17:28:01 -060033 callback(parseInt(match[1]), match[4].trim());
Matt Godbolt5be62682012-06-20 14:46:45 -050034 } else {
35 callback(null, line);
36 }
37 }
38 });
39}
Matt Godbolt3075f962013-02-04 21:25:57 -060040
Gabriel Devillers28ef7682016-06-27 11:29:35 +020041// Function called on the editor's window, or on a slot's window
Matt Godbolt5be62682012-06-20 14:46:45 -050042function clearBackground(cm) {
43 for (var i = 0; i < cm.lineCount(); ++i) {
Matt Godbolt091bf372013-02-04 22:18:37 -060044 cm.removeLineClass(i, "background", null);
Matt Godbolt5be62682012-06-20 14:46:45 -050045 }
46}
Matt Godbolt3075f962013-02-04 21:25:57 -060047
48const NumRainbowColours = 12;
Matt Godbolt5be62682012-06-20 14:46:45 -050049
Gabriel Devillersac2338f2016-07-04 16:54:38 +020050// This function is called in function initialise in static/gcc.js
Matt Godbolt32e742e2016-08-06 15:20:03 -050051function Compiler(domRoot, origFilters, windowLocalPrefix,
Gabriel Devillers2e057e52016-07-29 11:39:05 +020052 onEditorChangeCallback, lang, compilers, defaultCompiler) {
Gabriel Devillers28ef7682016-06-27 11:29:35 +020053 console.log("[TRACE] Entering function Compiler()");
Gabriel Devillers39966c72016-08-01 17:29:11 +020054 // Global array that will contain the slots.
Matt Godbolt51ae5482016-08-06 14:46:47 -050055 var slots = [];
Matt Godbolt32e742e2016-08-06 15:20:03 -050056 var Slot = function (id) {
Gabriel Devillers39966c72016-08-01 17:29:11 +020057 // this id will be used in the DOM, ex : class="slot"+id
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +020058 // the getAvailableId could be placed here but that could
Gabriel Devillers39966c72016-08-01 17:29:11 +020059 // lead to confusion if the Slot is not pushed in slots
60 this.id = id;
61 this.asmCodeMirror = null;
Gabriel Devillers39966c72016-08-01 17:29:11 +020062 this.currentAssembly = null;
Gabriel Devillers39966c72016-08-01 17:29:11 +020063 // lastRequest contains the previous request in the slot
64 // it can be used to prevent useless re-compilation
65 // if no parameters were really changed (e.g. spaces moved)
66 this.lastRequest = null;
Gabriel Devillers60c96cd2016-07-25 14:30:34 +020067 this.pendingDiffs = [];
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +020068 this.node = null; // Will be initialized in slotDomCtor
Matt Godbolt32e742e2016-08-06 15:20:03 -050069 this.description = function () {
Gabriel Devillersece67892016-08-03 14:49:14 +020070 var options = this.node.find('.compiler-options').val();
71 var compiler = currentCompiler(this);
72 return compiler.name + " " + options;
Matt Godbolt51ae5482016-08-06 14:46:47 -050073 };
Matt Godbolt32e742e2016-08-06 15:20:03 -050074 this.shortDescription = function () {
Gabriel Devillers68379dd2016-08-04 15:43:12 +020075 var description = this.description();
76 if (description.length >= 19) {
Matt Godbolt32e742e2016-08-06 15:20:03 -050077 return description.substring(0, 13) + "[...]"
Gabriel Devillers68379dd2016-08-04 15:43:12 +020078 } else {
79 return description;
80 }
81 }
Matt Godbolt51ae5482016-08-06 14:46:47 -050082 };
Gabriel Devillers39966c72016-08-01 17:29:11 +020083
Matt Godbolt51ae5482016-08-06 14:46:47 -050084 var diffs = [];
Matt Godbolt32e742e2016-08-06 15:20:03 -050085 var Diff = function (id) {
Gabriel Devillersa49e0e92016-07-18 14:36:57 +020086 this.id = id;
Gabriel Devillers711af7a2016-08-01 14:47:12 +020087 this.beforeSlot = null;
88 this.afterSlot = null;
Gabriel Devillersa49e0e92016-07-18 14:36:57 +020089 this.currentDiff = null;
Gabriel Devillers711af7a2016-08-01 14:47:12 +020090 this.asmCodeMirror = null;
Gabriel Devillers269615a2016-07-20 18:18:55 +020091 this.zones = null;
Matt Godbolt51ae5482016-08-06 14:46:47 -050092
Gabriel Devillers3205e562016-07-25 15:57:15 +020093 // used only if the editor's code is modified,
94 // to prevent two diff generation by waiting for the second one.
95 this.remainingTriggers = 2;
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +020096 this.node = null; // Will be initialized in diffDomCtor
Matt Godbolt51ae5482016-08-06 14:46:47 -050097 };
Gabriel Devillers60c96cd2016-07-25 14:30:34 +020098
99 function contains(array, object) {
100 for (var i = 0; i < array.length; i++) {
101 if (array[i] === object) {
102 return true;
103 }
104 }
105 return false;
106 }
107
108 // adds diff to the set (array) slot.pendingDiffs
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200109 function addToPendings(slot, diff) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500110 if (!contains(slot.pendingDiffs, diff)) {
Gabriel Devillers60c96cd2016-07-25 14:30:34 +0200111 slot.pendingDiffs.push(diff);
112 }
Gabriel Devillersa49e0e92016-07-18 14:36:57 +0200113 }
114
Gabriel Devillers39966c72016-08-01 17:29:11 +0200115 // returns the smallest Natural that is not used as an id
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200116 // (suppose that ids are Naturals, but any other way of getting
117 // an unique id usable in HTML's classes should work)
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200118 function getAvailableId(array) {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200119 if (array.length == 0) return 0;
Matt Godbolt51ae5482016-08-06 14:46:47 -0500120 var usedIds = [];
121 var i;
122 for (i = 0; i < array.length; i++) {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200123 usedIds.push(array[i].id)
Gabriel Devillers39966c72016-08-01 17:29:11 +0200124 }
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200125 usedIds.sort();
Gabriel Devillers39966c72016-08-01 17:29:11 +0200126 var prev = -1;
Matt Godbolt51ae5482016-08-06 14:46:47 -0500127 for (i = 0; i < usedIds.length; i++) {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200128 if (usedIds[i] - prev > 1) return prev + 1;
129 prev = usedIds[i];
Gabriel Devillers39966c72016-08-01 17:29:11 +0200130 }
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200131 return usedIds.length;
Gabriel Devillers39966c72016-08-01 17:29:11 +0200132 }
133
Matt Godbolt32e742e2016-08-06 15:20:03 -0500134
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200135 // setSetting('leaderSlot', null); // TODO : remove ?
136 var leaderSlot = null; // is set up correctly at the end of this function.
137 function isLeader(slot) {
138 return (slot == leaderSlot);
139 }
140
Matt Godboltf4e76d22015-01-22 07:22:25 -0600141 var compilersById = {};
142 var compilersByAlias = {};
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200143
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200144 var pendingTimeoutInEditor = null;
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200145
Matt Godbolt5be62682012-06-20 14:46:45 -0500146 var cppEditor = null;
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200147
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200148 // default filters
Matt Godboltb8fca032015-11-28 13:46:39 -0600149 var filters_ = $.extend({}, origFilters);
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200150 var ignoreChanges = true; // Horrible hack to avoid onEditorChange doing anything on first starting, ie before we've set anything up.
Matt Godboltb8fca032015-11-28 13:46:39 -0600151
Matt Godbolt32e742e2016-08-06 15:20:03 -0500152 function setCompilerById(compilerId, slot) {
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +0200153 var compilerNode = slot.node.find('.compiler');
Gabriel Devillers39966c72016-08-01 17:29:11 +0200154 compilerNode.text(compilersById[compilerId].name);
155 compilerNode.attr('data', compilerId);
Matt Godbolt3b391412016-03-27 12:04:52 -0500156 }
157
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200158 function currentCompilerId(slot) {
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +0200159 return slot.node.find('.compiler').attr('data');
Matt Godbolt3b391412016-03-27 12:04:52 -0500160 }
161
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200162 function currentCompiler(slot) {
163 return compilersById[currentCompilerId(slot)];
Matt Godboltb8fca032015-11-28 13:46:39 -0600164 }
165
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200166 // set the autocompile button on static/index.html
Matt Godbolt51ae5482016-08-06 14:46:47 -0500167 var autocompile = $('.autocompile');
168 autocompile.click(function (e) {
169 autocompile.toggleClass('active');
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200170 onEditorChange();
Matt Godbolt32e742e2016-08-06 15:20:03 -0500171 setSetting('autocompile', autocompile.hasClass('active'));
172 });
Matt Godbolt51ae5482016-08-06 14:46:47 -0500173 autocompile.toggleClass('active', getSetting("autocompile") !== "false");
Matt Godbolt15d5b932016-03-27 22:41:18 -0500174
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200175 // handle filter options that are specific to a compiler
Matt Godboltb8fca032015-11-28 13:46:39 -0600176 function patchUpFilters(filters) {
177 filters = $.extend({}, filters);
Gabriel Devillers39966c72016-08-01 17:29:11 +0200178 // TODO : correct the fact that filters should be slot specific !!
179 var compiler = currentCompiler(slots[0]);
Matt Godboltb8fca032015-11-28 13:46:39 -0600180 var compilerSupportsBinary = compiler ? compiler.supportsBinary : true;
181 if (filters.binary && !(OPTIONS.supportsBinary && compilerSupportsBinary)) {
182 filters.binary = false;
183 }
184 return filters;
185 }
Matt Godbolt91c89652015-02-06 21:57:58 -0600186
Matt Godbolt986252d2015-02-20 08:25:55 -0600187 var cmMode;
188 switch (lang.toLowerCase()) {
189 default:
190 cmMode = "text/x-c++src";
191 break;
Ola Jeppssonb7619602015-08-08 11:33:11 +0000192 case "c":
193 cmMode = "text/x-c";
194 break;
Matt Godbolt986252d2015-02-20 08:25:55 -0600195 case "rust":
196 cmMode = "text/x-rustsrc";
197 break;
198 case "d":
199 cmMode = "text/x-d";
200 break;
201 case "go":
202 cmMode = "text/x-go";
203 break;
Matt Godbolt91c89652015-02-06 21:57:58 -0600204 }
Matt Godbolt5be62682012-06-20 14:46:45 -0500205
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200206 // Set up the editor's window
207 // [0] is mandatory here because domRoot.find() returns an array of all
208 // matching elements. It is not a problem for jquery which applies it's
209 // functions to all elements, whereas CodeMirror works on a single DOM node.
Matt Godbolt5be62682012-06-20 14:46:45 -0500210 cppEditor = CodeMirror.fromTextArea(domRoot.find(".editor textarea")[0], {
211 lineNumbers: true,
Matt Godbolt091bf372013-02-04 22:18:37 -0600212 matchBrackets: true,
213 useCPP: true,
Matt Godbolt217c41d2014-04-30 23:26:08 -0500214 mode: cmMode
Matt Godbolt5be62682012-06-20 14:46:45 -0500215 });
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200216
Matt Godbolt28b66082016-06-11 08:29:32 -0500217 // With reference to "fix typing '#' in emacs mode"
218 // https://github.com/mattgodbolt/gcc-explorer/pull/131
Arvid Gerstmann2cd6ff72016-06-11 01:54:42 +0200219 cppEditor.setOption("extraKeys", {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500220 "Alt-F": false
Arvid Gerstmann2cd6ff72016-06-11 01:54:42 +0200221 });
Matt Godbolt15d5b932016-03-27 22:41:18 -0500222 cppEditor.on("change", function () {
223 if ($('.autocompile').hasClass('active')) {
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200224 onEditorChange();
Matt Godbolt15d5b932016-03-27 22:41:18 -0500225 }
226 });
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200227
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200228 // Load/Save/Remove setting from the browser
Matt Godbolt35156ff2012-07-09 06:56:11 -0500229 function getSetting(name) {
230 return window.localStorage[windowLocalPrefix + "." + name];
231 }
Matt Godbolt32e742e2016-08-06 15:20:03 -0500232
Matt Godbolt35156ff2012-07-09 06:56:11 -0500233 function setSetting(name, value) {
234 window.localStorage[windowLocalPrefix + "." + name] = value;
235 }
Matt Godbolt32e742e2016-08-06 15:20:03 -0500236
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200237 function removeSetting(name) {
238 // source: http://stackoverflow.com/questions/9943220/how-to-delete-a-localstorage-item-when-the-browser-window-tab-is-closed
239 window.localStorage.removeItem(windowLocalPrefix + "." + name);
240 }
241
Matt Godbolt91c89652015-02-06 21:57:58 -0600242 var codeText = getSetting('code');
243 if (!codeText) codeText = $(".template.lang." + lang.replace(/[^a-zA-Z]/g, '').toLowerCase()).text();
244 if (codeText) cppEditor.setValue(codeText);
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200245
Matt Godbolt5be62682012-06-20 14:46:45 -0500246 ignoreChanges = false;
Matt Godbolt5be62682012-06-20 14:46:45 -0500247
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200248 // auxiliary function to onCompileResponse(),
249 // used to display the compiler error messages in the editor's window
Matt Godbolt43231b82013-02-05 06:26:59 -0600250 function makeErrNode(text) {
Matt Godbolt6dd61682013-02-06 17:28:01 -0600251 var clazz = "error";
252 if (text.match(/^warning/)) clazz = "warning";
253 if (text.match(/^note/)) clazz = "note";
254 var node = $('<div class="' + clazz + ' inline-msg"><span class="icon">!!</span><span class="msg"></span></div>');
Matt Godbolt43231b82013-02-05 06:26:59 -0600255 node.find(".msg").text(text);
256 return node[0];
Matt Godbolt091bf372013-02-04 22:18:37 -0600257 }
258
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200259 // keep track of error widgets to delete them if need be
Matt Godbolt43231b82013-02-05 06:26:59 -0600260 var errorWidgets = [];
Matt Godboltc60cad22014-11-26 08:24:40 -0600261
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200262 // Compilation's callback
Gabriel Devillers39966c72016-08-01 17:29:11 +0200263 function onCompileResponse(slot, request, data) {
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200264 var leaderSlot = getSetting('leaderSlot');
Gabriel Devillers39966c72016-08-01 17:29:11 +0200265
Matt Godbolt32e742e2016-08-06 15:20:03 -0500266 console.log("[CALLBACK] onCompileResponse() with slot = " + slot.id + ", leaderSlot = ", +leaderSlot);
Matt Godbolt5be62682012-06-20 14:46:45 -0500267 var stdout = data.stdout || "";
268 var stderr = data.stderr || "";
Matt Godboltc60cad22014-11-26 08:24:40 -0600269 if (data.code === 0) {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200270 stdout += "Compiled ok in slot " + slot.id + "\n";
Matt Godbolt5be62682012-06-20 14:46:45 -0500271 } else {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200272 stderr += "Compilation failed in slot " + slot.id + "\n";
Matt Godbolt5be62682012-06-20 14:46:45 -0500273 }
Matt Godboltb10029c2013-02-06 06:19:41 -0600274 if (_gaq) {
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200275 // TODO : to modify to handle the slots ?
Matt Godboltc9cbcd92013-02-07 13:35:28 -0600276 _gaq.push(['_trackEvent', 'Compile', request.compiler, request.options, data.code]);
277 _gaq.push(['_trackTiming', 'Compile', 'Timing', new Date() - request.timestamp]);
Matt Godboltb10029c2013-02-06 06:19:41 -0600278 }
Matt Godbolt889cf272016-08-16 06:59:46 -0500279 var outputRoot = slot.node.find('.result .output');
280 outputRoot.find(':visible').remove();
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200281 // only show in Editor messages comming from the leaderSlot
Matt Godbolt51ae5482016-08-06 14:46:47 -0500282 var i;
Gabriel Devillers39966c72016-08-01 17:29:11 +0200283 if (slot.id == leaderSlot) {
Matt Godbolt51ae5482016-08-06 14:46:47 -0500284 for (i = 0; i < errorWidgets.length; ++i)
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200285 cppEditor.removeLineWidget(errorWidgets[i]);
286 errorWidgets.length = 0;
287 }
Matt Godbolt746072c2015-02-21 12:10:51 -0600288 var numLines = 0;
Matt Godboltc60cad22014-11-26 08:24:40 -0600289 parseLines(stderr + stdout, function (lineNum, msg) {
Matt Godbolt746072c2015-02-21 12:10:51 -0600290 if (numLines > 50) return;
291 if (numLines === 50) {
292 lineNum = null;
293 msg = "Too many output lines...truncated";
294 }
295 numLines++;
Matt Godbolt889cf272016-08-16 06:59:46 -0500296 var elem = outputRoot.find('.template').clone().appendTo(outputRoot).removeClass('template');
Matt Godbolt5be62682012-06-20 14:46:45 -0500297 if (lineNum) {
Matt Godbolt480b1302016-08-07 20:47:28 -0500298 // only show messages coming from the leaderSlot in the Editor
Matt Godbolt32e742e2016-08-06 15:20:03 -0500299 if (slot.id == leaderSlot) {
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200300 errorWidgets.push(cppEditor.addLineWidget(lineNum - 1, makeErrNode(msg), {
301 coverGutter: false, noHScroll: true
302 }));
303 }
Gabriel Devillers68379dd2016-08-04 15:43:12 +0200304 elem.html($('<a href="#">').text(lineNum + " : " + msg)).click(function (e) {
Matt Godbolt5be62682012-06-20 14:46:45 -0500305 cppEditor.setSelection({line: lineNum - 1, ch: 0}, {line: lineNum, ch: 0});
Gabriel Devillers68379dd2016-08-04 15:43:12 +0200306
307 // do not bring user to the top of index.html
308 // http://stackoverflow.com/questions/3252730
309 e.preventDefault();
Matt Godbolt5be62682012-06-20 14:46:45 -0500310 return false;
311 });
312 } else {
313 elem.text(msg);
314 }
315 });
Gabriel Devillers39966c72016-08-01 17:29:11 +0200316 slot.currentAssembly = data.asm || fakeAsm("[no output]");
317 updateAsm(slot);
Matt Godbolt51ae5482016-08-06 14:46:47 -0500318 for (i = 0; i < slot.pendingDiffs.length; i++) {
Gabriel Devillers3205e562016-07-25 15:57:15 +0200319 onDiffChange(slot.pendingDiffs[i], request.fromEditor);
Gabriel Devillers60c96cd2016-07-25 14:30:34 +0200320 }
Matt Godbolt5be62682012-06-20 14:46:45 -0500321 }
322
Matt Godbolt480b1302016-08-07 20:47:28 -0500323 function numberUsedLines() {
324 var result = {source: {}, pending: false, asm: {}};
325 _.each(slots, function (slot) {
326 if (slot.currentAssembly) {
327 slot.currentAssembly.forEach(function (x) {
328 if (x.source) result.source[x.source - 1] = true;
329 });
330 }
Matt Godboltc60cad22014-11-26 08:24:40 -0600331 });
Matt Godbolt5be62682012-06-20 14:46:45 -0500332 var ordinal = 0;
Matt Godbolt480b1302016-08-07 20:47:28 -0500333 _.each(result.source, function (v, k) {
334 result.source[k] = ordinal++;
Matt Godboltc60cad22014-11-26 08:24:40 -0600335 });
Matt Godbolt480b1302016-08-07 20:47:28 -0500336 _.each(slots, function (slot) {
337 var asmLines = {};
338 if (slot.currentAssembly) {
339 slot.currentAssembly.forEach(function (x, index) {
340 if (x.source) asmLines[index] = result.source[x.source - 1];
341 if (x.fake) result.pending = true;
342 });
343 }
344 result.asm[slot.id] = asmLines;
Matt Godboltc60cad22014-11-26 08:24:40 -0600345 });
Matt Godbolt480b1302016-08-07 20:47:28 -0500346 return result;
Matt Godbolt5be62682012-06-20 14:46:45 -0500347 }
Matt Godbolt480b1302016-08-07 20:47:28 -0500348
349 var colourise = function colourise() {
350 var numberedLines = numberUsedLines();
351 cppEditor.operation(function () {
352 clearBackground(cppEditor);
353 if (numberedLines.pending) return; // don't colourise until all results are in
354 _.each(numberedLines.source, function (ordinal, line) {
355 cppEditor.addLineClass(parseInt(line),
356 "background", "rainbow-" + (ordinal % NumRainbowColours));
357 });
358 });
359 // colourise the assembly in slots
360 _.each(slots, function (slot) {
361 slot.asmCodeMirror.operation(function () {
362 clearBackground(slot.asmCodeMirror);
363 if (numberedLines.pending) return; // don't colourise until all results are in
364 _.each(numberedLines.asm[slot.id], function (ordinal, line) {
365 slot.asmCodeMirror.addLineClass(parseInt(line),
366 "background", "rainbow-" + (ordinal % NumRainbowColours));
367 });
368 });
369 });
370 };
Matt Godbolt5be62682012-06-20 14:46:45 -0500371
Matt Godbolt32e742e2016-08-06 15:20:03 -0500372 function updateAsm(slot, forceUpdate) {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200373 console.log("[CALLBACK] updateAsm() with slot = " + slot.id + ", forceUpdate = " + forceUpdate);
374 if (!slot.currentAssembly) return;
375 var hashedUpdate = JSON.stringify(slot.currentAssembly);
Matt Godbolt480b1302016-08-07 20:47:28 -0500376 if (!forceUpdate && JSON.stringify(slot.lastUpdatedAsm) == hashedUpdate) {
Matt Godboltc60cad22014-11-26 08:24:40 -0600377 return;
378 }
Gabriel Devillers39966c72016-08-01 17:29:11 +0200379 slot.lastUpdatedAsm = hashedUpdate;
Matt Godbolt5be62682012-06-20 14:46:45 -0500380
Gabriel Devillers39966c72016-08-01 17:29:11 +0200381 var asmText = $.map(slot.currentAssembly, function (x) {
Matt Godboltc60cad22014-11-26 08:24:40 -0600382 return x.text;
383 }).join("\n");
Matt Godboltc60cad22014-11-26 08:24:40 -0600384
Matt Godboltb8fca032015-11-28 13:46:39 -0600385 var filters = currentFilters();
Gabriel Devillers39966c72016-08-01 17:29:11 +0200386 slot.asmCodeMirror.operation(function () {
387 slot.asmCodeMirror.setValue(asmText);
388 clearBackground(slot.asmCodeMirror);
Matt Godboltb8dac7e2015-11-23 22:26:00 -0600389 var addrToAddrDiv = {};
Gabriel Devillers39966c72016-08-01 17:29:11 +0200390 $.each(slot.currentAssembly, function (line, obj) {
Matt Godbolt0f954902015-11-23 18:16:34 -0600391 var address = obj.address ? obj.address.toString(16) : "";
Matt Godboltb8dac7e2015-11-23 22:26:00 -0600392 var div = $("<div class='address cm-number'>" + address + "</div>");
393 addrToAddrDiv[address] = {div: div, line: line};
Gabriel Devillers39966c72016-08-01 17:29:11 +0200394 slot.asmCodeMirror.setGutterMarker(line, 'address', div[0]);
Matt Godboltb8dac7e2015-11-23 22:26:00 -0600395 });
Gabriel Devillers39966c72016-08-01 17:29:11 +0200396 $.each(slot.currentAssembly, function (line, obj) {
Matt Godbolt0f954902015-11-23 18:16:34 -0600397 var opcodes = $("<div class='opcodes'></div>");
398 if (obj.opcodes) {
399 var title = [];
400 $.each(obj.opcodes, function (_, op) {
401 var opcodeNum = "00" + op.toString(16);
402 opcodeNum = opcodeNum.substr(opcodeNum.length - 2);
403 title.push(opcodeNum);
404 var opcode = $("<span class='opcode'>" + opcodeNum + "</span>");
405 opcodes.append(opcode);
406 });
407 opcodes.attr('title', title.join(" "));
408 }
Gabriel Devillers39966c72016-08-01 17:29:11 +0200409 slot.asmCodeMirror.setGutterMarker(line, 'opcodes', opcodes[0]);
Matt Godboltb8dac7e2015-11-23 22:26:00 -0600410 if (obj.links) {
411 $.each(obj.links, function (_, link) {
412 var from = {line: line, ch: link.offset};
413 var to = {line: line, ch: link.offset + link.length};
414 var address = link.to.toString(16);
415 var thing = $("<a href='#' class='cm-number'>" + address + "</a>");
Gabriel Devillers39966c72016-08-01 17:29:11 +0200416 slot.asmCodeMirror.markText(
Matt Godboltb8dac7e2015-11-23 22:26:00 -0600417 from, to, {replacedWith: thing[0], handleMouseEvents: false});
418 var dest = addrToAddrDiv[address];
419 if (dest) {
420 thing.on('hover', function (e) {
421 var entered = e.type == "mouseenter";
422 dest.div.toggleClass("highlighted", entered);
423 thing.toggleClass("highlighted", entered);
424 });
425 thing.on('click', function (e) {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200426 slot.asmCodeMirror.scrollIntoView({line: dest.line, ch: 0}, 30);
Matt Godbolt7eb2f5e2015-11-23 23:14:39 -0600427 dest.div.toggleClass("highlighted", false);
428 thing.toggleClass("highlighted", false);
Gabriel Devillers68379dd2016-08-04 15:43:12 +0200429
430 // do not bring user to the top of index.html
431 e.preventDefault();
Matt Godboltb8dac7e2015-11-23 22:26:00 -0600432 });
433 }
434 });
435 }
Matt Godbolt0f954902015-11-23 18:16:34 -0600436 });
Matt Godbolt7eb2f5e2015-11-23 23:14:39 -0600437 if (filters.binary) {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200438 slot.asmCodeMirror.setOption('lineNumbers', false);
439 slot.asmCodeMirror.setOption('gutters', ['address', 'opcodes']);
Matt Godbolt7eb2f5e2015-11-23 23:14:39 -0600440 } else {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200441 slot.asmCodeMirror.setOption('lineNumbers', true);
442 slot.asmCodeMirror.setOption('gutters', ['CodeMirror-linenumbers']);
Matt Godbolt7eb2f5e2015-11-23 23:14:39 -0600443 }
Matt Godboltcc62e712013-02-05 17:30:49 -0600444 });
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200445
Matt Godbolt480b1302016-08-07 20:47:28 -0500446 // colourise the editor
447 if (filters.colouriseAsm) {
448 colourise();
Matt Godbolt5be62682012-06-20 14:46:45 -0500449 }
450 }
451
Matt Godbolt4b47e422015-11-11 17:41:19 -0600452 function fakeAsm(text) {
Matt Godbolt480b1302016-08-07 20:47:28 -0500453 return [{text: text, source: null, fake: true}];
Matt Godbolt498930d2012-09-19 18:16:10 -0500454 }
455
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200456 // slot's parameters callback
457 // TODO : refactor with onEditorChange : those functions could call an updateSlot(slot)
Matt Godbolt32e742e2016-08-06 15:20:03 -0500458 function onParamChange(slot, force) {
459 console.log("[CALLBACK] onParamChange() on slot " + slot.id);
Gabriel Devillersece67892016-08-03 14:49:14 +0200460
461 // update the UI of the diff that depends of this slot
462 for (var i = 0; i < slot.pendingDiffs.length; i++) {
463 updateDiffUI(slot.pendingDiffs[i]);
464 }
465
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200466 if (ignoreChanges) return; // Ugly hack during startup.
Gabriel Devillers39966c72016-08-01 17:29:11 +0200467 if (slot.pendingTimeoutInSlot) {
468 console.log("[TIME] Clearing time out in slot " + slot.id);
469 clearTimeout(slot.pendingTimeoutInSlot);
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200470 }
471
Gabriel Devillers39966c72016-08-01 17:29:11 +0200472 console.log("[TIME] Setting time out in slot " + slot.id);
473 slot.pendingTimeoutInSlot = setTimeout(function () {
474 console.log("[TIME] Timed out : compiling in slot " + slot.id + " triggered by modification of params...");
Matt Godbolt32e742e2016-08-06 15:20:03 -0500475 (function (slot) {
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200476 var data = {
Gabriel Devillers3205e562016-07-25 15:57:15 +0200477 fromEditor: false,
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200478 source: cppEditor.getValue(),
479 compiler: currentCompilerId(slot),
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200480 options: slot.node.find('.compiler-options').val(),
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200481 filters: currentFilters()
482 };
Matt Godbolt32e742e2016-08-06 15:20:03 -0500483 setSetting('compiler' + slot.id, data.compiler);
484 setSetting('compilerOptions' + slot.id, data.options);
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200485 var stringifiedReq = JSON.stringify(data);
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200486 if (!force && stringifiedReq == slot.lastRequest) return;
Gabriel Devillers39966c72016-08-01 17:29:11 +0200487 slot.lastRequest = stringifiedReq;
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200488 data.timestamp = new Date();
489 $.ajax({
490 type: 'POST',
491 url: '/compile',
492 dataType: 'json',
493 contentType: 'application/json',
494 data: JSON.stringify(data),
495 success: function (result) {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200496 onCompileResponse(slot, data, result);
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200497 },
498 error: function (xhr, e_status, error) {
499 console.log("AJAX request failed, reason : " + error);
500 },
501 cache: false
502 });
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200503 setSetting('code', cppEditor.getValue());
Gabriel Devillers39966c72016-08-01 17:29:11 +0200504 slot.currentAssembly = fakeAsm("[Processing...]");
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200505 updateAsm(slot);
Matt Godbolt32e742e2016-08-06 15:20:03 -0500506 })(slot);
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200507 }, 750); // Time in ms after which action is taken (if inactivity)
508
509 // (maybe redundant) execute the callback passed to Compiler()
510 onEditorChangeCallback();
511 }
512
Gabriel Devillerse157d9f2016-06-28 14:51:27 +0200513 function onEditorChange(force) {
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200514 console.log("[CALLBACK] onEditorChange()");
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200515 if (ignoreChanges) return; // Ugly hack during startup.
516 if (pendingTimeoutInEditor) {
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200517 console.log("[TIME] Clearing time out in editor");
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200518 clearTimeout(pendingTimeoutInEditor);
519 }
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200520
521 console.log("[TIME] Setting time out in editor");
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200522 pendingTimeoutInEditor = setTimeout(function () {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500523 console.log("[TIME] Timed out in editor : compiling in all " + slots.length + " slots...");
Gabriel Devillers39966c72016-08-01 17:29:11 +0200524 for (var i = 0; i < slots.length; i++) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500525 (function (slot) {
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200526 var data = {
Gabriel Devillers3205e562016-07-25 15:57:15 +0200527 fromEditor: true,
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200528 source: cppEditor.getValue(),
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200529 compiler: currentCompilerId(slot),
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200530 options: slot.node.find('.compiler-options').val(),
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200531 filters: currentFilters()
532 };
Matt Godbolt32e742e2016-08-06 15:20:03 -0500533 setSetting('compiler' + slot.id, data.compiler);
534 setSetting('compilerOptions' + slot.id, data.options);
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200535 var stringifiedReq = JSON.stringify(data);
Gabriel Devillers39966c72016-08-01 17:29:11 +0200536 if (!force && stringifiedReq == slot.lastRequest) return;
537 slot.lastRequest = stringifiedReq;
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200538 data.timestamp = new Date();
539 $.ajax({
540 type: 'POST',
541 url: '/compile',
542 dataType: 'json',
543 contentType: 'application/json',
544 data: JSON.stringify(data),
545 success: function (result) {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200546 onCompileResponse(slot, data, result);
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200547 },
548 error: function (xhr, e_status, error) {
Gabriel Devillerse157d9f2016-06-28 14:51:27 +0200549 console.log("AJAX request failed, reason : " + error);
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200550 },
551 cache: false
552 });
Gabriel Devillers39966c72016-08-01 17:29:11 +0200553 slot.currentAssembly = fakeAsm("[Processing...]");
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200554 updateAsm(slot);
Matt Godbolt32e742e2016-08-06 15:20:03 -0500555 })(slots[i]);
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200556 }
557 }, 750); // Time in ms after which action is taken (if inactivity)
Matt Godbolt35156ff2012-07-09 06:56:11 -0500558 setSetting('code', cppEditor.getValue());
Gabriel Devillers39966c72016-08-01 17:29:11 +0200559 for (var i = 0; i < slots.length; i++) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500560 (function (slot) {
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200561 updateAsm(slot);
Matt Godbolt32e742e2016-08-06 15:20:03 -0500562 })(slots[i]);
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200563 }
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200564
Gabriel Devillersac2338f2016-07-04 16:54:38 +0200565 // execute the callback passed to Compiler()
Gabriel Devillers3f62aa62016-06-23 13:38:03 +0200566 onEditorChangeCallback();
Matt Godbolt5be62682012-06-20 14:46:45 -0500567 }
568
569 function setSource(code) {
570 cppEditor.setValue(code);
571 }
572
573 function getSource() {
574 return cppEditor.getValue();
575 }
576
Matt Godbolt1e810d32016-03-23 22:14:21 -0500577 function serialiseState(compress) {
Gabriel Devillers27189212016-07-04 17:17:39 +0200578 console.log("[WINDOW] Serialising state...");
Gabriel Devillers32475792016-08-04 09:52:50 +0200579 // Beware: we do not serialise the whole objects Slots / Diffs !
580 // (they are to big to be passed by a URL)
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200581
582 // Memorize informations on slots
Gabriel Devillers60c96cd2016-07-25 14:30:34 +0200583 var slotIds = []; // necessary only to link with iiffs
Gabriel Devillers32475792016-08-04 09:52:50 +0200584 var leaderSlotId = leaderSlot.id;
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200585 var compilersInSlots = [];
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200586 var optionsInSlots = [];
Matt Godbolt32e742e2016-08-06 15:20:03 -0500587 slots.forEach(function (slot) {
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200588 slotIds.push(slot.id);
Gabriel Devillers39966c72016-08-01 17:29:11 +0200589 compilersInSlots.push(currentCompilerId(slot));
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200590 optionsInSlots.push(slot.node.find('.compiler-options').val());
Gabriel Devillers39966c72016-08-01 17:29:11 +0200591 });
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200592
593 // Memorize informations on diffs
594 var diffIds = [];
595 var slotsInDiffs = [];
Matt Godbolt32e742e2016-08-06 15:20:03 -0500596 diffs.forEach(function (diff) {
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200597 diffIds.push(diff.id);
Matt Godbolt32e742e2016-08-06 15:20:03 -0500598 slotsInDiffs.push({
599 before: diff.beforeSlot.id,
600 after: diff.afterSlot.id
601 });
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200602 });
603
Matt Godbolt5be62682012-06-20 14:46:45 -0500604 var state = {
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200605 slotCount: slots.length,
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200606 slotIds: slotIds,
Gabriel Devillers32475792016-08-04 09:52:50 +0200607 leaderSlotId: leaderSlotId,
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200608 compilersInSlots: compilersInSlots,
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200609 optionsInSlots: optionsInSlots,
610
611 diffCount: diffs.length,
612 diffIds: diffIds,
613 slotsInDiffs: slotsInDiffs
Matt Godbolt5be62682012-06-20 14:46:45 -0500614 };
Matt Godbolt1e810d32016-03-23 22:14:21 -0500615 if (compress) {
616 state.sourcez = LZString.compressToBase64(cppEditor.getValue());
617 } else {
618 state.source = cppEditor.getValue();
619 }
Matt Godbolt35156ff2012-07-09 06:56:11 -0500620 return state;
Matt Godbolt5be62682012-06-20 14:46:45 -0500621 }
622
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200623 function deserialiseState(state, compilers, defaultCompiler) {
624 console.log("[WINDOW] Deserialising state ...");
625 if (state.hasOwnProperty('sourcez')) {
626 cppEditor.setValue(LZString.decompressFromBase64(state.sourcez));
627 } else {
628 cppEditor.setValue(state.source);
629 }
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200630
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200631 if (slots.length != 0) {
632 console.log("[WINDOW] Deserialisation : deleting existing slots ...");
633 while (slots.length != 0) {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200634 deleteAndUnplaceSlot(slots[slots.length - 1]);
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200635 }
636 }
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200637
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200638 if (diffs.length != 0) {
639 console.log("[WINDOW] Deserialisation : deleting existing diffs ...");
640 while (diffs.length != 0) {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200641 deleteAndUnplaceDiff(diffs[diffs.length - 1]);
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200642 }
643 }
644
Gabriel Devillers32475792016-08-04 09:52:50 +0200645 // Deserialise slots
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200646 console.log("[WINDOW] Deserialisation : deserializing slots...");
Matt Godbolt51ae5482016-08-06 14:46:47 -0500647 var i;
648 for (i = 0; i < state.slotCount; i++) {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200649 var newSlot = createAndPlaceSlot(compilers,
Matt Godbolt32e742e2016-08-06 15:20:03 -0500650 defaultCompiler,
651 state.slotIds[i]);
652 setCompilerById(state.compilersInSlots[i], newSlot);
Gabriel Devillers32475792016-08-04 09:52:50 +0200653 newSlot.node.find('.compiler-options').val(state.optionsInSlots[i]);
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200654 // Somewhat hackily persist compiler into local storage else when the ajax response comes in
655 // with the list of compilers it can splat over the deserialized version.
656 // The whole serialize/hash/localStorage code is a mess! TODO(mg): fix
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200657
Matt Godbolt32e742e2016-08-06 15:20:03 -0500658 setSetting('compiler' + newSlot.id, state.compilersInSlots[i]);
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200659 }
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200660
Gabriel Devillers32475792016-08-04 09:52:50 +0200661 // Deserialise leaderSlot
662 setLeaderSlotIcon(getSlotById(state.leaderSlotId));
663 leaderSlot = getSlotById(state.leaderSlotId);
664 setSetting('leaderSlot', leaderSlot.id);
665
666 // Deserialise diffs
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200667 console.log("[WINDOW] Deserialisation : deserializing diffs...");
Matt Godbolt51ae5482016-08-06 14:46:47 -0500668 for (i = 0; i < state.diffCount; i++) {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200669 var newDiff = createAndPlaceDiff(state.diffIds[i]);
Gabriel Devillersece67892016-08-03 14:49:14 +0200670 setSlotInDiff(newDiff,
Matt Godbolt32e742e2016-08-06 15:20:03 -0500671 "before",
672 getSlotById(state.slotsInDiffs[i]["before"]));
Gabriel Devillersece67892016-08-03 14:49:14 +0200673 setSlotInDiff(newDiff,
Matt Godbolt32e742e2016-08-06 15:20:03 -0500674 "after",
675 getSlotById(state.slotsInDiffs[i]["after"]));
Gabriel Devillers7a8fec32016-07-28 10:32:29 +0200676 onDiffChange(newDiff, false);
Gabriel Devillers60c04b12016-07-25 11:25:06 +0200677 }
678
679 resizeEditors();
Matt Godbolt5be62682012-06-20 14:46:45 -0500680 return true;
681 }
682
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200683 // TODO : split in two functions : one is slot dependant, the other set parameters common to all slots
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200684 function updateCompilerAndButtons(slot) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500685 var compiler = currentCompiler(slot); // TODO handle compiler being null (if e.g. a compiler is removed from the site)
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +0200686 slot.node.find('.compilerVersion').text(compiler.name + " (" + compiler.version + ")");
Matt Godboltb8fca032015-11-28 13:46:39 -0600687 var filters = currentFilters();
Matt Godbolte6dbd2b2015-11-28 11:04:38 -0600688 var supportsIntel = compiler.intelAsm || filters.binary;
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200689 domRoot.find('#commonParams .filter button.btn[value="intel"]').toggleClass("disabled", !supportsIntel);
690 domRoot.find('#commonParams .filter button.btn[value="binary"]').toggleClass("disabled", !compiler.supportsBinary).toggle(OPTIONS.supportsBinary);
691 domRoot.find('#commonParams .filter .nonbinary').toggleClass("disabled", !!filters.binary);
Matt Godbolte6dbd2b2015-11-28 11:04:38 -0600692 }
693
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200694 function onCompilerChange(slot) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500695 console.log("[DEBUG] onCompilerChange called with slot.id = " + slot.id);
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200696 onParamChange(slot);
697 updateCompilerAndButtons(slot);
Gabriel Devillersa49e0e92016-07-18 14:36:57 +0200698 setAllDiffSlotsMenus();
Matt Godbolt5be62682012-06-20 14:46:45 -0500699 }
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200700
Gabriel Devillers3205e562016-07-25 15:57:15 +0200701 function onDiffChange(diff, fromEditor) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500702 console.log("[DEBUG] inside onDiffChange with diff id = " + diff.id +
703 ", seen fromEditor = " + fromEditor);
Gabriel Devillers3205e562016-07-25 15:57:15 +0200704 if (fromEditor == false) {
705 diff.remainingTriggers = 2;
706 } else {
707 diff.remainingTriggers = diff.remainingTriggers - 1;
708 if (diff.remainingTriggers == 0) {
709 diff.remainingTriggers = 2;
710 } else {
711 return null;
712 }
713 }
714
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200715 // If one slot is not mentioned, stop before making the ajax request
716 if (diff.beforeSlot == null || diff.afterSlot == null) {
717 return null;
718 }
719 var data = {
720 // it should also be possible to use .currentAsembly
721 before: diff.beforeSlot.asmCodeMirror.getValue(),
722 after: diff.afterSlot.asmCodeMirror.getValue()
Matt Godbolt51ae5482016-08-06 14:46:47 -0500723 };
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200724
725 $.ajax({
726 type: 'POST',
727 url: '/diff',
728 dataType: 'json',
729 contentType: 'application/json',
730 data: JSON.stringify(data),
731 success: function (result) {
732 //console.log("Success : "+JSON.stringify(result));
733 onDiffResponse(diff, data, result);
734 },
735 error: function (xhr, e_status, error) {
736 console.log("AJAX request for diff failed, reason : " + error);
737 },
738 cache: false
739 });
740 }
741
742 function onDiffResponse(diff, data, result) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500743 console.log("[CALLBACK] onDiffResponse() with diff = " + diff.id);
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200744 // console.log("[DEBUG] result: "+result);
745 diff.currentDiff = result.computedDiff;
Gabriel Devillers269615a2016-07-20 18:18:55 +0200746 diff.zones = result.zones;
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200747 updateDiff(diff);
748 }
749
750 function updateDiff(diff) {
751 console.log("[CALLBACK] updateDiff() with diff = " + diff.id);
752 // console.log("[DEBUG] currentDiff: " + JSON.stringify(diff.currentDiff));
753 if (!diff.currentDiff) {
754 return;
755 }
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200756
757 diff.asmCodeMirror.operation(function () {
758 diff.asmCodeMirror.setValue(diff.currentDiff);
759 clearBackground(diff.asmCodeMirror);
760 });
Matt Godboltdc57aba2016-08-06 15:50:06 -0500761 if (!diff.zones) return;
Matt Godbolt51ae5482016-08-06 14:46:47 -0500762 var doc = diff.asmCodeMirror.getDoc();
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200763 var computeLineChCoord = buildComputeLineChCoord(diff.currentDiff);
Gabriel Devillers269615a2016-07-20 18:18:55 +0200764 // Same colors as in phabricator's diffs
765 var cssStyles = ["background-color: rgba(151,234,151,.6);",
Matt Godbolt32e742e2016-08-06 15:20:03 -0500766 "background-color: rgba(251,175,175,.7);"];
Matt Godbolt51ae5482016-08-06 14:46:47 -0500767 var colorMarkedZones = [];
Matt Godbolt32e742e2016-08-06 15:20:03 -0500768 for (var i = 0; i < diff.zones.length; i++) {
769 for (var j = 0; j < diff.zones[i].length; j++) {
Gabriel Devillers269615a2016-07-20 18:18:55 +0200770 colorMarkedZones.push(
771 doc.markText(computeLineChCoord(diff.zones[i][j].begin),
Matt Godbolt32e742e2016-08-06 15:20:03 -0500772 computeLineChCoord(diff.zones[i][j].end + 1),
773 {css: cssStyles[i]}));
Gabriel Devillers269615a2016-07-20 18:18:55 +0200774 }
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200775 }
776 }
777
Gabriel Devillers269615a2016-07-20 18:18:55 +0200778 // This function is required to place multiline marks in a CodeMirror
779 // windows: markText accepts only coordinates in the form (line, column)
780 // with line and column starting at 1.
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200781 function buildComputeLineChCoord(text) {
782 // assume text is 1 line containing '\n' to break lines
783 // below calculations are placed outside the function to speed up
784 var splitedStr = text.split("\n");
Matt Godbolt51ae5482016-08-06 14:46:47 -0500785 var i;
Matt Godbolt32e742e2016-08-06 15:20:03 -0500786 for (i = 0; i < splitedStr.length; i++) {
787 splitedStr[i] = splitedStr[i] + "\n";
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200788 }
789 var lastPosInLine = [];
790 var currentSum = splitedStr[0].length - 1;
791 // console.log("Last pos in line "+0+": "+currentSum);
Matt Godbolt51ae5482016-08-06 14:46:47 -0500792 lastPosInLine.push(currentSum);
793 for (i = 1; i < splitedStr.length; i++) {
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200794 currentSum = currentSum + splitedStr[i].length;
Matt Godbolt51ae5482016-08-06 14:46:47 -0500795 lastPosInLine.push(currentSum);
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200796 // console.log("Last pos in line "+i+": "+currentSum);
797 }
Matt Godbolt32e742e2016-08-06 15:20:03 -0500798 return function (pos) {
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200799 var line = 0;
Matt Godbolt32e742e2016-08-06 15:20:03 -0500800 while (lastPosInLine[line] < pos) {
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200801 line = line + 1;
802 }
Matt Godbolt32e742e2016-08-06 15:20:03 -0500803 var ch = (line === 0) ? pos : pos - lastPosInLine[line - 1] - 1;
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200804 return {line: line, ch: ch};
805 }
806 }
Matt Godboltc60cad22014-11-26 08:24:40 -0600807
Matt Godbolt7f397722015-01-22 22:30:35 -0600808 function mapCompiler(compiler) {
809 if (!compilersById[compiler]) {
810 // Handle old settings and try the alias table.
Matt Godboltd5bef9e2015-01-27 12:52:38 -0600811 compiler = compilersByAlias[compiler];
812 if (compiler) compiler = compiler.id;
Matt Godbolt7f397722015-01-22 22:30:35 -0600813 }
814 return compiler;
815 }
Matt Godbolt32e742e2016-08-06 15:20:03 -0500816
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200817 // added has auxiliary to setCompilers, in order not to break interface
818 // TODO : consider refactoring as some tasks are repeated
819 function setCompilersInSlot(compilers, defaultCompiler, slot) {
Gabriel Devillersece67892016-08-03 14:49:14 +0200820 console.log("[INIT] inside setCompilersInSlot()");
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +0200821 slot.node.find('.compilers li').remove();
Matt Godboltf4e76d22015-01-22 07:22:25 -0600822 compilersById = {};
823 compilersByAlias = {};
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200824 // fills the compiler list
Matt Godboltc60cad22014-11-26 08:24:40 -0600825 $.each(compilers, function (index, arg) {
Matt Godboltf4e76d22015-01-22 07:22:25 -0600826 compilersById[arg.id] = arg;
827 if (arg.alias) compilersByAlias[arg.alias] = arg;
Matt Godbolt3b391412016-03-27 12:04:52 -0500828 var elem = $('<li><a href="#">' + arg.name + '</a></li>');
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +0200829 slot.node.find('.compilers').append(elem);
Matt Godbolt3b391412016-03-27 12:04:52 -0500830 (function () {
Gabriel Devillers68379dd2016-08-04 15:43:12 +0200831 elem.click(function (e) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500832 setCompilerById(arg.id, slot);
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200833 onCompilerChange(slot);
Gabriel Devillers68379dd2016-08-04 15:43:12 +0200834
835 // do not bring user to the top of index.html
836 e.preventDefault();
Matt Godbolt3b391412016-03-27 12:04:52 -0500837 });
838 })(elem.find("a"), arg.id);
Matt Godbolt5be62682012-06-20 14:46:45 -0500839 });
Matt Godbolt32e742e2016-08-06 15:20:03 -0500840 var compiler = getSetting('compiler' + slot.id);
Gabriel Devillersb70d82e2016-07-04 17:06:29 +0200841 if (!compiler) {
842 compiler = defaultCompiler;
843 compiler = mapCompiler(compiler);
844 if (!compiler)
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200845 console.log("Could not map the default compiler id. " +
Matt Godbolt32e742e2016-08-06 15:20:03 -0500846 "Please double check your configuration file.");
Gabriel Devillersb70d82e2016-07-04 17:06:29 +0200847 } else {
848 compiler = mapCompiler(compiler);
849 if (!compiler)
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200850 console.log("Could not map the compiler found in settings. " +
Matt Godbolt32e742e2016-08-06 15:20:03 -0500851 "Please clear your browser cache.");
Gabriel Devillersb70d82e2016-07-04 17:06:29 +0200852 }
Matt Godboltf4e76d22015-01-22 07:22:25 -0600853 if (compiler) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500854 setCompilerById(compiler, slot);
Matt Godbolt42945b42012-07-06 06:22:11 -0500855 }
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200856 onCompilerChange(slot);
857 }
858
859 function setCompilers(compilers, defaultCompiler) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500860 console.log("[INIT] setCompilers() was called with compilers = " +
861 JSON.stringify(compilers) + ", defaultCompiler = " + defaultCompiler);
Gabriel Devillers39966c72016-08-01 17:29:11 +0200862 for (var i = 0; i < slots.length; i++) {
Matt Godbolt32e742e2016-08-06 15:20:03 -0500863 (function (slot) {
864 setCompilersInSlot(compilers, defaultCompiler, slot);
Gabriel Devillers39966c72016-08-01 17:29:11 +0200865 })(slots[i]);
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200866 }
Matt Godbolt5be62682012-06-20 14:46:45 -0500867 }
868
Matt Godboltb8fca032015-11-28 13:46:39 -0600869 function currentFilters() {
870 return patchUpFilters(filters_);
871 }
Matt Godbolt3b391412016-03-27 12:04:52 -0500872
Matt Godbolt77006912012-06-28 06:12:41 -0500873 function setFilters(f) {
Matt Godboltb8fca032015-11-28 13:46:39 -0600874 filters_ = $.extend({}, f);
Gabriel Devillers39966c72016-08-01 17:29:11 +0200875 slots.forEach(function (slot) {
Gabriel Devillersfdbf39f2016-08-01 15:40:07 +0200876 onParamChange(slot);
Gabriel Devillers28ef7682016-06-27 11:29:35 +0200877 updateCompilerAndButtons(slot);
Gabriel Devillers39966c72016-08-01 17:29:11 +0200878 });
Matt Godbolt77006912012-06-28 06:12:41 -0500879 }
880
Gabriel Devillers27189212016-07-04 17:17:39 +0200881 // External wrapper used by gcc.js only
882 function refreshSlot(slot) {
883 onCompilerChange(slot);
884 }
Matt Godbolt32e742e2016-08-06 15:20:03 -0500885
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200886 // Auxiliary function to slotUseDom
887 function generateChangeCallback(slot) {
Gabriel Devillers39966c72016-08-01 17:29:11 +0200888 return function callback() {
889 onParamChange(slot);
890 }
891 }
Gabriel Devillers27189212016-07-04 17:17:39 +0200892
Gabriel Devillers0586ec42016-08-03 10:32:50 +0200893 // must be called *before* doing slot = leaderSlot;
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200894 function setLeaderSlotIcon(slot) {
895 console.log("[UI] Toggling icon(s)...");
896
897 // source for javascript unicode escape codes:
898 // http://www.fileformat.info/info/unicode/char/search.htm
899 // to convert a character to JS/HTML/CSS/URIs... escape code:
900 // https://r12a.github.io/apps/conversion/
Gabriel Devillers0586ec42016-08-03 10:32:50 +0200901
902 // accessKey property : www.w3schools.com/jsref/prop_html_accesskey.asp
Matt Godbolt32e742e2016-08-06 15:20:03 -0500903
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200904 var selectedIcon = "\u2605"; // Unicode character: full star
905 var unselectedIcon = "\u2606"; // Unicode character: empty star
906 // you must keep those characters in sync with the template
907 // slotTemplate in index.html
Matt Godbolt32e742e2016-08-06 15:20:03 -0500908
Gabriel Devillers0586ec42016-08-03 10:32:50 +0200909 // if there was a leaderSlot,
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200910 if (leaderSlot != null) {
Gabriel Devillers0586ec42016-08-03 10:32:50 +0200911 // toggle icon in previous leaderSlot:
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +0200912 var prevIcon = leaderSlot.node.find('.leaderSlotIcon');
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200913 prevIcon.text(unselectedIcon);
914 prevIcon.addClass("unselectedCharacterIcon");
915 prevIcon.removeClass("selectedCharacterIcon");
Gabriel Devillers0586ec42016-08-03 10:32:50 +0200916
917 // removes access key in previous leaderSlot
Matt Godbolt32e742e2016-08-06 15:20:03 -0500918 leaderSlot.node.find('.compiler-selection').prop("accessKey", "");
919 leaderSlot.node.find('.compiler-options').prop("accessKey", "");
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200920 }
921
Gabriel Devillers0586ec42016-08-03 10:32:50 +0200922 // toggles the new icon
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +0200923 var newIcon = slot.node.find('.leaderSlotIcon');
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200924 newIcon.text(selectedIcon);
925 newIcon.addClass("selectedCharacterIcon");
926 newIcon.removeClass("unselectedCharacterIcon");
Gabriel Devillers0586ec42016-08-03 10:32:50 +0200927
928 // enables accesskeys in the leaderSlot
Matt Godbolt32e742e2016-08-06 15:20:03 -0500929 slot.node.find('.compiler-selection').prop("accessKey", "c");
930 slot.node.find('.compiler-options').prop("accessKey", "o");
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200931 }
932
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200933 // Function to call each time a slot is added to the page.
934 // This function requires that the slot's DOM object already exists.
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200935 function slotUseDom(slot) {
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200936 slot.asmCodeMirror = CodeMirror.fromTextArea(
Matt Godbolt32e742e2016-08-06 15:20:03 -0500937 slot.node.find(".asm textarea")[0], {
938 lineNumbers: true,
939 mode: "text/x-asm",
940 readOnly: true,
941 gutters: ['CodeMirror-linenumbers'],
942 lineWrapping: true
943 });
Gabriel Devillers39966c72016-08-01 17:29:11 +0200944 // handle compiler option (slot specific) such as '-O1'
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200945 slot.node.find('.compiler-options').change(
946 generateChangeCallback(slot)).keyup(
947 generateChangeCallback(slot));
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200948
Matt Godbolt32e742e2016-08-06 15:20:03 -0500949 slot.node.find('.leaderSlotIcon').on('click', function (e) {
950 console.log("[UI] Clicked on leaderSlotIcon in slot " + slot.id);
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200951 if (slot != leaderSlot) {
952 clearBackground(leaderSlot.asmCodeMirror);
953
954 setLeaderSlotIcon(slot);
955 leaderSlot = slot;
Gabriel Devillersa5857b92016-08-02 13:24:37 +0200956 setSetting('leaderSlot', slot.id);
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200957 onParamChange(slot, true);
958 }
Gabriel Devillers68379dd2016-08-04 15:43:12 +0200959
960 // do not bring user to the top of index.html
961 e.preventDefault();
Gabriel Devillers6d94cab2016-07-29 15:44:31 +0200962 });
963
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200964 if (slots.length == 1) {
965 // "force" menu update if this is the first slot added
966 var leaderSlotMenuNode = domRoot.find('#commonParams .leaderSlot');
Matt Godbolt32e742e2016-08-06 15:20:03 -0500967 leaderSlotMenuNode.text('leader slot : ' + slots[0].id);
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200968 }
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200969 }
970
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200971 function diffUseDom(diff) {
Gabriel Devillers711af7a2016-08-01 14:47:12 +0200972 diff.asmCodeMirror = CodeMirror.fromTextArea(
Matt Godbolt32e742e2016-08-06 15:20:03 -0500973 diff.node.find('.diffText textarea')[0], {
974 lineNumbers: true,
975 mode: "text/x-asm",
976 readOnly: true,
977 gutters: ['CodeMirror-linenumbers'],
978 lineWrapping: true
979 });
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +0200980 var reverseDiffButton = diff.node.find('.reverse-diff');
Matt Godbolt32e742e2016-08-06 15:20:03 -0500981 reverseDiffButton.on('click', function (e) {
982 console.log("[UI] User clicked on reverse-diff button in diff " + diff.id);
Gabriel Devillers43d3d992016-07-29 17:29:56 +0200983 var tmp = diff.beforeSlot;
984 diff.beforeSlot = diff.afterSlot;
985 diff.afterSlot = tmp;
Gabriel Devillersece67892016-08-03 14:49:14 +0200986 setSlotInDiff(diff, "before", diff.beforeSlot);
987 setSlotInDiff(diff, "after", diff.afterSlot);
Gabriel Devillers43d3d992016-07-29 17:29:56 +0200988 setDiffSlotsMenus(diff);
Matt Godbolt32e742e2016-08-06 15:20:03 -0500989 onDiffChange(diff, false);
Gabriel Devillers68379dd2016-08-04 15:43:12 +0200990
991 // do not bring user to the top of index.html
992 e.preventDefault();
Gabriel Devillers43d3d992016-07-29 17:29:56 +0200993 });
Gabriel Devillers27189212016-07-04 17:17:39 +0200994 }
Gabriel Devillers39966c72016-08-01 17:29:11 +0200995
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +0200996 function getSlotsIds() {
Gabriel Devillers27463ac2016-07-01 17:09:18 +0200997 var ids = [];
998 for (var i = 0; i < slots.length; i++) {
999 ids.push(slots[i].id);
1000 }
1001 return ids;
1002 }
1003
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001004 // TODO : refactor !
Gabriel Devillersece67892016-08-03 14:49:14 +02001005 function getDiffsIds() {
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001006 var ids = [];
1007 for (var i = 0; i < diffs.length; i++) {
1008 ids.push(diffs[i].id);
1009 }
1010 return ids;
1011 }
1012
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001013 function slotCtor(optionalId) {
Gabriel Devillers39966c72016-08-01 17:29:11 +02001014 var newSlot = new Slot();
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001015 if (optionalId) {
1016 newSlot.id = optionalId;
1017 } else {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001018 newSlot.id = getAvailableId(slots);
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001019 }
Gabriel Devillers39966c72016-08-01 17:29:11 +02001020 slots.push(newSlot);
Matt Godbolt32e742e2016-08-06 15:20:03 -05001021 setSetting('slotIds', JSON.stringify(getSlotsIds()));
Gabriel Devillers39966c72016-08-01 17:29:11 +02001022 return newSlot;
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001023 }
1024
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001025 function diffCtor(optionalId) {
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001026 var newDiff = new Diff();
1027 if (optionalId) {
1028 newDiff.id = optionalId;
1029 } else {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001030 newDiff.id = getAvailableId(diffs);
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001031 }
1032 diffs.push(newDiff);
Matt Godbolt32e742e2016-08-06 15:20:03 -05001033 setSetting('diffIds', JSON.stringify(getDiffsIds()));
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001034 return newDiff;
Gabriel Devillers39966c72016-08-01 17:29:11 +02001035 }
Matt Godbolt32e742e2016-08-06 15:20:03 -05001036
Gabriel Devillers39966c72016-08-01 17:29:11 +02001037 // Array Remove - By John Resig (MIT Licensed)
Matt Godbolt32e742e2016-08-06 15:20:03 -05001038 Array.prototype.remove = function (from, to) {
Gabriel Devillers39966c72016-08-01 17:29:11 +02001039 var rest = this.slice((to || from) + 1 || this.length);
1040 this.length = from < 0 ? this.length + from : from;
1041 return this.push.apply(this, rest);
1042 };
1043
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001044 function removeIdInArray(id, array) {
Matt Godbolt32e742e2016-08-06 15:20:03 -05001045 for (var i = 0; i < array.length; i++) {
Gabriel Devillers39966c72016-08-01 17:29:11 +02001046 if (array[i].id == id) {
1047 array.remove(i);
1048 break;
1049 }
1050 }
1051 }
1052
Matt Godbolt32e742e2016-08-06 15:20:03 -05001053 function anotherSlot(slot) {
Gabriel Devillers6d94cab2016-07-29 15:44:31 +02001054 for (var i = 0; i < slots.length; i++) {
1055 if (slots[i] != slot) {
1056 return slots[i];
1057 }
1058 }
1059 return null; // should not happen (at least 1 slot is open)
1060 }
1061
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001062 function slotDtor(slot) {
Gabriel Devillers6d94cab2016-07-29 15:44:31 +02001063 // if slot is the leader, find a new leader and change the icon
Gabriel Devillers32475792016-08-04 09:52:50 +02001064 if (slots.length > 1) {
Matt Godbolt51ae5482016-08-06 14:46:47 -05001065 leaderSlot = anotherSlot(slot);
Gabriel Devillers32475792016-08-04 09:52:50 +02001066 setLeaderSlotIcon(leaderSlot);
1067 setSetting('leaderSlot', leaderSlot.id);
1068 }
Gabriel Devillers6d94cab2016-07-29 15:44:31 +02001069
Gabriel Devillers37076eb2016-08-04 14:13:05 +02001070 // hide the close-slot icon if there will remain 1 slot
1071 if (slots.length <= 2) {
Gabriel Devillers17e36092016-08-04 17:06:44 +02001072 domRoot.find('.slot .closeButton').fadeOut(550);
Gabriel Devillers37076eb2016-08-04 14:13:05 +02001073 }
1074
Gabriel Devillers6d94cab2016-07-29 15:44:31 +02001075 // now safely delete:
Matt Godbolt32e742e2016-08-06 15:20:03 -05001076 removeSetting('compiler' + slot.id);
1077 removeSetting('compilerOptions' + slot.id);
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001078 removeIdInArray(slot.id, slots);
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001079 // after the deletion, update the browser's settings :
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001080 setSetting('slotIds', JSON.stringify(getSlotsIds()));
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001081 }
1082
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001083 function diffDtor(diff) {
1084 removeIdInArray(diff.id, diffs);
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001085 // after the deletion, update the browser's settings :
Gabriel Devillersece67892016-08-03 14:49:14 +02001086 setSetting('diffIds', JSON.stringify(getDiffsIds()));
Gabriel Devillers39966c72016-08-01 17:29:11 +02001087 }
1088
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001089 function getSlotById(slotId) {
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001090 for (var i = 0; i < slots.length; i++) {
Gabriel Devillers39966c72016-08-01 17:29:11 +02001091 if (slots[i].id == slotId) return slots[i];
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001092 }
1093 return null;
1094 }
1095
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001096 function getDiffById(diffId) {
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001097 for (var i = 0; i < diffs.length; i++) {
1098 if (diffs[i].id == diffId) return diffs[i];
Gabriel Devillers39966c72016-08-01 17:29:11 +02001099 }
1100 return null;
1101 }
1102
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001103 function setPanelListSortable() {
1104 // source : JQuery UI examples
1105 var panelList = $('#draggablePanelList');
1106 panelList.sortable({
Matt Godbolt32e742e2016-08-06 15:20:03 -05001107 handle: '.panel-heading',
1108 update: function () {
1109 $('.panel', panelList).each(function (index, elem) {
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001110 var $listItem = $(elem),
Matt Godbolt32e742e2016-08-06 15:20:03 -05001111 newIndex = $listItem.index();
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001112
Matt Godbolt32e742e2016-08-06 15:20:03 -05001113 // TODO Persist the new indices.
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001114 });
1115 }
1116 });
Matt Godbolt889cf272016-08-16 06:59:46 -05001117 $('.resizable:visible').resizable(
1118 {
1119 resize: resizeOutputs,
1120 minHeight: 300,
1121 minWidth: 300,
1122 alsoResize: ".resizable:visible"
1123 }
1124 );
1125 $('.resizable-e:visible').resizable({handles: 'e'});
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001126 }
1127
Gabriel Devillers17e36092016-08-04 17:06:44 +02001128 function slotDomCtor(slot, onUserAction) {
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001129 // source : http://stackoverflow.com/questions/10126395/how-to-jquery-clone-and-change-id
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +02001130 var slotTemplate = domRoot.find('#slotTemplate');
Matt Godbolt32e742e2016-08-06 15:20:03 -05001131 var clone = slotTemplate.clone().prop('id', 'slot' + slot.id);
Gabriel Devillers1dfd4092016-08-04 11:45:35 +02001132
1133 // Insert the slot in the list of panels
1134 // domRoot.find('#slotTemplate').after(clone);
1135 domRoot.find('#draggablePanelList').append(clone);
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001136
Matt Godbolt32e742e2016-08-06 15:20:03 -05001137 slot.node = domRoot.find('#slot' + slot.id);
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +02001138
Matt Godbolt32e742e2016-08-06 15:20:03 -05001139 slot.node.find('.title').text("Slot " + slot.id + " (drag me) ");
Gabriel Devillers17e36092016-08-04 17:06:44 +02001140
1141 if (onUserAction) {
1142 slot.node.fadeIn(550);
1143 } else {
1144 // auto spawn of the panel: no need to fade in
1145 slot.node.show();
1146 }
1147
Matt Godbolt32e742e2016-08-06 15:20:03 -05001148 slot.node.find('.closeButton').on('click', function (e) {
1149 console.log("[UI] User clicked on closeButton in slot " + slot.id);
Gabriel Devillers37076eb2016-08-04 14:13:05 +02001150 var slotToDelete = getSlotById(slot.id);
Gabriel Devillers17e36092016-08-04 17:06:44 +02001151 deleteAndUnplaceSlot(slotToDelete, true);
Gabriel Devillers68379dd2016-08-04 15:43:12 +02001152
1153 // do not bring user to the top of index.html
1154 e.preventDefault();
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001155 });
Gabriel Devillers37076eb2016-08-04 14:13:05 +02001156
1157 // show the close-slot icons if there will be more than 1 slot
1158 if (slots.length == 1) {
Gabriel Devillers17e36092016-08-04 17:06:44 +02001159 domRoot.find('.slot .closeButton').fadeOut(550);
Gabriel Devillers37076eb2016-08-04 14:13:05 +02001160 }
1161 if (slots.length == 2) {
Gabriel Devillers17e36092016-08-04 17:06:44 +02001162 domRoot.find('.slot .closeButton').fadeIn(550);
Gabriel Devillers37076eb2016-08-04 14:13:05 +02001163 }
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001164
1165 setPanelListSortable();
1166 }
1167
Gabriel Devillers17e36092016-08-04 17:06:44 +02001168 function diffDomCtor(diff, onUserAction) {
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +02001169 var diffTemplate = domRoot.find('#diffTemplate');
Matt Godbolt32e742e2016-08-06 15:20:03 -05001170 var clone = diffTemplate.clone().prop('id', 'diff' + diff.id);
Gabriel Devillers1dfd4092016-08-04 11:45:35 +02001171
1172 // Insert the diff in the list of panels
1173 // domRoot.find('#diffTemplate').after(clone);
1174 domRoot.find('#draggablePanelList').append(clone);
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001175
Matt Godbolt32e742e2016-08-06 15:20:03 -05001176 diff.node = domRoot.find('#diff' + diff.id);
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +02001177
Matt Godbolt32e742e2016-08-06 15:20:03 -05001178 diff.node.find('.title').text("Diff " + diff.id + " (drag me) ");
Gabriel Devillers17e36092016-08-04 17:06:44 +02001179
1180 if (onUserAction) {
1181 diff.node.fadeIn(550);
1182 } else {
1183 // auto spawn of the panel: no need to fade in
1184 diff.node.show();
1185 }
1186
Matt Godbolt32e742e2016-08-06 15:20:03 -05001187 diff.node.find('.closeButton').on('click', function (e) {
1188 console.log("[UI] User clicked on closeButton in diff " + diff.id);
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001189 var diffToDelete = getDiffById(diff.id);
Gabriel Devillers17e36092016-08-04 17:06:44 +02001190 deleteAndUnplaceDiff(diffToDelete, true);
Gabriel Devillers68379dd2016-08-04 15:43:12 +02001191 // do not bring user to the top of index.html
1192 e.preventDefault();
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001193 });
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001194
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001195 setPanelListSortable();
1196 setDiffSlotsMenus(diff);
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001197 }
1198
Gabriel Devillers17e36092016-08-04 17:06:44 +02001199 function slotDomDtor(slot, onUserAction) {
1200 if (onUserAction) {
1201 slot.node.fadeOut(550, function () {
1202 slot.node.remove();
1203 });
1204 } else {
1205 slot.node.remove();
1206 }
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001207 }
1208
Gabriel Devillers17e36092016-08-04 17:06:44 +02001209 function diffDomDtor(diff, onUserAction) {
1210 if (onUserAction) {
1211 diff.node.fadeOut(550, function () {
1212 diff.node.remove();
1213 });
1214 } else {
1215 diff.node.remove();
1216 }
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001217 }
1218
Matt Godbolt889cf272016-08-16 06:59:46 -05001219 function ensureAllSlotsSameSize() {
1220 var allResizable = $('.resizable:visible');
1221 var w = allResizable.width();
1222 var h = allResizable.height();
1223 allResizable.width(w);
1224 allResizable.height(h);
1225 }
1226
Gabriel Devillers17e36092016-08-04 17:06:44 +02001227 function createAndPlaceSlot(compilers, defaultCompiler, optionalId, onUserAction) {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001228 var newSlot = slotCtor(optionalId);
Gabriel Devillers17e36092016-08-04 17:06:44 +02001229 slotDomCtor(newSlot, onUserAction);
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001230 slotUseDom(newSlot);
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001231 setCompilersInSlot(compilers, defaultCompiler, newSlot);
Matt Godbolt889cf272016-08-16 06:59:46 -05001232 ensureAllSlotsSameSize();
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001233 return newSlot;
1234 }
1235
Gabriel Devillers17e36092016-08-04 17:06:44 +02001236 function createAndPlaceDiff(optionalId, onUserAction) {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001237 var newDiff = diffCtor(optionalId);
Gabriel Devillers17e36092016-08-04 17:06:44 +02001238 diffDomCtor(newDiff, onUserAction);
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001239 diffUseDom(newDiff);
Matt Godbolt889cf272016-08-16 06:59:46 -05001240 ensureAllSlotsSameSize();
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001241 return newDiff;
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001242 }
1243
Gabriel Devillers17e36092016-08-04 17:06:44 +02001244 function createAndPlaceDiffUI(optionalId, onUserAction) {
1245 var newDiff = createAndPlaceDiff(optionalId, onUserAction);
Gabriel Devillers48c6e8d2016-07-25 12:29:13 +02001246 if (slots.length > 0) {
Matt Godbolt32e742e2016-08-06 15:20:03 -05001247 setSlotInDiff(newDiff, "before", slots[0]);
Gabriel Devillers48c6e8d2016-07-25 12:29:13 +02001248 if (slots.length > 1) {
Matt Godbolt32e742e2016-08-06 15:20:03 -05001249 setSlotInDiff(newDiff, "after", slots[1]);
Gabriel Devillers48c6e8d2016-07-25 12:29:13 +02001250 } else {
Matt Godbolt32e742e2016-08-06 15:20:03 -05001251 setSlotInDiff(newDiff, "after", slots[0]);
Gabriel Devillers48c6e8d2016-07-25 12:29:13 +02001252 }
Gabriel Devillers7a8fec32016-07-28 10:32:29 +02001253 onDiffChange(newDiff, false);
Gabriel Devillers48c6e8d2016-07-25 12:29:13 +02001254 }
1255 return newDiff;
1256 }
1257
Gabriel Devillers17e36092016-08-04 17:06:44 +02001258 function deleteAndUnplaceSlot(slot, onUserAction) {
1259 slotDomDtor(slot, onUserAction);
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001260 slotDtor(slot);
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001261 }
1262
Gabriel Devillers17e36092016-08-04 17:06:44 +02001263 function deleteAndUnplaceDiff(diff, onUserAction) {
1264 diffDomDtor(diff, onUserAction);
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001265 diffDtor(diff);
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001266 }
1267
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001268 // refresh (or place) the two drop-down lists of the diff panel containging
1269 // descriptions of the slots that can be used to make a diff
1270
Gabriel Devillersece67892016-08-03 14:49:14 +02001271 function updateDiffButton(diff, className) {
Matt Godbolt32e742e2016-08-06 15:20:03 -05001272 var slot = diff[className + 'Slot'];
1273 var diffSlotMenuNode = diff.node.find('.' + className + ' .slotName');
Gabriel Devillers68379dd2016-08-04 15:43:12 +02001274 diffSlotMenuNode.text(slot.shortDescription());
Gabriel Devillersece67892016-08-03 14:49:14 +02001275 }
1276
1277 // this function is called if the name or option of a compiler is changed.
1278 function updateDiffUI(diff) {
1279 updateDiffButton(diff, "before");
1280 updateDiffButton(diff, "after");
1281 setDiffSlotsMenus(diff);
1282 }
1283
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001284 // Auxilary to setDiffSlotsMenus and deserialisation
Gabriel Devillersece67892016-08-03 14:49:14 +02001285 function setSlotInDiff(diff, className, slot) {
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001286 // className can be "before" or "after"
Gabriel Devillers48c6e8d2016-07-25 12:29:13 +02001287 if (slot == null) {
Gabriel Devillersece67892016-08-03 14:49:14 +02001288 console.log("[DEBUG] setSlotInDiff: diff.id = " +
Matt Godbolt32e742e2016-08-06 15:20:03 -05001289 diff.id + ", " + className + " -> " + "null.id");
Gabriel Devillers48c6e8d2016-07-25 12:29:13 +02001290 } else {
Gabriel Devillersece67892016-08-03 14:49:14 +02001291 console.log("[DEBUG] setSlotInDiff: diff.id = " +
Matt Godbolt32e742e2016-08-06 15:20:03 -05001292 diff.id + ", " + className + " -> " + slot.id);
Gabriel Devillers48c6e8d2016-07-25 12:29:13 +02001293 }
Matt Godbolt32e742e2016-08-06 15:20:03 -05001294 diff[className + 'Slot'] = slot;
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001295 if (slot != null) {
Gabriel Devillersece67892016-08-03 14:49:14 +02001296 updateDiffButton(diff, className);
1297
Matt Godbolt32e742e2016-08-06 15:20:03 -05001298 setSetting('diff' + diff.id + className, slot.id);
Gabriel Devillersece67892016-08-03 14:49:14 +02001299
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001300 addToPendings(slot, diff);
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001301 }
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001302 }
1303
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001304 function setDiffSlotsMenus(diff) {
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001305 // className can be "before" or "after"
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001306 function setSlotMenu(className) {
Matt Godbolt32e742e2016-08-06 15:20:03 -05001307 console.log("[DEBUG] : setSlotMenu with " + className +
1308 " and diff.id = " + diff.id);
1309 diff.node.find('.' + className + ' li').remove();
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001310 for (var i = 0; i < slots.length; i++) {
Gabriel Devillersece67892016-08-03 14:49:14 +02001311 var elem = $('<li><a href="#">' + slots[i].description() + '</a></li>');
Matt Godbolt32e742e2016-08-06 15:20:03 -05001312 diff.node.find('.' + className + ' .slotNameList').append(elem);
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001313 (function (i) {
Gabriel Devillers68379dd2016-08-04 15:43:12 +02001314 elem.click(function (e) {
Gabriel Devillersf6a5dd12016-08-02 14:08:46 +02001315 // TODO: check if modifying diff with [] will survive to
Gabriel Devillers711af7a2016-08-01 14:47:12 +02001316 // minifying http://stackoverflow.com/questions/4244896/
Matt Godbolt32e742e2016-08-06 15:20:03 -05001317 console.log("[UI] user set " + slots[i].id + " as " + className +
1318 " slot in diff with id " + diff.id);
Gabriel Devillersece67892016-08-03 14:49:14 +02001319 setSlotInDiff(diff, className, slots[i]);
Gabriel Devillers7a8fec32016-07-28 10:32:29 +02001320 onDiffChange(diff, false);
Gabriel Devillers68379dd2016-08-04 15:43:12 +02001321
1322 // do not bring user to the top of index.html
1323 e.preventDefault();
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001324 });
1325 })(i);
1326 }
1327 }
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001328
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001329 setSlotMenu("before");
1330 setSlotMenu("after");
1331 }
1332
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001333 // refresh (or place) all of the drop-down lists containging descriptions of
1334 // the slots that can be used to make a diff
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001335 function setAllDiffSlotsMenus() {
Matt Godbolt32e742e2016-08-06 15:20:03 -05001336 console.log("[DEBUG] : inside setAllDiffSlotsMenus, diffs.length = " + diffs.length);
1337 for (var i = 0; i < diffs.length; i++) {
Gabriel Devillersa49e0e92016-07-18 14:36:57 +02001338 setDiffSlotsMenus(diffs[i]);
1339 }
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001340 }
1341
Gabriel Devillers39966c72016-08-01 17:29:11 +02001342 // on startup, for each slot,
1343 // if a setting is defined, set it on static/index.html page
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001344 var slotIds = getSetting('slotIds');
Gabriel Devillers7a8fec32016-07-28 10:32:29 +02001345 if (slotIds != null) {
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001346 slotIds = JSON.parse(slotIds);
Gabriel Devillers7a8fec32016-07-28 10:32:29 +02001347 } else {
1348 slotIds = [];
1349 }
Matt Godbolt51ae5482016-08-06 14:46:47 -05001350 var i, newSlot;
Gabriel Devillers7a8fec32016-07-28 10:32:29 +02001351 if (slotIds.length > 0) {
1352 console.log("[STARTUP] found slot data : restoring from previous session");
Matt Godbolt32e742e2016-08-06 15:20:03 -05001353 console.log("[DEBUG] slotIds: " + JSON.stringify(slotIds));
Matt Godbolt51ae5482016-08-06 14:46:47 -05001354 for (i = 0; i < slotIds.length; i++) {
1355 newSlot = slotCtor(slotIds[i]);
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001356 slotDomCtor(newSlot);
1357 slotUseDom(newSlot);
Matt Godbolt32e742e2016-08-06 15:20:03 -05001358 if (getSetting('compilerOptions' + slotIds[i]) === undefined) {
Gabriel Devillersece67892016-08-03 14:49:14 +02001359 console.log("[STARTUP] There was a problem while restoring slots from previous session.");
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001360 } else {
Matt Godbolt32e742e2016-08-06 15:20:03 -05001361 newSlot.node.find('.compiler-options').val(getSetting('compilerOptions' + newSlot.id));
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001362 }
1363 }
Matt Godbolt32e742e2016-08-06 15:20:03 -05001364 var leaderSlotSetting = getSetting('leaderSlot');
1365 if (!leaderSlotSetting) {
1366 console.log("Leader slot was missing; picking first");
1367 leaderSlot = getSlotById(0);
1368 } else {
1369 leaderSlot = getSlotById(leaderSlotSetting);
1370 }
1371 if (leaderSlot) setLeaderSlotIcon(leaderSlot);
Gabriel Devillers2e057e52016-07-29 11:39:05 +02001372 } else {
Gabriel Devillers2e057e52016-07-29 11:39:05 +02001373 // not slot data found. It is probably the first time the user come to
1374 // visit (or to debug a wipeSetting(); was done in the browser console)
1375 // therefore it seems logical to open at least 1 slot
Matt Godbolt32e742e2016-08-06 15:20:03 -05001376 leaderSlot = createAndPlaceSlot(compilers, defaultCompiler);
Gabriel Devillersa5857b92016-08-02 13:24:37 +02001377 setSetting('leaderSlot', leaderSlot.id);
Gabriel Devillers6d94cab2016-07-29 15:44:31 +02001378 setLeaderSlotIcon(leaderSlot);
Gabriel Devillers27463ac2016-07-01 17:09:18 +02001379 }
Gabriel Devillers2e057e52016-07-29 11:39:05 +02001380
Gabriel Devillersece67892016-08-03 14:49:14 +02001381 // This part of the initialisation must (currently) occur
1382 // after the creation of slots, and before the creation of diffs.
1383 // Previously it was located in gcc.js, in Initialize()
1384 setCompilers(compilers, defaultCompiler);
Matt Godbolt32e742e2016-08-06 15:20:03 -05001385
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001386 // on startup, for each diff,
1387 // if a setting is defined, set it on static/index.html page
1388 var diffIds = getSetting('diffIds');
Gabriel Devillers7a8fec32016-07-28 10:32:29 +02001389 if (diffIds != null) {
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001390 diffIds = JSON.parse(diffIds);
Gabriel Devillers7a8fec32016-07-28 10:32:29 +02001391 } else {
1392 diffIds = [];
1393 }
Gabriel Devillersece67892016-08-03 14:49:14 +02001394 console.log("[DEBUG] diffIds: " + JSON.stringify(diffIds));
Gabriel Devillers7a8fec32016-07-28 10:32:29 +02001395 if (diffIds.length > 0) {
Gabriel Devillersece67892016-08-03 14:49:14 +02001396 console.log("[STARTUP] found diff data : restoring diffs from previous session");
Matt Godbolt51ae5482016-08-06 14:46:47 -05001397 for (i = 0; i < diffIds.length; i++) {
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001398 var newDiff = createAndPlaceDiff(diffIds[i]);
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001399
Matt Godbolt32e742e2016-08-06 15:20:03 -05001400 newDiff.beforeSlot = getSlotById(getSetting('diff' + newDiff.id + "before"));
Gabriel Devillersece67892016-08-03 14:49:14 +02001401 setSlotInDiff(newDiff, "before", newDiff.beforeSlot);
1402 addToPendings(newDiff.beforeSlot, newDiff);
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001403
Matt Godbolt32e742e2016-08-06 15:20:03 -05001404 newDiff.afterSlot = getSlotById(getSetting('diff' + newDiff.id + "after"));
Gabriel Devillersece67892016-08-03 14:49:14 +02001405 setSlotInDiff(newDiff, "after", newDiff.afterSlot);
1406 addToPendings(newDiff.afterSlot, newDiff);
Gabriel Devillers48c6e8d2016-07-25 12:29:13 +02001407 //onDiffChange(newDiff);
Gabriel Devillers60c04b12016-07-25 11:25:06 +02001408 }
1409 }
Gabriel Devillers27189212016-07-04 17:17:39 +02001410
Matt Godbolt889cf272016-08-16 06:59:46 -05001411 function resizeOutputs() {
1412 function doResize(cm) {
1413 var parent = $(cm.getTextArea()).parent().find(".CodeMirror");
1414 var container = parent.closest(".panel");
1415 var containerSize = container.height();
1416 var top = parent.position().top;
Matt Godboltd93da762016-08-17 20:46:56 -05001417 var footerHeight = container.find('.panel-footer').height() || 0;
1418 // TODO - padding!
1419 cm.setSize(null, containerSize - top - footerHeight);
Matt Godbolt889cf272016-08-16 06:59:46 -05001420 }
1421 _.each(slots, function(slot) { doResize(slot.asmCodeMirror); });
1422 _.each(diffs, function(slot) { doResize(slot.asmCodeMirror); });
1423 }
1424
1425 function resize(windowHeight) {
1426 var editor = $(cppEditor.getTextArea()).parent();
1427 var top = editor.offset().top;
Matt Godboltd93da762016-08-17 20:46:56 -05001428 // TODO: a total rethink here. kill output/result etc
1429 // make errors a pop-up-able thing?
1430 // var compOutputSize = Math.max(100, windowHeight * 0.05);
1431 // $('.output').height(compOutputSize);
1432 // var resultHeight = $('.result').height();
1433 var height = windowHeight - top;// - resultHeight - 10;
Matt Godbolt889cf272016-08-16 06:59:46 -05001434 cppEditor.setSize(null, height);
1435 resizeOutputs();
1436 }
1437
Matt Godbolt5be62682012-06-20 14:46:45 -05001438 return {
Matt Godbolt35156ff2012-07-09 06:56:11 -05001439 serialiseState: serialiseState,
Matt Godbolt5be62682012-06-20 14:46:45 -05001440 deserialiseState: deserialiseState,
Matt Godbolt186cabb2012-06-20 15:05:59 -05001441 getSource: getSource,
Matt Godbolt77006912012-06-28 06:12:41 -05001442 setSource: setSource,
Matt Godbolt9b873172013-02-07 07:30:10 -06001443 setFilters: setFilters,
Gabriel Devillers6d7e68c2016-08-02 17:34:39 +02001444 createAndPlaceSlot: createAndPlaceSlot,
1445 createAndPlaceDiffUI: createAndPlaceDiffUI,
Matt Godbolt889cf272016-08-16 06:59:46 -05001446 refreshSlot: refreshSlot,
1447 resize: resize
Matt Godbolt5be62682012-06-20 14:46:45 -05001448 };
1449}