Skip to content
This repository was archived by the owner on Sep 30, 2020. It is now read-only.

Commit 677000a

Browse files
committed
Merge pull request #26 from SergioBenitez/gh-pages
Added a live code editor based on Ace.js and rust-playpen.
2 parents b1b830d + 07ca30c commit 677000a

File tree

3 files changed

+228
-1
lines changed

3 files changed

+228
-1
lines changed

css/style.css

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,51 @@ ul.laundry-list {
250250
}
251251
}
252252

253+
#editor {
254+
padding: none;
255+
margin: none;
256+
width: 100%;
257+
height: 340px;
258+
font-size: 13px;
259+
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
260+
}
261+
262+
#active-code {
263+
position: relative;
264+
display: none;
265+
padding: 10px;
266+
border-radius: 4px;
267+
background-color: #FDFDFD;
268+
border: 1px solid #CCC;
269+
}
270+
271+
#run-code {
272+
position: absolute;
273+
z-index: 10;
274+
float: right;
275+
right: 8px;
276+
top: 8px;
277+
outline: none;
278+
}
279+
280+
#result {
281+
background-color: #E2EEF6;
282+
margin-top: 10px;
283+
padding: 10px;
284+
display: none;
285+
border-radius: 4px;
286+
}
287+
288+
.ace-error-text {
289+
background-color: #e9abab;
290+
position: absolute;
291+
}
292+
293+
.ace-error-line {
294+
background-color: #F6E2E2;
295+
position: absolute;
296+
}
297+
253298
pre { background-color: #FDFDFD; }
254299

255300
/* Code highlighting */
@@ -261,4 +306,4 @@ pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
261306
pre.rust .comment { color: #8E908C; }
262307
pre.rust .doccomment { color: #4D4D4C; }
263308
pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
264-
pre.rust .lifetime { color: #B76514; }
309+
pre.rust .lifetime { color: #B76514; }

index.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,33 @@ <h2>Featuring</h2>
4444
</ul>
4545
</div>
4646
<div class="col-md-8">
47+
<div id="active-code">
48+
<button type="button" class="btn btn-primary btn-sm" id="run-code">Run</button>
49+
<div id="editor">// This code is editable and runnable!
50+
fn main() {
51+
// A simple integer calculator:
52+
// `+` or `-` means add/sub by 1
53+
// `*` or `/` means mul/div by 2
54+
55+
let program = "+ + * - /";
56+
let mut accumulator = 0;
57+
58+
for token in program.chars() {
59+
match token {
60+
'+' => accumulator += 1,
61+
'-' => accumulator -= 1,
62+
'*' => accumulator *= 2,
63+
'/' => accumulator /= 2,
64+
_ => { /* ignore everything else */ }
65+
}
66+
}
67+
68+
println!("The program \"{}\" calculates the value {}",
69+
program, accumulator);
70+
}</div>
71+
<div id="result"></div>
72+
</div>
73+
<div id="static-code">
4774
<pre class='rust'>
4875
<span class='kw'>fn</span> main() {
4976
<span class='comment'>// A simple integer calculator:
@@ -67,6 +94,7 @@ <h2>Featuring</h2>
6794
program, accumulator);
6895
}
6996
</pre>
97+
</div>
7098
</div>
7199
</div>
72100

@@ -123,3 +151,6 @@ <h2>Featuring</h2>
123151
rec_inst_link.setAttribute("href", rec_dl_addy);
124152

125153
</script>
154+
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace.js"></script>
155+
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/mode-rust.js"></script>
156+
<script type="text/javascript" charset="utf-8" src="/js/editor.js"></script>

js/editor.js

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// ECMAScript 6 Backwards compatability
2+
if (typeof String.prototype.startsWith != 'function') {
3+
String.prototype.startsWith = function(str) {
4+
return this.slice(0, str.length) == str;
5+
};
6+
}
7+
8+
// Fetching DOM items
9+
var activeCode = document.getElementById("active-code");
10+
var staticCode = document.getElementById("static-code");
11+
var runButton = document.getElementById("run-code");
12+
var resultDiv = document.getElementById("result");
13+
14+
// Background colors for program result on success/error
15+
var successColor = "#E2EEF6";
16+
var errorColor = "#F6E2E2";
17+
18+
// Error message to return when there's a server failure
19+
var errMsg = "The server encountered an error while running the program.";
20+
21+
// Stores ACE editor markers (highights) for errors
22+
var markers = [];
23+
24+
// JS exists, display ACE editor
25+
staticCode.style.display = "none";
26+
activeCode.style.display = "block";
27+
28+
// Setting up ace editor
29+
var editor = ace.edit("editor");
30+
var Range = ace.require('ace/range').Range;
31+
editor.setTheme("ace/theme/chrome");
32+
editor.getSession().setMode("ace/mode/rust");
33+
editor.setShowPrintMargin(false);
34+
editor.renderer.setShowGutter(false);
35+
36+
// Dispatches a XMLHttpRequest to the Rust playpen, running the program, and
37+
// issues a callback to `callback` with the result (or null on error)
38+
function runProgram(program, callback) {
39+
var req = new XMLHttpRequest();
40+
var data = JSON.stringify({
41+
version: "master",
42+
optimize: "2",
43+
code: program
44+
});
45+
46+
<!-- console.log("Sending", data); -->
47+
req.open('POST', "http://playtest.rust-lang.org/evaluate.json", true);
48+
req.onload = function(e) {
49+
if (req.readyState === 4 && req.status === 200) {
50+
var result = JSON.parse(req.response).result;
51+
// Need server support to get an accurate version of this.
52+
var isSuccess = (result.indexOf("error:") === -1);
53+
callback(isSuccess, result);
54+
} else {
55+
callback(false, null);
56+
}
57+
};
58+
59+
req.onerror = function(e) {
60+
callback(false, null);
61+
}
62+
63+
req.setRequestHeader("Content-Type", "application/json");
64+
req.send(data);
65+
}
66+
67+
// The callback to runProgram
68+
function handleResult(success, message) {
69+
var message = message.replace(/<anon>/g, '');
70+
var message = message.replace(/(?:\r\n|\r|\n)/g, '<br />');
71+
72+
// Dispatch depending on result type
73+
if (result == null) {
74+
resultDiv.style.backgroundColor = errorColor;
75+
resultDiv.innerHTML = errMsg;
76+
} else if (success) {
77+
handleSuccess(message);
78+
} else {
79+
handleError(message);
80+
}
81+
}
82+
83+
// Called on successful program run
84+
function handleSuccess(message) {
85+
resultDiv.style.backgroundColor = successColor;
86+
resultDiv.innerHTML = message;
87+
}
88+
89+
// Called on unsuccessful program run. Detects and prints errors in program
90+
// output and highlights relevant lines and text in the code.
91+
function handleError(message) {
92+
resultDiv.style.backgroundColor = errorColor;
93+
94+
// Getting list of ranges with errors
95+
var lines = message.split("<br />");
96+
var ranges = parseError(lines);
97+
98+
// Cleaning up the message: keeps only relevant error output
99+
var cleanMessage = lines.map(function(line) {
100+
var errIndex = line.indexOf("error: ");
101+
if (errIndex !== -1) {
102+
return line.slice(errIndex);
103+
}
104+
return "";
105+
}).filter(function(line) {
106+
return line !== "";
107+
}).join("<br />");
108+
109+
// Setting message
110+
resultDiv.innerHTML = cleanMessage;
111+
112+
// Highlighting the lines
113+
markers = ranges.map(function(range) {
114+
return editor.getSession().addMarker(range, "ace-error-line", "fullLine", false);
115+
});
116+
117+
// Highlighting the specific text
118+
markers = markers.concat(ranges.map(function(range) {
119+
return editor.getSession().addMarker(range, "ace-error-text", "text", false);
120+
}));
121+
}
122+
123+
// Parses an error message returning a list of ranges (row:col, row:col) where
124+
// erors in the code have occured.
125+
function parseError(lines) {
126+
var ranges = [];
127+
for (var i in lines) {
128+
var line = lines[i];
129+
if (line.startsWith(":") && line.indexOf(": ") !== -1) {
130+
var parts = line.split(/:\s?|\s+/, 5).slice(1, 5);
131+
var ip = parts.map(function(p) { return parseInt(p, 10) - 1; });
132+
<!-- console.log("line:", line, parts, ip); -->
133+
ranges.push(new Range(ip[0], ip[1], ip[2], ip[3]));
134+
}
135+
}
136+
137+
return ranges;
138+
}
139+
140+
// Registering handler for run button click
141+
runButton.addEventListener("click", function(ev) {
142+
resultDiv.style.display = "block";
143+
resultDiv.innerHTML = "Running...";
144+
145+
// clear previous markers, if any
146+
markers.map(function(id) { editor.getSession().removeMarker(id); });
147+
148+
// Get the code, run the program
149+
var program = editor.getValue();
150+
runProgram(program, handleResult);
151+
});

0 commit comments

Comments
 (0)