blob: eebc29a9993045471c9b0cb13415fef3322f9ab1 [file] [log] [blame]
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"http"
"template"
)
func init() {
http.HandleFunc("/compile", Compile)
}
// Compile is an HTTP handler that reads Go source code from the request,
// compiles and links the code (returning any errors), runs the program,
// and sends the program's output as the HTTP response.
func Compile(w http.ResponseWriter, req *http.Request) {
out, err := compile(req)
if err != nil {
w.WriteHeader(404)
var s string
if out != nil {
s = string(out)
} else {
s = err.String()
}
output.Execute(w, s)
return
}
// write the output of x as the http response
if *htmlOutput {
w.Write(out)
} else if url, ok := isImage(out); ok {
fmt.Fprintf(w, `<img src="%s">`, url)
} else {
output.Execute(w, out)
}
}
func isImage(out []byte) (string, bool) {
out = bytes.TrimSpace(out)
if !bytes.HasPrefix(out, []byte("IMAGE:")) {
return "", false
}
out = out[6:]
for _, c := range out {
switch {
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z', '0' <= c && c <= '9',
c == '+', c == '-', c == '/', c == '_', c == '=':
default:
println("bad", c)
return "", false
}
}
return "data:image/png;base64," + string(out), true
}
var frontPage, output *template.Template // HTML templates
func init() {
frontPage = template.New(nil)
frontPage.SetDelims("«", "»")
if err := frontPage.Parse(frontPageText); err != nil {
panic(err)
}
output = template.MustParse(outputText, nil)
}
var outputText = `<pre>{@|html}</pre>`
var frontPageText = `<!doctype html>
<html>
<head>
<style>
pre, textarea {
font-family: monospace; /* use the user's browser setting */
font-size: 100%;
}
.hints {
font-size: 0.8em;
text-align: right;
}
#edit, #output, #errors { width: 100%; text-align: left; }
#edit { height: 500px; }
#output { color: #00c; }
#errors { color: #c00; }
</style>
<script>
function insertTabs(n) {
// find the selection start and end
var cont = document.getElementById("edit");
var start = cont.selectionStart;
var end = cont.selectionEnd;
// split the textarea content into two, and insert n tabs
var v = cont.value;
var u = v.substr(0, start);
for (var i=0; i<n; i++) {
u += "\t";
}
u += v.substr(end);
// set revised content
cont.value = u;
// reset caret position after inserted tabs
cont.selectionStart = start+n;
cont.selectionEnd = start+n;
}
function autoindent(el) {
var curpos = el.selectionStart;
var tabs = 0;
while (curpos > 0) {
curpos--;
if (el.value[curpos] == "\t") {
tabs++;
} else if (tabs > 0 || el.value[curpos] == "\n") {
break;
}
}
setTimeout(function() {
insertTabs(tabs);
}, 1);
}
function keyHandler(event) {
var e = window.event || event;
if (e.keyCode == 9) { // tab
insertTabs(1);
e.preventDefault();
return false;
}
if (e.keyCode == 13) { // enter
if (e.shiftKey) { // +shift
compile(e.target);
e.preventDefault();
return false;
} else {
autoindent(e.target);
}
}
return true;
}
var xmlreq;
function autocompile() {
if(!document.getElementById("autocompile").checked) {
return;
}
compile();
}
function compile() {
var prog = document.getElementById("edit").value;
var req = new XMLHttpRequest();
xmlreq = req;
req.onreadystatechange = function() { compileUpdate(req); }
req.open("POST", "/compile", true);
req.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
req.send(prog);
document.getElementById("output").innerHTML = "running...";
}
function compileUpdate(req) {
if(req != xmlreq || !req || req.readyState != 4) {
return;
}
if(req.status == 200) {
document.getElementById("output").innerHTML = req.responseText;
document.getElementById("errors").innerHTML = "";
} else {
document.getElementById("errors").innerHTML = req.responseText;
document.getElementById("output").innerHTML = "";
}
}
</script>
</head>
<body>
<table width="100%"><tr><td width="60%" valign="top">
<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler(event);" onkeyup="autocompile();">«@|html»</textarea>
<div class="hints">
(Shift-Enter to compile and run.)&nbsp;&nbsp;&nbsp;&nbsp;
<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke
</div>
<td width="3%">
<td width="27%" align="right" valign="top">
<div id="output"></div>
</table>
<div id="errors"></div>
</body>
</html>
`
var helloWorld = []byte(`package main
import "fmt"
func main() {
fmt.Println("hello, world")
}
`)