diff --git a/_includes/editor.js b/_includes/editor.js new file mode 100644 index 000000000..72332b6ba --- /dev/null +++ b/_includes/editor.js @@ -0,0 +1,243 @@ +(function () { + "use strict"; + // ECMAScript 6 Backwards compatability + if (typeof String.prototype.startsWith !== 'function') { + String.prototype.startsWith = function(str) { + return this.slice(0, str.length) === str; + }; + } + + // Regex for finding new lines + var newLineRegex = /(?:\r\n|\r|\n)/g; + + // Fetching DOM items + var activeCode = document.getElementById("active-code"); + var editorDiv = document.getElementById("editor"); + var staticCode = document.getElementById("static-code"); + var runButton = document.getElementById("run-code"); + var resultDiv = document.getElementById("result"); + var playLink = document.getElementById("playlink"); + + // Background colors for program result on success/error + var successColor = "#E2EEF6"; + var errorColor = "#F6E2E2"; + var warningColor = "#FFFBCB"; + + // Error message to return when there's a server failure + var errMsg = "The server encountered an error while running the program."; + + // Stores ACE editor markers (highights) for errors + var markers = []; + + // Status codes, because there are no enums in Javascript + var SUCCESS = 0; + var ERROR = 1; + var WARNING = 2; + + // JS exists, display ACE editor + staticCode.style.display = "none"; + activeCode.style.display = "block"; + + // Setting up ace editor + var editor = ace.edit("editor"); + var Range = ace.require('ace/range').Range; + editor.setTheme("ace/theme/chrome"); + editor.getSession().setMode("ace/mode/rust"); + editor.setShowPrintMargin(false); + editor.renderer.setShowGutter(false); + editor.setHighlightActiveLine(false); + + // Changes the height of the editor to match its contents + function updateEditorHeight() { + // http://stackoverflow.com/questions/11584061/ + var newHeight = editor.getSession().getScreenLength() + * editor.renderer.lineHeight + + editor.renderer.scrollBar.getWidth(); + + editorDiv.style.height = Math.ceil(newHeight).toString() + "px"; + editor.resize(); + } + + // Set initial size to match initial content + updateEditorHeight(); + + function escapeHTML(unsafe) { + return unsafe + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'") + .replace(newLineRegex, '
'); + } + + // Dispatches a XMLHttpRequest to the Rust playpen, running the program, and + // issues a callback to `callback` with the result (or null on error) + function runProgram(program, callback) { + var req = new XMLHttpRequest(); + var data = JSON.stringify({ + version: "master", + optimize: "2", + code: program + }); + + // console.log("Sending", data); + req.open('POST', "http://play.rust-lang.org/evaluate.json", true); + req.onload = function(e) { + if (req.readyState === 4 && req.status === 200) { + var result = JSON.parse(req.response).result; + + // Need server support to get an accurate version of this. + var statusCode = SUCCESS; + if (result.indexOf("error:") !== -1) { + statusCode = ERROR; + } else if (result.indexOf("warning:") !== -1) { + statusCode = WARNING; + } + + callback(statusCode, result); + } else { + callback(false, null); + } + }; + + req.onerror = function(e) { + callback(false, null); + }; + + req.setRequestHeader("Content-Type", "application/json"); + req.send(data); + } + + // The callback to runProgram + function handleResult(statusCode, message) { + // Dispatch depending on result type + if (result == null) { + resultDiv.style.backgroundColor = errorColor; + resultDiv.innerHTML = errMsg; + } else if (statusCode === SUCCESS) { + handleSuccess(message); + } else if (statusCode === WARNING) { + handleWarning(message); + } else { + handleError(message); + } + } + + // Called on successful program run: display output and playground icon + function handleSuccess(message) { + resultDiv.style.backgroundColor = successColor; + var program = encodeURIComponent(editor.getValue()); + // playLink.href = "http://play.rust-lang.org/?code=" + program + "&run=1" + // console.log(playLink.href); + resultDiv.innerHTML = ''; // clear resultDiv, then add + resultDiv.appendChild(playLink); // playLink icon and message + resultDiv.innerHTML += escapeHTML(message); + } + + // Called when program run results in warning(s) + function handleWarning(message) { + resultDiv.style.backgroundColor = warningColor; + handleProblem(message, "warning"); + } + + // Called when program run results in error(s) + function handleError(message) { + resultDiv.style.backgroundColor = errorColor; + handleProblem(message, "error"); + } + + // Called on unsuccessful program run. Detects and prints problems (either + // warnings or errors) in program output and highlights relevant lines and text + // in the code. + function handleProblem(message, problem) { + // Getting list of ranges with problems + var lines = message.split(newLineRegex); + + // Cleaning up the message: keeps only relevant problem output + var cleanMessage = lines.map(function(line) { + if (line.startsWith("") || line.indexOf("^") !== -1) { + var errIndex = line.indexOf(problem + ": "); + if (errIndex !== -1) {return line.slice(errIndex);} + return ""; + } + + // Discard playpen messages, keep the rest + if (line.startsWith("playpen:")) {return "";} + return line; + }).filter(function(line) { + return line !== ""; + }).map(function(line) { + return escapeHTML(line); + }).join("
"); + + // Setting message + var program = encodeURIComponent(editor.getValue()); + // playLink.href = "http://play.rust-lang.org/?code=" + program + "&run=1" + // console.log(playLink.href); + resultDiv.innerHTML = ''; // clear resultDiv, then add + resultDiv.appendChild(playLink); // playLink icon and error message + resultDiv.innerHTML += cleanMessage; + + // Highlighting the lines + var ranges = parseProblems(lines); + markers = ranges.map(function(range) { + return editor.getSession().addMarker(range, "ace-" + problem + "-line", + "fullLine", false); + }); + + // Highlighting the specific text + markers = markers.concat(ranges.map(function(range) { + return editor.getSession().addMarker(range, "ace-" + problem + "-text", + "text", false); + })); + } + + // Parses a problem message returning a list of ranges (row:col, row:col) where + // problems in the code have occured. + function parseProblems(lines) { + var ranges = []; + for (var i in lines) { + var line = lines[i]; + if (line.startsWith(":") && line.indexOf(": ") !== -1) { + var parts = line.split(/:\s?|\s+/, 5).slice(1, 5); + var ip = parts.map(function(p) { return parseInt(p, 10) - 1; }); + // console.log("line:", line, parts, ip); + ranges.push(new Range(ip[0], ip[1], ip[2], ip[3])); + } + } + + return ranges; + } + + // Registering handler for run button click + runButton.addEventListener("click", function(ev) { + resultDiv.style.display = "block"; + resultDiv.innerHTML = "Running..."; + + // clear previous markers, if any + markers.map(function(id) { editor.getSession().removeMarker(id); }); + + // Get the code, run the program + var program = editor.getValue(); + runProgram(program, handleResult); + }); + + // When clicking on the playground icon, navigate to the playground itself + function goPlayground() { + var program = "http://play.rust-lang.org/?code=" + + encodeURIComponent(editor.getValue()) + "&run=1"; + window.location = program; + // console.log(program); + } + + // Highlight active line when focused + editor.on('focus', function() { + editor.setHighlightActiveLine(true); + }); + + // Don't when not + editor.on('blur', function() { + editor.setHighlightActiveLine(false); + }); +}()); diff --git a/_includes/editor.min.js b/_includes/editor.min.js new file mode 100644 index 000000000..8f6b8ec1d --- /dev/null +++ b/_includes/editor.min.js @@ -0,0 +1 @@ +!function(){"use strict";function r(){var a=p.getSession().getScreenLength()*p.renderer.lineHeight+p.renderer.scrollBar.getWidth();c.style.height=Math.ceil(a).toString()+"px",p.resize()}function s(b){return b.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'").replace(a,"
")}function t(a,b){var c=new XMLHttpRequest,d=JSON.stringify({version:"master",optimize:"2",code:a});c.open("POST","http://play.rust-lang.org/evaluate.json",!0),c.onload=function(){if(4===c.readyState&&200===c.status){var d=JSON.parse(c.response).result,e=m;-1!==d.indexOf("error:")?e=n:-1!==d.indexOf("warning:")&&(e=o),b(e,d)}else b(!1,null)},c.onerror=function(){b(!1,null)},c.setRequestHeader("Content-Type","application/json"),c.send(d)}function u(a,b){null==result?(f.style.backgroundColor=i,f.innerHTML=k):a===m?v(b):a===o?w(b):x(b)}function v(a){f.style.backgroundColor=h,encodeURIComponent(p.getValue()),f.innerHTML="",f.appendChild(g),f.innerHTML+=s(a)}function w(a){f.style.backgroundColor=j,y(a,"warning")}function x(a){f.style.backgroundColor=i,y(a,"error")}function y(b,c){var d=b.split(a),e=d.map(function(a){if(a.startsWith("")||-1!==a.indexOf("^")){var b=a.indexOf(c+": ");return-1!==b?a.slice(b):""}return a.startsWith("playpen:")?"":a}).filter(function(a){return""!==a}).map(function(a){return s(a)}).join("
");encodeURIComponent(p.getValue()),f.innerHTML="",f.appendChild(g),f.innerHTML+=e;var i=z(d);l=i.map(function(a){return p.getSession().addMarker(a,"ace-"+c+"-line","fullLine",!1)}),l=l.concat(i.map(function(a){return p.getSession().addMarker(a,"ace-"+c+"-text","text",!1)}))}function z(a){var b=[];for(var c in a){var d=a[c];if(d.startsWith(":")&&-1!==d.indexOf(": ")){var e=d.split(/:\s?|\s+/,5).slice(1,5),f=e.map(function(a){return parseInt(a,10)-1});b.push(new q(f[0],f[1],f[2],f[3]))}}return b}"function"!=typeof String.prototype.startsWith&&(String.prototype.startsWith=function(a){return this.slice(0,a.length)===a});var a=/(?:\r\n|\r|\n)/g,b=document.getElementById("active-code"),c=document.getElementById("editor"),d=document.getElementById("static-code"),e=document.getElementById("run-code"),f=document.getElementById("result"),g=document.getElementById("playlink"),h="#E2EEF6",i="#F6E2E2",j="#FFFBCB",k="The server encountered an error while running the program.",l=[],m=0,n=1,o=2;d.style.display="none",b.style.display="block";var p=ace.edit("editor"),q=ace.require("ace/range").Range;p.setTheme("ace/theme/chrome"),p.getSession().setMode("ace/mode/rust"),p.setShowPrintMargin(!1),p.renderer.setShowGutter(!1),p.setHighlightActiveLine(!1),r(),e.addEventListener("click",function(){f.style.display="block",f.innerHTML="Running...",l.map(function(a){p.getSession().removeMarker(a)});var b=p.getValue();t(b,u)}),p.on("focus",function(){p.setHighlightActiveLine(!0)}),p.on("blur",function(){p.setHighlightActiveLine(!1)})}(); diff --git a/_includes/example.rs b/_includes/example.rs new file mode 100644 index 000000000..436f24f5a --- /dev/null +++ b/_includes/example.rs @@ -0,0 +1,22 @@ +// This code is editable and runnable! +fn main() { + // A simple integer calculator: + // `+` or `-` means add or subtract by 1 + // `*` or `/` means multiply or divide by 2 + + let program = "+ + * - /"; + let mut accumulator = 0i; + + for token in program.chars() { + match token { + '+' => accumulator += 1, + '-' => accumulator -= 1, + '*' => accumulator *= 2, + '/' => accumulator /= 2, + _ => { /* ignore everything else */ } + } + } + + println!("The program \"{}\" calculates the value {}", + program, accumulator); +} diff --git a/_includes/example.rs.html b/_includes/example.rs.html new file mode 100644 index 000000000..56744e995 --- /dev/null +++ b/_includes/example.rs.html @@ -0,0 +1,23 @@ +
// This code is editable and runnable!
+fn main() {
+// A simple integer calculator:
+// `+` or `-` means add or subtract by 1
+// `*` or `/` means multiply or divide by 2
+
+let program = "+ + * - /";
+let mut accumulator = 0i;
+
+for token in program.chars() {
+match token {
+    '+' => accumulator += 1,
+    '-' => accumulator -= 1,
+    '*' => accumulator *= 2,
+    '/' => accumulator /= 2,
+    _ => { /* ignore everything else */ }
+}
+}
+
+println!("The program \"{}\" calculates the value {}",
+   program, accumulator);
+}
+
diff --git a/_includes/include.js b/_includes/include.js new file mode 100644 index 000000000..4f1cf2f7f --- /dev/null +++ b/_includes/include.js @@ -0,0 +1,38 @@ +include = function() { + + // save references to save a few bytes + var args = arguments; + var doc = document; + + var toLoad = args.length; // load this many scripts + var lastArgument = args[toLoad - 1]; + var hasCallback = lastArgument.call; // is the last arg a callback? + if (hasCallback) { + toLoad --; + } + + function onScriptLoaded() { + var readyState = this.readyState; // we test for "complete" or "loaded" if on IE + if (!readyState || /ded|te/.test(readyState)) { + toLoad --; + if (!toLoad && hasCallback) { + lastArgument(); + } + } + } + + var script; + for (var i = 0; i < toLoad; i ++) { + + script = doc.createElement('script'); + script.src = arguments[i]; + script.async = true; + script.onload = script.onerror = script.onreadystatechange = onScriptLoaded; + ( + doc.head || + doc.getElementsByTagName('head')[0] + ).appendChild(script); + + } + +}; diff --git a/_includes/include.min.js b/_includes/include.min.js new file mode 100644 index 000000000..036fe8e42 --- /dev/null +++ b/_includes/include.min.js @@ -0,0 +1 @@ +include=function(){function f(){var a=this.readyState;(!a||/ded|te/.test(a))&&(c--,!c&&e&&d())}var a=arguments,b=document,c=a.length,d=a[c-1],e=d.call;e&&c--;for(var g,h=0;c>h;h++)g=b.createElement("script"),g.src=arguments[h],g.async=!0,g.onload=g.onerror=g.onreadystatechange=f,(b.head||b.getElementsByTagName("head")[0]).appendChild(g)}; diff --git a/_includes/set_platform.js b/_includes/set_platform.js new file mode 100644 index 000000000..de3255906 --- /dev/null +++ b/_includes/set_platform.js @@ -0,0 +1,49 @@ +function detect_platform() { + "use strict"; + var os = "unknown"; + + if (os == "unknown") { + if (navigator.platform == "Linux x86_64") {os = "x86_64-unknown-linux-gnu";} + if (navigator.platform == "Linux i686") {os = "i686-unknown-linux-gnu";} + } + + // I wish I knew by know, but I don't. Try harder. + if (os == "unknown") { + if (navigator.appVersion.indexOf("Win")!=-1) {os = "x86_64-pc-windows-gnu";} + if (navigator.appVersion.indexOf("Mac")!=-1) {os = "x86_64-apple-darwin";} + if (navigator.appVersion.indexOf("Linux")!=-1) {os = "x86_64-unknown-linux-gnu";} + } + + return os; +} + +(function () { + "use strict"; + var platform = detect_platform(); + + var rec_package_name = "nightly"; + var rec_version_type = "source"; + var rec_download_file = "rust-nightly.tar.gz"; + + if (platform == "x86_64-unknown-linux-gnu") { + rec_version_type = "Linux binary"; + rec_download_file = "rust-" + rec_package_name + "-x86_64-unknown-linux-gnu.tar.gz"; + } else if (platform == "i686-unknown-linux-gnu") { + rec_version_type = "Linux binary"; + rec_download_file = "rust-" + rec_package_name + "-i686-unknown-linux-gnu.tar.gz"; + } else if (platform == "x86_64-apple-darwin") { + rec_version_type = "Mac installer"; + rec_download_file = "rust-" + rec_package_name + "-x86_64-apple-darwin.pkg"; + } else if (platform == "x86_64-pc-windows-gnu") { + rec_version_type = "Windows installer"; + rec_download_file = "rust-" + rec_package_name + "-x86_64-pc-windows-gnu.exe"; + } + + var rec_package_desc = rec_package_name + " (" + rec_version_type + ")"; + var rec_vers_div = document.getElementById("install-version"); + rec_vers_div.innerHTML = rec_package_desc; + + var rec_dl_addy = "https://static.rust-lang.org/dist/" + rec_download_file; + var rec_inst_link = document.getElementById("inst-link"); + rec_inst_link.setAttribute("href", rec_dl_addy); +}()); diff --git a/_includes/set_platform.min.js b/_includes/set_platform.min.js new file mode 100644 index 000000000..8924ab2f2 --- /dev/null +++ b/_includes/set_platform.min.js @@ -0,0 +1 @@ +function detect_platform(){"use strict";var a="unknown";return"unknown"==a&&("Linux x86_64"==navigator.platform&&(a="x86_64-unknown-linux-gnu"),"Linux i686"==navigator.platform&&(a="i686-unknown-linux-gnu")),"unknown"==a&&(-1!=navigator.appVersion.indexOf("Win")&&(a="x86_64-pc-windows-gnu"),-1!=navigator.appVersion.indexOf("Mac")&&(a="x86_64-apple-darwin"),-1!=navigator.appVersion.indexOf("Linux")&&(a="x86_64-unknown-linux-gnu")),a}!function(){"use strict";var a=detect_platform(),b="nightly",c="source",d="rust-nightly.tar.gz";"x86_64-unknown-linux-gnu"==a?(c="Linux binary",d="rust-"+b+"-x86_64-unknown-linux-gnu.tar.gz"):"i686-unknown-linux-gnu"==a?(c="Linux binary",d="rust-"+b+"-i686-unknown-linux-gnu.tar.gz"):"x86_64-apple-darwin"==a?(c="Mac installer",d="rust-"+b+"-x86_64-apple-darwin.pkg"):"x86_64-pc-windows-gnu"==a&&(c="Windows installer",d="rust-"+b+"-x86_64-pc-windows-gnu.exe");var e=b+" ("+c+")",f=document.getElementById("install-version");f.innerHTML=e;var g="https://static.rust-lang.org/dist/"+d,h=document.getElementById("inst-link");h.setAttribute("href",g)}(); diff --git a/_layouts/default.html b/_layouts/default.html index 8a1a9080a..fcd0acd18 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -11,13 +11,17 @@ - + + +