playground: add examples to demonstrate tricks
As a way to document the playground's tricks, this change adds
a dropdown of examples to the right of the "Share" button. They
are as follows:
- Hello, playground (default)
- Tests
- Multiple files
- Display image
- Sleep
- Clear
Fixes golang/go#32294.
Change-Id: I6cdd54714d5638a932b2d392db1ea888468f5cec
Reviewed-on: https://go-review.googlesource.com/c/playground/+/216359
Run-TryBot: Andrew Bonventre <andybons@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
diff --git a/Dockerfile b/Dockerfile
index 063f9a5..dafa0d4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -121,6 +121,7 @@
COPY --from=build /go/bin/playground /app
COPY edit.html /app
COPY static /app/static
+COPY examples /app/examples
WORKDIR /app
# Whether we allow third-party imports via proxy.golang.org:
diff --git a/edit.html b/edit.html
index 2b5ded8..719edab 100644
--- a/edit.html
+++ b/edit.html
@@ -31,7 +31,8 @@
{{end}}
'enableHistory': true,
'enableShortcuts': true,
- 'enableVet': true
+ 'enableVet': true,
+ 'toysEl': '.js-playgroundToysEl'
});
playgroundEmbed({
'codeEl': '#code',
@@ -120,6 +121,14 @@
embed
</label>
{{end}}
+ <select class="js-playgroundToysEl">
+ <option value="hello.txt">Hello, playground</option>
+ <option value="test.txt">Tests</option>
+ <option value="multi.txt">Multiple files</option>
+ <option value="image.txt">Display image</option>
+ <option value="sleep.txt">Sleep</option>
+ <option value="clear.txt">Clear</option>
+ </select>
</div>
<div id="aboutControls">
<input type="button" value="About" id="aboutButton">
diff --git a/examples/clear.txt b/examples/clear.txt
new file mode 100644
index 0000000..c5381d7
--- /dev/null
+++ b/examples/clear.txt
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "fmt"
+ "strings"
+ "time"
+)
+
+func main() {
+ const col = 30
+ // Clear the screen by printing \x0c.
+ bar := fmt.Sprintf("\x0c[%%-%vs]", col)
+ for i := 0; i < col; i++ {
+ fmt.Printf(bar, strings.Repeat("=", i)+">")
+ time.Sleep(100 * time.Millisecond)
+ }
+ fmt.Printf(bar+" Done!", strings.Repeat("=", col))
+}
diff --git a/examples/hello.txt b/examples/hello.txt
new file mode 100644
index 0000000..8fd43ed
--- /dev/null
+++ b/examples/hello.txt
@@ -0,0 +1,9 @@
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ fmt.Println("Hello, playground")
+}
diff --git a/examples/image.txt b/examples/image.txt
new file mode 100644
index 0000000..4180a45
--- /dev/null
+++ b/examples/image.txt
@@ -0,0 +1,40 @@
+package main
+
+import (
+ "bytes"
+ "encoding/base64"
+ "fmt"
+ "image"
+ "image/png"
+)
+
+var favicon = []byte{
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x0f, 0x04, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x5d, 0x52, 0x1c, 0x00, 0x00, 0x00, 0x0f, 0x50,
+ 0x4c, 0x54, 0x45, 0x7a, 0xdf, 0xfd, 0xfd, 0xff, 0xfc, 0x39, 0x4d, 0x52, 0x19, 0x16, 0x15, 0xc3, 0x8d, 0x76, 0xc7,
+ 0x36, 0x2c, 0xf5, 0x00, 0x00, 0x00, 0x40, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x95, 0xc9, 0xd1, 0x0d, 0xc0, 0x20,
+ 0x0c, 0x03, 0xd1, 0x23, 0x5d, 0xa0, 0x49, 0x17, 0x20, 0x4c, 0xc0, 0x10, 0xec, 0x3f, 0x53, 0x8d, 0xc2, 0x02, 0x9c,
+ 0xfc, 0xf1, 0x24, 0xe3, 0x31, 0x54, 0x3a, 0xd1, 0x51, 0x96, 0x74, 0x1c, 0xcd, 0x18, 0xed, 0x9b, 0x9a, 0x11, 0x85,
+ 0x24, 0xea, 0xda, 0xe0, 0x99, 0x14, 0xd6, 0x3a, 0x68, 0x6f, 0x41, 0xdd, 0xe2, 0x07, 0xdb, 0xb5, 0x05, 0xca, 0xdb,
+ 0xb2, 0x9a, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
+}
+
+// displayImage renders an image to the playground's console by
+// base64-encoding the encoded image and printing it to stdout
+// with the prefix "IMAGE:".
+func displayImage(m image.Image) {
+ var buf bytes.Buffer
+ err := png.Encode(&buf, m)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println("IMAGE:" + base64.StdEncoding.EncodeToString(buf.Bytes()))
+}
+
+func main() {
+ m, err := png.Decode(bytes.NewReader(favicon))
+ if err != nil {
+ panic(err)
+ }
+ displayImage(m)
+}
diff --git a/examples/multi.txt b/examples/multi.txt
new file mode 100644
index 0000000..ad41446
--- /dev/null
+++ b/examples/multi.txt
@@ -0,0 +1,21 @@
+package main
+
+import (
+ "play.ground/foo"
+)
+
+func main() {
+ foo.Bar()
+}
+
+-- go.mod --
+module play.ground
+
+-- foo/foo.go --
+package foo
+
+import "fmt"
+
+func Bar() {
+ fmt.Println("This function lives in an another file!")
+}
diff --git a/examples/sleep.txt b/examples/sleep.txt
new file mode 100644
index 0000000..d68a3d8
--- /dev/null
+++ b/examples/sleep.txt
@@ -0,0 +1,17 @@
+package main
+
+import (
+ "fmt"
+ "math/rand"
+ "time"
+)
+
+func main() {
+ for i := 0; i < 10; i++ {
+ dur := time.Duration(rand.Intn(1000)) * time.Millisecond
+ fmt.Printf("Sleeping for %v\n", dur)
+ // Sleep for a random duration between 0-1000ms
+ time.Sleep(dur)
+ }
+ fmt.Println("Done!")
+}
diff --git a/examples/test.txt b/examples/test.txt
new file mode 100644
index 0000000..4bf86e9
--- /dev/null
+++ b/examples/test.txt
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "testing"
+)
+
+// LastIndex returns the index of the last instance of x in list, or
+// -1 if x is not present. The loop condition has a fault that
+// causes somes tests to fail. Change it to i >= 0 to see them pass.
+func LastIndex(list []int, x int) int {
+ for i := len(list) - 1; i > 0; i-- {
+ if list[i] == x {
+ return i
+ }
+ }
+ return -1
+}
+
+func TestLastIndex(t *testing.T) {
+ tests := []struct {
+ list []int
+ x int
+ want int
+ }{
+ {list: []int{1}, x: 1, want: 0},
+ {list: []int{1, 1}, x: 1, want: 1},
+ {list: []int{2, 1}, x: 2, want: 0},
+ {list: []int{1, 2, 1, 1}, x: 2, want: 1},
+ {list: []int{1, 1, 1, 2, 2, 1}, x: 3, want: -1},
+ {list: []int{3, 1, 2, 2, 1, 1}, x: 3, want: 0},
+ }
+ for _, tt := range tests {
+ if got := LastIndex(tt.list, tt.x); got != tt.want {
+ t.Errorf("LastIndex(%v, %v) = %v, want %v", tt.list, tt.x, got, tt.want)
+ }
+ }
+}
diff --git a/server.go b/server.go
index d3a491b..f091933 100644
--- a/server.go
+++ b/server.go
@@ -59,6 +59,9 @@
staticHandler := http.StripPrefix("/static/", http.FileServer(http.Dir("./static")))
s.mux.Handle("/static/", staticHandler)
+
+ examplesHandler := http.StripPrefix("/doc/play/", http.FileServer(http.Dir("./examples")))
+ s.mux.Handle("/doc/play/", examplesHandler)
}
func (s *server) handlePlaygroundJS(w http.ResponseWriter, r *http.Request) {
diff --git a/static/style.css b/static/style.css
index 1cd00e8..ac93cf0 100644
--- a/static/style.css
+++ b/static/style.css
@@ -174,3 +174,9 @@
top: 10px;
right: 10px;
}
+
+#controls select {
+ font-size: 0.875rem;
+ border: 0.0625rem solid #375EAB;
+ margin: 0;
+}
\ No newline at end of file