diff --git a/static/web.html b/static/web.html index 205872d..fe114f0 100644 --- a/static/web.html +++ b/static/web.html @@ -73,6 +73,12 @@ +

+ diff --git a/static/web.js b/static/web.js index 35dec24..f8df17a 100644 --- a/static/web.js +++ b/static/web.js @@ -133,8 +133,8 @@ result.parentNode.style.visibility = ""; } - function evaluate(result, code, version, optimize, button, test) { - send("evaluate.json", {code: code, version: version, optimize: optimize, test: !!test, separate_output: true, color: true}, + function evaluate(result, code, version, optimize, button, test, backtrace) { + send("evaluate.json", {code: code, version: version, optimize: optimize, test: !!test, separate_output: true, color: true, backtrace: backtrace }, function(object) { var samp, pre; set_result(result); @@ -174,10 +174,10 @@ }, button, test ? "Running tests…" : "Running…", result); } - function compile(emit, result, code, version, optimize, button) { + function compile(emit, result, code, version, optimize, button, backtrace) { var syntax = document.getElementById('asm-flavor').value; send("compile.json", {emit: emit, code: code, version: version, optimize: optimize, - color: true, highlight: true, syntax: syntax}, function(object) { + color: true, highlight: true, syntax: syntax, backtrace: backtrace}, function(object) { if ("error" in object) { set_result(result, "

"); result.firstChild.firstChild.innerHTML = formatCompilerOutput(object.error); @@ -233,10 +233,11 @@ result.parentNode.style.visibility = ""; } - function shareGist(result, version, code, button) { + function shareGist(result, version, code, button, backtraceval) { // only needed for the "shrinking" animation var full_url = "https://play.rust-lang.org/?code=" + encodeURIComponent(code) + - "&version=" + encodeURIComponent(version); + "&version=" + encodeURIComponent(version) + + "&backtrace=" + encodeURIComponent(backtraceval); var url = "https://api.github.com/gists"; button.disabled = true; @@ -275,7 +276,8 @@ var play_url = "https://play.rust-lang.org/?gist=" + encodeURIComponent(gist_id) + "&version=" + - encodeURIComponent(version); + encodeURIComponent(version) + + "&backtrace=" + encodeURIComponent(backtraceval); var link = result.firstChild.firstElementChild; @@ -301,9 +303,10 @@ ); } - function share(result, version, code, button) { + function share(result, version, code, button, backtraceval) { var playurl = "https://play.rust-lang.org/?code=" + encodeURIComponent(code); playurl += "&version=" + encodeURIComponent(version); + playurl += "&backtrace=" + encodeURIComponent(backtraceval); if (playurl.length > 5000) { set_result(result, "

Sorry, your code is too long to share this way." + "

At present, sharing produces a link containing the" + @@ -482,6 +485,7 @@ var mode; var query; var asm_flavor; + var backtrace; function updateEvaluateAction(code) { // A very simple pair of heuristics; there’s no point in doing more, IMO. @@ -503,7 +507,8 @@ } evaluate(result, session.getValue(), getRadioValue("version"), getRadioValue("optimize"), evaluateButton, - evaluateAction === "test"); + evaluateAction === "test", + backtrace.value); } var COLOR_CODES = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white']; @@ -552,6 +557,7 @@ clearResultButton = document.getElementById("clear-result"); keyboard = document.getElementById("keyboard"); asm_flavor = document.getElementById("asm-flavor"); + backtrace = document.getElementById("backtrace"); themes = document.getElementById("themes"); editor = ace.edit("editor"); set_result.editor = editor; @@ -589,6 +595,11 @@ asm_flavor.value = flavor; } + var vbacktrace = optionalLocalStorageGetItem("backtrace"); + if (vbacktrace !== null) { + backtrace.value = vbacktrace; + } + query = getQueryParameters(); if ("code" in query) { session.setValue(query.code); @@ -610,6 +621,12 @@ } } + if ("backtrace" in query) { + if (backtrace !== null) { + backtrace.value = query.backtrace; + } + } + if (query.run === "1") { doEvaluate(); } else { @@ -637,6 +654,11 @@ optionalLocalStorageSetItem("asm_flavor", flavor); }; + backtrace.onkeyup = backtrace.onchange = function() { + var vbacktrace = backtrace.options[backtrace.selectedIndex].value; + optionalLocalStorageSetItem("backtrace", vbacktrace); + }; + evaluateButton.onclick = function() { doEvaluate(true); }; @@ -656,18 +678,18 @@ asmButton.onclick = function() { compile("asm", result, session.getValue(), getRadioValue("version"), - getRadioValue("optimize"), asmButton); + getRadioValue("optimize"), asmButton, backtrace.value); }; irButton.onclick = function() { compile("llvm-ir", result, session.getValue(), getRadioValue("version"), - getRadioValue("optimize"), irButton); + getRadioValue("optimize"), irButton, backtrace.value); }; mirButton.onclick = function() { document.getElementById("version-nightly").checked = true; compile("mir", result, session.getValue(), getRadioValue("version"), - getRadioValue("optimize"), mirButton); + getRadioValue("optimize"), mirButton, backtrace.value); }; formatButton.onclick = function() { @@ -675,11 +697,11 @@ }; shareButton.onclick = function() { - share(result, getRadioValue("version"), session.getValue(), shareButton); + share(result, getRadioValue("version"), session.getValue(), shareButton, backtrace.value); }; gistButton.onclick = function() { - shareGist(result, getRadioValue("version"), session.getValue(), gistButton); + shareGist(result, getRadioValue("version"), session.getValue(), gistButton, backtrace.value); }; configureEditorButton.onclick = function() { diff --git a/web.py b/web.py index 6c4d98b..3ca98e9 100755 --- a/web.py +++ b/web.py @@ -3,6 +3,7 @@ import functools import os import sys +import shlex #for shlex.quote() needed only when backtrace is on, to escape args from bottle import get, request, response, route, run, static_file from pygments import highlight @@ -32,7 +33,13 @@ def serve_static(path): return static_file(path, root="static") @functools.lru_cache(maxsize=256) -def execute(version, command, arguments, code): +def execute(version, command, arguments, code, show_backtrace): + if show_backtrace: + escapedargs="" + for arg in arguments: + escapedargs += " " + shlex.quote(arg) + arguments = ("-c", "export RUST_BACKTRACE=1; " + command + escapedargs) + command = "/usr/bin/dash" print("running:", version, command, arguments, file=sys.stderr, flush=True) return playpen.execute(version, command, arguments, code) @@ -57,22 +64,31 @@ def wrapper(*args, **kwargs): return wrapper return decorator +def init_args_get_bt(optimize, color, backtrace_str): + args = ["-C", "opt-level=" + optimize] + if "1" == backtrace_str or ( "2" == backtrace_str and "0" == optimize ): + show_backtrace = True + else: + show_backtrace = False + if "0" == optimize: + args.append("-g") + if color: + args.append("--color=always") + return (args, show_backtrace) + @route("/evaluate.json", method=["POST", "OPTIONS"]) @enable_post_cors +@extractor("backtrace", "0", ("0", "1", "2")) @extractor("color", False, (True, False)) @extractor("test", False, (True, False)) @extractor("version", "stable", ("stable", "beta", "nightly")) @extractor("optimize", "2", ("0", "1", "2", "3")) -def evaluate(optimize, version, test, color): - args = ["-C", "opt-level=" + optimize] - if optimize == "0": - args.append("-g") - if color: - args.append("--color=always") +def evaluate(optimize, version, test, color, backtrace_str): + args, show_backtrace = init_args_get_bt(optimize, color, backtrace_str) if test: args.append("--test") - out, _ = execute(version, "/usr/local/bin/evaluate.sh", tuple(args), request.json["code"]) + out, _ = execute(version, "/usr/local/bin/evaluate.sh", tuple(args), request.json["code"], show_backtrace) if request.json.get("separate_output") is True: split = out.split(b"\xff", 1) @@ -87,9 +103,12 @@ def evaluate(optimize, version, test, color): @route("/format.json", method=["POST", "OPTIONS"]) @enable_post_cors +@extractor("optimize", "2", ("0", "1", "2", "3")) +@extractor("backtrace", "0", ("0", "1", "2")) @extractor("version", "stable", ("stable", "beta", "nightly")) -def format(version): - out, rc = execute(version, "/usr/bin/rustfmt", (), request.json["code"]) +def format(version, backtrace_str, optimize): + _, show_backtrace = init_args_get_bt(optimize, None, backtrace_str) + out, rc = execute(version, "/usr/bin/rustfmt", (), request.json["code"], show_backtrace) if rc: return {"error": out.decode()} else: @@ -97,17 +116,14 @@ def format(version): @route("/compile.json", method=["POST", "OPTIONS"]) @enable_post_cors +@extractor("backtrace", "0", ("0", "1", "2")) @extractor("syntax", "att", ("att", "intel")) @extractor("color", False, (True, False)) @extractor("version", "stable", ("stable", "beta", "nightly")) @extractor("optimize", "2", ("0", "1", "2", "3")) @extractor("emit", "asm", ("asm", "llvm-ir", "mir")) -def compile(emit, optimize, version, color, syntax): - args = ["-C", "opt-level=" + optimize] - if optimize == "0": - args.append("-g") - if color: - args.append("--color=always") +def compile(emit, optimize, version, color, syntax, backtrace_str): + args, show_backtrace = init_args_get_bt(optimize, color, backtrace_str) if syntax: args.append("-C") args.append("llvm-args=-x86-asm-syntax=%s" % syntax) @@ -116,7 +132,7 @@ def compile(emit, optimize, version, color, syntax): args.append("--unpretty=mir") else: args.append("--emit=" + emit) - out, _ = execute(version, "/usr/local/bin/compile.sh", tuple(args), request.json["code"]) + out, _ = execute(version, "/usr/local/bin/compile.sh", tuple(args), request.json["code"], show_backtrace) split = out.split(b"\xff", 1) if len(split) == 2: rustc_output = split[0].decode()