diff --git a/cmd/godoc/appinit.go b/cmd/godoc/appinit.go index cb747b30ef..6318bb75fb 100644 --- a/cmd/godoc/appinit.go +++ b/cmd/godoc/appinit.go @@ -89,12 +89,11 @@ func main() { pres = godoc.NewPresentation(corpus) pres.TabWidth = 8 pres.ShowPlayground = true - pres.ShowExamples = true pres.DeclLinks = true pres.NotesRx = regexp.MustCompile("BUG") pres.GoogleAnalytics = os.Getenv("GODOC_ANALYTICS") - readTemplates(pres, true) + readTemplates(pres) datastoreClient, memcacheClient := getClients() diff --git a/cmd/godoc/godoc_test.go b/cmd/godoc/godoc_test.go index 7200c917b0..54fe540ddf 100644 --- a/cmd/godoc/godoc_test.go +++ b/cmd/godoc/godoc_test.go @@ -54,75 +54,6 @@ func buildGodoc(t *testing.T) (bin string, cleanup func()) { return bin, func() { os.RemoveAll(tmp) } } -// Basic regression test for godoc command-line tool. -func TestCLI(t *testing.T) { - bin, cleanup := buildGodoc(t) - defer cleanup() - - tests := []struct { - args []string - matches []string // regular expressions - dontmatch []string // regular expressions - }{ - { - args: []string{"fmt"}, - matches: []string{ - `import "fmt"`, - `Package fmt implements formatted I/O`, - }, - }, - { - args: []string{"io", "WriteString"}, - matches: []string{ - `func WriteString\(`, - `WriteString writes the contents of the string s to w`, - }, - }, - { - args: []string{"nonexistingpkg"}, - matches: []string{ - `cannot find package`, - }, - }, - { - args: []string{"fmt", "NonexistentSymbol"}, - matches: []string{ - `No match found\.`, - }, - }, - { - args: []string{"-src", "syscall", "Open"}, - matches: []string{ - `func Open\(`, - }, - dontmatch: []string{ - `No match found\.`, - }, - }, - } - for _, test := range tests { - cmd := exec.Command(bin, test.args...) - cmd.Args[0] = "godoc" - out, err := cmd.CombinedOutput() - if err != nil { - t.Errorf("Running with args %#v: %v", test.args, err) - continue - } - for _, pat := range test.matches { - re := regexp.MustCompile(pat) - if !re.Match(out) { - t.Errorf("godoc %v =\n%s\nwanted /%v/", strings.Join(test.args, " "), out, pat) - } - } - for _, pat := range test.dontmatch { - re := regexp.MustCompile(pat) - if re.Match(out) { - t.Errorf("godoc %v =\n%s\ndid not want /%v/", strings.Join(test.args, " "), out, pat) - } - } - } -} - func serverAddress(t *testing.T) string { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { diff --git a/cmd/godoc/handlers.go b/cmd/godoc/handlers.go index fabb679779..d393992eb9 100644 --- a/cmd/godoc/handlers.go +++ b/cmd/godoc/handlers.go @@ -112,28 +112,23 @@ func readTemplate(name string) *template.Template { return t } -func readTemplates(p *godoc.Presentation, html bool) { - p.PackageText = readTemplate("package.txt") - p.SearchText = readTemplate("search.txt") - - if html || p.HTMLMode { - codewalkHTML = readTemplate("codewalk.html") - codewalkdirHTML = readTemplate("codewalkdir.html") - p.CallGraphHTML = readTemplate("callgraph.html") - p.DirlistHTML = readTemplate("dirlist.html") - p.ErrorHTML = readTemplate("error.html") - p.ExampleHTML = readTemplate("example.html") - p.GodocHTML = readTemplate("godoc.html") - p.ImplementsHTML = readTemplate("implements.html") - p.MethodSetHTML = readTemplate("methodset.html") - p.PackageHTML = readTemplate("package.html") - p.PackageRootHTML = readTemplate("packageroot.html") - p.SearchHTML = readTemplate("search.html") - p.SearchDocHTML = readTemplate("searchdoc.html") - p.SearchCodeHTML = readTemplate("searchcode.html") - p.SearchTxtHTML = readTemplate("searchtxt.html") - p.SearchDescXML = readTemplate("opensearch.xml") - } +func readTemplates(p *godoc.Presentation) { + codewalkHTML = readTemplate("codewalk.html") + codewalkdirHTML = readTemplate("codewalkdir.html") + p.CallGraphHTML = readTemplate("callgraph.html") + p.DirlistHTML = readTemplate("dirlist.html") + p.ErrorHTML = readTemplate("error.html") + p.ExampleHTML = readTemplate("example.html") + p.GodocHTML = readTemplate("godoc.html") + p.ImplementsHTML = readTemplate("implements.html") + p.MethodSetHTML = readTemplate("methodset.html") + p.PackageHTML = readTemplate("package.html") + p.PackageRootHTML = readTemplate("packageroot.html") + p.SearchHTML = readTemplate("search.html") + p.SearchDocHTML = readTemplate("searchdoc.html") + p.SearchCodeHTML = readTemplate("searchcode.html") + p.SearchTxtHTML = readTemplate("searchtxt.html") + p.SearchDescXML = readTemplate("opensearch.xml") } type fmtResponse struct { diff --git a/cmd/godoc/main.go b/cmd/godoc/main.go index 7f0ac0c985..19b5a453c4 100644 --- a/cmd/godoc/main.go +++ b/cmd/godoc/main.go @@ -53,7 +53,7 @@ import ( "golang.org/x/tools/godoc/vfs/zipfs" ) -const defaultAddr = ":6060" // default webserver address +const defaultAddr = "localhost:6060" // default webserver address var ( // file system to serve @@ -66,18 +66,11 @@ var ( analysisFlag = flag.String("analysis", "", `comma-separated list of analyses to perform (supported: type, pointer). See http://golang.org/lib/godoc/analysis/help.html`) // network - httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')") - serverAddr = flag.String("server", "", "webserver address for command line searches") + httpAddr = flag.String("http", defaultAddr, "HTTP service address") // layout control - html = flag.Bool("html", false, "print HTML in command-line mode") - srcMode = flag.Bool("src", false, "print (exported) source in command-line mode") - allMode = flag.Bool("all", false, "include unexported identifiers in command-line mode") urlFlag = flag.String("url", "", "print HTML for named URL") - // command-line searches - query = flag.Bool("q", false, "arguments are considered search queries") - verbose = flag.Bool("v", false, "verbose mode") // file system roots @@ -85,11 +78,9 @@ var ( goroot = flag.String("goroot", findGOROOT(), "Go root directory") // layout control - tabWidth = flag.Int("tabwidth", 4, "tab width") showTimestamps = flag.Bool("timestamps", false, "show timestamps with directory listings") templateDir = flag.String("templates", "", "load templates/JS/CSS from disk in this directory") showPlayground = flag.Bool("play", false, "enable playground in web interface") - showExamples = flag.Bool("ex", false, "show examples in command line mode") declLinks = flag.Bool("links", true, "link identifiers to their declarations") // search index @@ -104,9 +95,7 @@ var ( ) func usage() { - fmt.Fprintf(os.Stderr, - "usage: godoc package [name ...]\n"+ - " godoc -http="+defaultAddr+"\n") + fmt.Fprintf(os.Stderr, "usage: godoc -http="+defaultAddr+"\n") flag.PrintDefaults() os.Exit(2) } @@ -173,7 +162,7 @@ func main() { // Check usage: server and no args. if (*httpAddr != "" || *urlFlag != "") && (flag.NArg() > 0) { - fmt.Fprintln(os.Stderr, "can't use -http with args.") + fmt.Fprintln(os.Stderr, "Unexpected arguments.") usage() } @@ -183,11 +172,10 @@ func main() { usage() } - // Setting the resolved goroot. + // Set the resolved goroot. vfs.GOROOT = *goroot - var fsGate chan bool - fsGate = make(chan bool, 20) + fsGate := make(chan bool, 20) // Determine file system to use. if *zipfile == "" { @@ -214,8 +202,6 @@ func main() { fs.Bind("/src", gatefs.New(vfs.OS(p), fsGate), "/src", vfs.BindAfter) } - httpMode := *httpAddr != "" - var typeAnalysis, pointerAnalysis bool if *analysisFlag != "" { for _, a := range strings.Split(*analysisFlag, ",") { @@ -233,7 +219,7 @@ func main() { corpus := godoc.NewCorpus(fs) corpus.Verbose = *verbose corpus.MaxResults = *maxResults - corpus.IndexEnabled = *indexEnabled && httpMode + corpus.IndexEnabled = *indexEnabled if *maxResults == 0 { corpus.IndexFullText = false } @@ -245,32 +231,21 @@ func main() { corpus.IndexThrottle = 1.0 corpus.IndexEnabled = true } - if *writeIndex || httpMode || *urlFlag != "" { - if httpMode { - go initCorpus(corpus) - } else { - initCorpus(corpus) - } - } + go initCorpus(corpus) // Initialize the version info before readTemplates, which saves // the map value in a method value. corpus.InitVersionInfo() pres = godoc.NewPresentation(corpus) - pres.TabWidth = *tabWidth pres.ShowTimestamps = *showTimestamps pres.ShowPlayground = *showPlayground - pres.ShowExamples = *showExamples pres.DeclLinks = *declLinks - pres.SrcMode = *srcMode - pres.HTMLMode = *html - pres.AllMode = *allMode if *notesRx != "" { pres.NotesRx = regexp.MustCompile(*notesRx) } - readTemplates(pres, httpMode || *urlFlag != "") + readTemplates(pres) registerHandlers(pres) if *writeIndex { @@ -305,67 +280,51 @@ func main() { return } - if httpMode { - // HTTP server mode. - var handler http.Handler = http.DefaultServeMux - if *verbose { - log.Printf("Go Documentation Server") - log.Printf("version = %s", runtime.Version()) - log.Printf("address = %s", *httpAddr) - log.Printf("goroot = %s", *goroot) - log.Printf("tabwidth = %d", *tabWidth) - switch { - case !*indexEnabled: - log.Print("search index disabled") - case *maxResults > 0: - log.Printf("full text index enabled (maxresults = %d)", *maxResults) - default: - log.Print("identifier search index enabled") + var handler http.Handler = http.DefaultServeMux + if *verbose { + log.Printf("Go Documentation Server") + log.Printf("version = %s", runtime.Version()) + log.Printf("address = %s", *httpAddr) + log.Printf("goroot = %s", *goroot) + switch { + case !*indexEnabled: + log.Print("search index disabled") + case *maxResults > 0: + log.Printf("full text index enabled (maxresults = %d)", *maxResults) + default: + log.Print("identifier search index enabled") + } + fs.Fprint(os.Stderr) + handler = loggingHandler(handler) + } + + // Initialize search index. + if *indexEnabled { + go corpus.RunIndexer() + } + + // Start type/pointer analysis. + if typeAnalysis || pointerAnalysis { + go analysis.Run(pointerAnalysis, &corpus.Analysis) + } + + if runHTTPS != nil { + go func() { + if err := runHTTPS(handler); err != nil { + log.Fatalf("ListenAndServe TLS: %v", err) } - fs.Fprint(os.Stderr) - handler = loggingHandler(handler) - } - - // Initialize search index. - if *indexEnabled { - go corpus.RunIndexer() - } - - // Start type/pointer analysis. - if typeAnalysis || pointerAnalysis { - go analysis.Run(pointerAnalysis, &corpus.Analysis) - } - - if runHTTPS != nil { - go func() { - if err := runHTTPS(handler); err != nil { - log.Fatalf("ListenAndServe TLS: %v", err) - } - }() - } - - // Start http server. - if *verbose { - log.Println("starting HTTP server") - } - if wrapHTTPMux != nil { - handler = wrapHTTPMux(handler) - } - if err := http.ListenAndServe(*httpAddr, handler); err != nil { - log.Fatalf("ListenAndServe %s: %v", *httpAddr, err) - } - - return + }() } - if *query { - handleRemoteSearch() - return + // Start http server. + if *verbose { + log.Println("starting HTTP server") } - - build.Default.GOROOT = *goroot - if err := godoc.CommandLine(os.Stdout, fs, pres, flag.Args()); err != nil { - log.Print(err) + if wrapHTTPMux != nil { + handler = wrapHTTPMux(handler) + } + if err := http.ListenAndServe(*httpAddr, handler); err != nil { + log.Fatalf("ListenAndServe %s: %v", *httpAddr, err) } } diff --git a/cmd/godoc/remotesearch.go b/cmd/godoc/remotesearch.go deleted file mode 100644 index 6f27d0b33a..0000000000 --- a/cmd/godoc/remotesearch.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2009 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. - -// +build !golangorg - -package main - -import ( - "errors" - "flag" - "io" - "log" - "net/http" - "net/url" - "os" -) - -func handleRemoteSearch() { - // Command-line queries. - for i := 0; i < flag.NArg(); i++ { - res, err := remoteSearch(flag.Arg(i)) - if err != nil { - log.Fatalf("remoteSearch: %s", err) - } - io.Copy(os.Stdout, res.Body) - } - return -} - -// remoteSearchURL returns the search URL for a given query as needed by -// remoteSearch. If html is set, an html result is requested; otherwise -// the result is in textual form. -// Adjust this function as necessary if modeNames or FormValue parameters -// change. -func remoteSearchURL(query string, html bool) string { - s := "/search?m=text&q=" - if html { - s = "/search?q=" - } - return s + url.QueryEscape(query) -} - -func remoteSearch(query string) (res *http.Response, err error) { - // list of addresses to try - var addrs []string - if *serverAddr != "" { - // explicit server address - only try this one - addrs = []string{*serverAddr} - } else { - addrs = []string{ - defaultAddr, - "golang.org", - } - } - - // remote search - search := remoteSearchURL(query, *html) - for _, addr := range addrs { - url := "http://" + addr + search - res, err = http.Get(url) - if err == nil && res.StatusCode == http.StatusOK { - break - } - } - - if err == nil && res.StatusCode != http.StatusOK { - err = errors.New(res.Status) - } - - return -} diff --git a/godoc/cmdline.go b/godoc/cmdline.go deleted file mode 100644 index 54f5f7ee7e..0000000000 --- a/godoc/cmdline.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2013 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 godoc - -import ( - "fmt" - "go/ast" - "go/build" - "io" - "log" - "os" - pathpkg "path" - "path/filepath" - "regexp" - "strings" - - "golang.org/x/tools/godoc/vfs" -) - -const ( - target = "/target" - cmdPrefix = "cmd/" - srcPrefix = "src/" - toolsPath = "golang.org/x/tools/cmd/" -) - -// CommandLine returns godoc results to w. -// Note that it may add a /target path to fs. -func CommandLine(w io.Writer, fs vfs.NameSpace, pres *Presentation, args []string) error { - path := args[0] - srcMode := pres.SrcMode - cmdMode := strings.HasPrefix(path, cmdPrefix) - if strings.HasPrefix(path, srcPrefix) { - path = strings.TrimPrefix(path, srcPrefix) - srcMode = true - } - var abspath, relpath string - if cmdMode { - path = strings.TrimPrefix(path, cmdPrefix) - } else { - abspath, relpath = paths(fs, pres, path) - } - - var mode PageInfoMode - if relpath == builtinPkgPath { - // the fake built-in package contains unexported identifiers - mode = NoFiltering | NoTypeAssoc - } - if pres.AllMode { - mode |= NoFiltering - } - if srcMode { - // only filter exports if we don't have explicit command-line filter arguments - if len(args) > 1 { - mode |= NoFiltering - } - mode |= ShowSource - } - - // First, try as package unless forced as command. - var info *PageInfo - if !cmdMode { - info = pres.GetPkgPageInfo(abspath, relpath, mode) - } - - // Second, try as command (if the path is not absolute). - var cinfo *PageInfo - if !filepath.IsAbs(path) { - // First try go.tools/cmd. - abspath = pathpkg.Join(pres.PkgFSRoot(), toolsPath+path) - cinfo = pres.GetCmdPageInfo(abspath, relpath, mode) - if cinfo.IsEmpty() { - // Then try $GOROOT/src/cmd. - abspath = pathpkg.Join(pres.CmdFSRoot(), cmdPrefix, path) - cinfo = pres.GetCmdPageInfo(abspath, relpath, mode) - } - } - - // determine what to use - if info == nil || info.IsEmpty() { - if cinfo != nil && !cinfo.IsEmpty() { - // only cinfo exists - switch to cinfo - info = cinfo - } - } else if cinfo != nil && !cinfo.IsEmpty() { - // both info and cinfo exist - use cinfo if info - // contains only subdirectory information - if info.PAst == nil && info.PDoc == nil { - info = cinfo - } else if relpath != target { - // The above check handles the case where an operating system path - // is provided (see documentation for paths below). In that case, - // relpath is set to "/target" (in anticipation of accessing packages there), - // and is therefore not expected to match a command. - fmt.Fprintf(w, "use 'godoc %s%s' for documentation on the %s command \n\n", cmdPrefix, relpath, relpath) - } - } - - if info == nil { - return fmt.Errorf("%s: no such directory or package", args[0]) - } - if info.Err != nil { - return info.Err - } - - if info.PDoc != nil && info.PDoc.ImportPath == target { - // Replace virtual /target with actual argument from command line. - info.PDoc.ImportPath = args[0] - } - - // If we have more than one argument, use the remaining arguments for filtering. - if len(args) > 1 { - info.IsFiltered = true - filterInfo(args[1:], info) - } - - packageText := pres.PackageText - if pres.HTMLMode { - packageText = pres.PackageHTML - } - if err := packageText.Execute(w, info); err != nil { - return err - } - return nil -} - -// paths determines the paths to use. -// -// If we are passed an operating system path like . or ./foo or /foo/bar or c:\mysrc, -// we need to map that path somewhere in the fs name space so that routines -// like getPageInfo will see it. We use the arbitrarily-chosen virtual path "/target" -// for this. That is, if we get passed a directory like the above, we map that -// directory so that getPageInfo sees it as /target. -// Returns the absolute and relative paths. -func paths(fs vfs.NameSpace, pres *Presentation, path string) (abspath, relpath string) { - if filepath.IsAbs(path) { - fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace) - return target, target - } - if build.IsLocalImport(path) { - cwd, err := os.Getwd() - if err != nil { - log.Printf("error while getting working directory: %v", err) - } - path = filepath.Join(cwd, path) - fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace) - return target, target - } - bp, err := build.Import(path, "", build.FindOnly) - if err != nil { - log.Printf("error while importing build package: %v", err) - } - if bp.Dir != "" && bp.ImportPath != "" { - fs.Bind(target, vfs.OS(bp.Dir), "/", vfs.BindReplace) - return target, bp.ImportPath - } - return pathpkg.Join(pres.PkgFSRoot(), path), path -} - -// filterInfo updates info to include only the nodes that match the given -// filter args. -func filterInfo(args []string, info *PageInfo) { - rx, err := makeRx(args) - if err != nil { - log.Fatalf("illegal regular expression from %v: %v", args, err) - } - - filter := func(s string) bool { return rx.MatchString(s) } - switch { - case info.PAst != nil: - newPAst := map[string]*ast.File{} - for name, a := range info.PAst { - cmap := ast.NewCommentMap(info.FSet, a, a.Comments) - a.Comments = []*ast.CommentGroup{} // remove all comments. - ast.FilterFile(a, filter) - if len(a.Decls) > 0 { - newPAst[name] = a - } - for _, d := range a.Decls { - // add back the comments associated with d only - comments := cmap.Filter(d).Comments() - a.Comments = append(a.Comments, comments...) - } - } - info.PAst = newPAst // add only matching files. - case info.PDoc != nil: - info.PDoc.Filter(filter) - } -} - -// Does s look like a regular expression? -func isRegexp(s string) bool { - return strings.ContainsAny(s, ".(|)*+?^$[]") -} - -// Make a regular expression of the form -// names[0]|names[1]|...names[len(names)-1]. -// Returns an error if the regular expression is illegal. -func makeRx(names []string) (*regexp.Regexp, error) { - if len(names) == 0 { - return nil, fmt.Errorf("no expression provided") - } - s := "" - for i, name := range names { - if i > 0 { - s += "|" - } - if isRegexp(name) { - s += name - } else { - s += "^" + name + "$" // must match exactly - } - } - return regexp.Compile(s) -} diff --git a/godoc/cmdline_test.go b/godoc/cmdline_test.go deleted file mode 100644 index cebbf70ecf..0000000000 --- a/godoc/cmdline_test.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2013 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 godoc - -import ( - "bytes" - "go/build" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "regexp" - "runtime" - "testing" - "text/template" - - "golang.org/x/tools/godoc/vfs" - "golang.org/x/tools/godoc/vfs/mapfs" -) - -// setupGoroot creates temporary directory to act as GOROOT when running tests -// that depend upon the build package. It updates build.Default to point to the -// new GOROOT. -// It returns a function that can be called to reset build.Default and remove -// the temporary directory. -func setupGoroot(t *testing.T) (cleanup func()) { - var stdLib = map[string]string{ - "src/fmt/fmt.go": `// Package fmt implements formatted I/O. -package fmt - -type Stringer interface { - String() string -} -`, - } - goroot, err := ioutil.TempDir("", "cmdline_test") - if err != nil { - t.Fatal(err) - } - origContext := build.Default - build.Default = build.Context{ - GOROOT: goroot, - Compiler: "gc", - } - for relname, contents := range stdLib { - name := filepath.Join(goroot, relname) - if err := os.MkdirAll(filepath.Dir(name), 0770); err != nil { - t.Fatal(err) - } - if err := ioutil.WriteFile(name, []byte(contents), 0770); err != nil { - t.Fatal(err) - } - } - - return func() { - if err := os.RemoveAll(goroot); err != nil { - t.Log(err) - } - build.Default = origContext - } -} - -func TestPaths(t *testing.T) { - cleanup := setupGoroot(t) - defer cleanup() - - pres := &Presentation{ - pkgHandler: handlerServer{ - fsRoot: "/fsroot", - }, - } - fs := make(vfs.NameSpace) - - absPath := "/foo/fmt" - if runtime.GOOS == "windows" { - absPath = `c:\foo\fmt` - } - - for _, tc := range []struct { - desc string - path string - expAbs string - expRel string - }{ - { - "Absolute path", - absPath, - "/target", - "/target", - }, - { - "Local import", - "../foo/fmt", - "/target", - "/target", - }, - { - "Import", - "fmt", - "/target", - "fmt", - }, - { - "Default", - "unknownpkg", - "/fsroot/unknownpkg", - "unknownpkg", - }, - } { - abs, rel := paths(fs, pres, tc.path) - if abs != tc.expAbs || rel != tc.expRel { - t.Errorf("%s: paths(%q) = %s,%s; want %s,%s", tc.desc, tc.path, abs, rel, tc.expAbs, tc.expRel) - } - } -} - -func TestMakeRx(t *testing.T) { - for _, tc := range []struct { - desc string - names []string - exp string - }{ - { - desc: "empty string", - names: []string{""}, - exp: `^$`, - }, - { - desc: "simple text", - names: []string{"a"}, - exp: `^a$`, - }, - { - desc: "two words", - names: []string{"foo", "bar"}, - exp: `^foo$|^bar$`, - }, - { - desc: "word & non-trivial", - names: []string{"foo", `ab?c`}, - exp: `^foo$|ab?c`, - }, - { - desc: "bad regexp", - names: []string{`(."`}, - exp: `(."`, - }, - } { - expRE, expErr := regexp.Compile(tc.exp) - if re, err := makeRx(tc.names); !reflect.DeepEqual(err, expErr) && !reflect.DeepEqual(re, expRE) { - t.Errorf("%s: makeRx(%v) = %q,%q; want %q,%q", tc.desc, tc.names, re, err, expRE, expErr) - } - } -} - -func TestCommandLine(t *testing.T) { - cleanup := setupGoroot(t) - defer cleanup() - mfs := mapfs.New(map[string]string{ - "src/bar/bar.go": `// Package bar is an example. -package bar -`, - "src/foo/foo.go": `// Package foo. -package foo - -// First function is first. -func First() { -} - -// Second function is second. -func Second() { -} - -// unexported function is third. -func unexported() { -} -`, - "src/gen/gen.go": `// Package gen -package gen - -//line notgen.go:3 -// F doc //line 1 should appear -// line 2 should appear -func F() -//line foo.go:100`, // no newline on end to check corner cases! - "src/vet/vet.go": `// Package vet -package vet -`, - "src/cmd/go/doc.go": `// The go command -package main -`, - "src/cmd/gofmt/doc.go": `// The gofmt command -package main -`, - "src/cmd/vet/vet.go": `// The vet command -package main -`, - }) - fs := make(vfs.NameSpace) - fs.Bind("/", mfs, "/", vfs.BindReplace) - c := NewCorpus(fs) - p := &Presentation{Corpus: c} - p.cmdHandler = handlerServer{ - p: p, - c: c, - pattern: "/cmd/", - fsRoot: "/src", - } - p.pkgHandler = handlerServer{ - p: p, - c: c, - pattern: "/pkg/", - fsRoot: "/src", - exclude: []string{"/src/cmd"}, - } - p.initFuncMap() - p.PackageText = template.Must(template.New("PackageText").Funcs(p.FuncMap()).Parse(`{{$info := .}}{{$filtered := .IsFiltered}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}}{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}: -{{node $ $ast}}{{end}}{{end}}{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND {{.Doc}}{{else}}PACKAGE {{.Doc}}{{end}}{{with .Funcs}} -{{range .}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}}{{end}}{{end}}{{end}}`)) - - for _, tc := range []struct { - desc string - args []string - all bool - exp string - err bool - }{ - { - desc: "standard package", - args: []string{"fmt"}, - exp: "PACKAGE Package fmt implements formatted I/O.\n", - }, - { - desc: "package", - args: []string{"bar"}, - exp: "PACKAGE Package bar is an example.\n", - }, - { - desc: "package w. filter", - args: []string{"foo", "First"}, - exp: "PACKAGE \nfunc First()\n First function is first.\n", - }, - { - desc: "package w. bad filter", - args: []string{"foo", "DNE"}, - exp: "PACKAGE ", - }, - { - desc: "source mode", - args: []string{"src/bar"}, - exp: "bar/bar.go:\n// Package bar is an example.\npackage bar\n", - }, - { - desc: "source mode w. filter", - args: []string{"src/foo", "Second"}, - exp: "// Second function is second.\nfunc Second() {\n}", - }, - { - desc: "package w. unexported filter", - args: []string{"foo", "unexported"}, - all: true, - exp: "PACKAGE \nfunc unexported()\n unexported function is third.\n", - }, - { - desc: "package w. unexported filter", - args: []string{"foo", "unexported"}, - all: false, - exp: "PACKAGE ", - }, - { - desc: "package w. //line comments", - args: []string{"gen", "F"}, - exp: "PACKAGE \nfunc F()\n F doc //line 1 should appear line 2 should appear\n", - }, - { - desc: "command", - args: []string{"go"}, - exp: "COMMAND The go command\n", - }, - { - desc: "forced command", - args: []string{"cmd/gofmt"}, - exp: "COMMAND The gofmt command\n", - }, - { - desc: "bad arg", - args: []string{"doesnotexist"}, - err: true, - }, - { - desc: "both command and package", - args: []string{"vet"}, - exp: "use 'godoc cmd/vet' for documentation on the vet command \n\nPACKAGE Package vet\n", - }, - { - desc: "root directory", - args: []string{"/"}, - exp: "", - }, - } { - p.AllMode = tc.all - w := new(bytes.Buffer) - err := CommandLine(w, fs, p, tc.args) - if got, want := w.String(), tc.exp; got != want || tc.err == (err == nil) { - t.Errorf("%s: CommandLine(%v), All(%v) = %q (%v); want %q (%v)", - tc.desc, tc.args, tc.all, got, err, want, tc.err) - } - } -} diff --git a/godoc/godoc.go b/godoc/godoc.go index 0acb49bf75..5add835fc3 100644 --- a/godoc/godoc.go +++ b/godoc/godoc.go @@ -77,7 +77,6 @@ func (p *Presentation) initFuncMap() { "node": p.nodeFunc, "node_html": p.node_htmlFunc, "comment_html": comment_htmlFunc, - "comment_text": comment_textFunc, "sanitize": sanitizeFunc, // support for URL attributes @@ -91,7 +90,6 @@ func (p *Presentation) initFuncMap() { // formatting of Examples "example_html": p.example_htmlFunc, - "example_text": p.example_textFunc, "example_name": p.example_nameFunc, "example_suffix": p.example_suffixFunc, @@ -372,15 +370,6 @@ func containsOnlySpace(buf []byte) bool { return bytes.IndexFunc(buf, isNotSpace) == -1 } -func comment_textFunc(comment, indent, preIndent string) string { - var buf bytes.Buffer - doc.ToText(&buf, comment, indent, preIndent, punchCardWidth-2*len(indent)) - if containsOnlySpace(buf.Bytes()) { - return "" - } - return buf.String() -} - // sanitizeFunc sanitizes the argument src by replacing newlines with // blanks, removing extra blanks, and by removing trailing whitespace // and commas before closing parentheses. @@ -589,50 +578,6 @@ func docLinkFunc(s string, ident string) string { return pathpkg.Clean("/pkg/"+s) + "/#" + ident } -func (p *Presentation) example_textFunc(info *PageInfo, funcName, indent string) string { - if !p.ShowExamples { - return "" - } - - var buf bytes.Buffer - first := true - for _, eg := range info.Examples { - name := stripExampleSuffix(eg.Name) - if name != funcName { - continue - } - - if !first { - buf.WriteString("\n") - } - first = false - - // print code - cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments} - config := &printer.Config{Mode: printer.UseSpaces, Tabwidth: p.TabWidth} - var buf1 bytes.Buffer - config.Fprint(&buf1, info.FSet, cnode) - code := buf1.String() - - // Additional formatting if this is a function body. Unfortunately, we - // can't print statements individually because we would lose comments - // on later statements. - if n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' { - // remove surrounding braces - code = code[1 : n-1] - // unindent - code = replaceLeadingIndentation(code, strings.Repeat(" ", p.TabWidth), indent) - } - code = strings.Trim(code, "\n") - - buf.WriteString(indent) - buf.WriteString("Example:\n") - buf.WriteString(code) - buf.WriteString("\n\n") - } - return buf.String() -} - func (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string { var buf bytes.Buffer for _, eg := range info.Examples { diff --git a/godoc/pres.go b/godoc/pres.go index b0077fd581..800937af48 100644 --- a/godoc/pres.go +++ b/godoc/pres.go @@ -34,12 +34,10 @@ type Presentation struct { MethodSetHTML, PackageHTML, PackageRootHTML, - PackageText, SearchHTML, SearchDocHTML, SearchCodeHTML, SearchTxtHTML, - SearchText, SearchDescXML *template.Template // TabWidth optionally specifies the tab width. @@ -47,7 +45,6 @@ type Presentation struct { ShowTimestamps bool ShowPlayground bool - ShowExamples bool DeclLinks bool // SrcMode outputs source code instead of documentation in command-line mode. @@ -113,9 +110,8 @@ func NewPresentation(c *Corpus) *Presentation { mux: http.NewServeMux(), fileServer: http.FileServer(httpfs.New(c.fs)), - TabWidth: 4, - ShowExamples: true, - DeclLinks: true, + TabWidth: 4, + DeclLinks: true, SearchResults: []SearchResultFunc{ (*Presentation).SearchResultDoc, (*Presentation).SearchResultCode, diff --git a/godoc/search.go b/godoc/search.go index d61193f218..870aefc018 100644 --- a/godoc/search.go +++ b/godoc/search.go @@ -99,11 +99,7 @@ func (p *Presentation) HandleSearch(w http.ResponseWriter, r *http.Request) { query := strings.TrimSpace(r.FormValue("q")) result := p.Corpus.Lookup(query) - if p.GetPageInfoMode(r)&NoHTML != 0 { - p.ServeText(w, applyTemplate(p.SearchText, "searchText", result)) - return - } - contents := bytes.Buffer{} + var contents bytes.Buffer for _, f := range p.SearchResults { contents.Write(f(p, result)) } diff --git a/godoc/server.go b/godoc/server.go index 2998967f4c..39f6922c89 100644 --- a/godoc/server.go +++ b/godoc/server.go @@ -276,11 +276,6 @@ func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - if mode&NoHTML != 0 { - h.p.ServeText(w, applyTemplate(h.p.PackageText, "packageText", info)) - return - } - var tabtitle, title, subtitle string switch { case info.PAst != nil: diff --git a/godoc/static/gen.go b/godoc/static/gen.go index 399fb84e09..76f7d34b37 100644 --- a/godoc/static/gen.go +++ b/godoc/static/gen.go @@ -57,11 +57,9 @@ var files = []string{ "opensearch.xml", "package.html", "packageroot.html", - "package.txt", "play.js", "playground.js", "search.html", - "search.txt", "searchcode.html", "searchdoc.html", "searchtxt.html", diff --git a/godoc/static/package.txt b/godoc/static/package.txt deleted file mode 100644 index e53fa6ed38..0000000000 --- a/godoc/static/package.txt +++ /dev/null @@ -1,116 +0,0 @@ -{{$info := .}}{{$filtered := .IsFiltered}}{{/* - ---------------------------------------- - -*/}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}} - -{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}: -{{node $ $ast}}{{end}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if and $filtered (not (or .PDoc .PAst))}}No match found. -{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND DOCUMENTATION - -{{comment_text .Doc " " "\t"}} -{{else}}{{if not $filtered}}PACKAGE DOCUMENTATION - -package {{.Name}} - import "{{.ImportPath}}" - -{{comment_text .Doc " " "\t"}} -{{example_text $ "" " "}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with .Consts}}{{if not $filtered}}CONSTANTS - -{{end}}{{range .}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with .Vars}}{{if not $filtered}}VARIABLES - -{{end}}{{range .}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with .Funcs}}{{if not $filtered}}FUNCTIONS - -{{end}}{{range .}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{example_text $ .Name " "}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with .Types}}{{if not $filtered}}TYPES - -{{end}}{{range .}}{{$tname := .Name}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{/* - ---------------------------------------- - -*/}}{{if .Consts}}{{range .Consts}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if .Vars}}{{range .Vars}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{range $name := .Names}}{{example_text $ $name " "}}{{end}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if .Funcs}}{{range .Funcs}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{example_text $ .Name " "}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if .Methods}}{{range .Methods}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{$name := printf "%s_%s" $tname .Name}}{{example_text $ $name " "}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if and $filtered (not (or .Consts (or .Vars (or .Funcs .Types))))}}No match found. -{{end}}{{/* - ---------------------------------------- - -*/}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with $.Notes}} -{{range $marker, $content := .}} -{{$marker}}S - -{{range $content}}{{comment_text .Body " " "\t"}} -{{end}}{{end}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if not $filtered}}{{with .Dirs}}SUBDIRECTORIES -{{if $.DirFlat}}{{range .List}}{{if .HasPkg}} - {{.Path}}{{end}}{{end}} -{{else}}{{range .List}} - {{repeat `. ` .Depth}}{{.Name}}{{end}} -{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{end}}{{/* -Make sure there is no newline at the end of this file. -perl -i -pe 'chomp if eof' package.txt -*/}} diff --git a/godoc/static/search.txt b/godoc/static/search.txt deleted file mode 100644 index 0ae0c080db..0000000000 --- a/godoc/static/search.txt +++ /dev/null @@ -1,54 +0,0 @@ -QUERY - {{.Query}} - -{{with .Alert}}{{.}} -{{end}}{{/* .Alert */}}{{/* - ---------------------------------------- - -*/}}{{with .Alt}}DID YOU MEAN - -{{range .Alts}} {{.}} -{{end}} -{{end}}{{/* .Alt */}}{{/* - ---------------------------------------- - -*/}}{{with .Pak}}PACKAGE {{$.Query}} - -{{range .}} {{pkgLink .Pak.Path}} -{{end}} -{{end}}{{/* .Pak */}}{{/* - ---------------------------------------- - -*/}}{{range $key, $val := .Idents}}{{if $val}}{{$key.Name}} -{{range $val}} {{.Path}}.{{.Name}} -{{end}} -{{end}}{{end}}{{/* .Idents */}}{{/* - ---------------------------------------- - -*/}}{{with .Hit}}{{with .Decls}}PACKAGE-LEVEL DECLARATIONS - -{{range .}}package {{.Pak.Name}} -{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}}{{end}} -{{end}}{{end}}{{/* .Files */}} -{{end}}{{end}}{{/* .Decls */}}{{/* - ---------------------------------------- - -*/}}{{with .Others}}LOCAL DECLARATIONS AND USES - -{{range .}}package {{.Pak.Name}} -{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}} -{{end}}{{end}}{{end}}{{/* .Files */}} -{{end}}{{end}}{{/* .Others */}}{{end}}{{/* .Hit */}}{{/* - ---------------------------------------- - -*/}}{{if .Textual}}{{if .Complete}}{{.Found}} TEXTUAL OCCURRENCES{{else}}MORE THAN {{.Found}} TEXTUAL OCCURRENCES{{end}} - -{{range .Textual}}{{len .Lines}} {{srcLink .Filename}} -{{end}}{{if not .Complete}}... ... -{{end}}{{end}} diff --git a/godoc/static/static.go b/godoc/static/static.go index 0fc0b40674..626b13465d 100644 --- a/godoc/static/static.go +++ b/godoc/static/static.go @@ -89,16 +89,12 @@ var Files = map[string]string{ "packageroot.html": "\x0a\x0a{{with\x20.PAst}}\x0a\x09{{range\x20$filename,\x20$ast\x20:=\x20.}}\x0a\x09\x09{{$filename|filename|html}}:
{{node_html\x20$\x20$ast\x20false}}
\x0a\x09{{end}}\x0a{{end}}\x0a\x0a{{with\x20.Dirs}}\x0a\x09{{/*\x20DirList\x20entries\x20are\x20numbers\x20and\x20strings\x20-\x20no\x20need\x20for\x20FSet\x20*/}}\x0a\x09{{if\x20$.PDoc}}\x0a\x09\x09Subdirectories\x0a\x09{{end}}\x0a\x09\x09\x0a\x09\x09\x09
\x0a\x09\x09\x09\x09
Standard\x20library
\x0a\x09\x09\x09\x09{{if\x20hasThirdParty\x20.List\x20}}\x0a\x09\x09\x09\x09\x09
Third\x20party
\x0a\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09
Other\x20packages
\x0a\x09\x09\x09\x09
Sub-repositories
\x0a\x09\x09\x09\x09
Community
\x0a\x09\x09\x09
\x0a\x09\x09\x0a\x0a\x09\x09\x0a\x09\x09\x09\x0a\x09\x09\x09\x09Standard\x20library\x20\xe2\x96\xb9\x0a\x09\x09\x09\x0a\x09\x09\x09\x0a\x09\x09\x09\x09Standard\x20library\x20\xe2\x96\xbe\x0a\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09Name\x0a\x09\x09\x09\x09\x09\x09\x09Synopsis\x0a\x09\x09\x09\x09\x09\x09\x0a\x0a\x09\x09\x09\x09\x09\x09{{range\x20.List}}\x0a\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09{{if\x20eq\x20.RootType\x20\"GOROOT\"}}\x0a\x09\x09\x09\x09\x09\x09\x09{{if\x20$.DirFlat}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09{{if\x20.HasPkg}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Path}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09{{else}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Name}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Synopsis}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09
\x0a\x09\x09\x09\x09\x20\x0a\x09\x09\x09\x20\x0a\x09\x09\x20\x0a\x0a\x09{{if\x20hasThirdParty\x20.List\x20}}\x0a\x09\x09\x0a\x09\x09\x09\x0a\x09\x09\x09\x09Third\x20party\x20\xe2\x96\xb9\x0a\x09\x09\x09\x0a\x09\x09\x09\x0a\x09\x09\x09\x09Third\x20party\x20\xe2\x96\xbe\x0a\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09Name\x0a\x09\x09\x09\x09\x09\x09\x09Synopsis\x0a\x09\x09\x09\x09\x09\x09\x0a\x0a\x09\x09\x09\x09\x09\x09{{range\x20.List}}\x0a\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09{{if\x20eq\x20.RootType\x20\"GOPATH\"}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09{{if\x20$.DirFlat}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09{{if\x20.HasPkg}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Path}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09{{else}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Name}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Synopsis}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09
\x0a\x09\x09\x09\x09\x20\x0a\x09\x09\x09\x20\x0a\x09\x09\x20\x0a\x09{{end}}\x0a\x0a\x09Other\x20packages\x0a\x09Sub-repositories\x0a\x09

\x0a\x09These\x20packages\x20are\x20part\x20of\x20the\x20Go\x20Project\x20but\x20outside\x20the\x20main\x20Go\x20tree.\x0a\x09They\x20are\x20developed\x20under\x20looser\x20compatibility\x20requirements\x20than\x20the\x20Go\x20core.\x0a\x09Install\x20them\x20with\x20\"go\x20get\".\x0a\x09

\x0a\x09
    \x0a\x09\x09
  • benchmarks\x20\xe2\x80\x94\x20benchmarks\x20to\x20measure\x20Go\x20as\x20it\x20is\x20developed.
  • \x0a\x09\x09
  • blog\x20\xe2\x80\x94\x20blog.golang.org's\x20implementation.
  • \x0a\x09\x09
  • build\x20\xe2\x80\x94\x20build.golang.org's\x20implementation.
  • \x0a\x09\x09
  • crypto\x20\xe2\x80\x94\x20additional\x20cryptography\x20packages.
  • \x0a\x09\x09
  • debug\x20\xe2\x80\x94\x20an\x20experimental\x20debugger\x20for\x20Go.
  • \x0a\x09\x09
  • image\x20\xe2\x80\x94\x20additional\x20imaging\x20packages.
  • \x0a\x09\x09
  • mobile\x20\xe2\x80\x94\x20experimental\x20support\x20for\x20Go\x20on\x20mobile\x20platforms.
  • \x0a\x09\x09
  • net\x20\xe2\x80\x94\x20additional\x20networking\x20packages.
  • \x0a\x09\x09
  • perf\x20\xe2\x80\x94\x20packages\x20and\x20tools\x20for\x20performance\x20measurement,\x20storage,\x20and\x20analysis.
  • \x0a\x09\x09
  • review\x20\xe2\x80\x94\x20a\x20tool\x20for\x20working\x20with\x20Gerrit\x20code\x20reviews.
  • \x0a\x09\x09
  • sync\x20\xe2\x80\x94\x20additional\x20concurrency\x20primitives.
  • \x0a\x09\x09
  • sys\x20\xe2\x80\x94\x20packages\x20for\x20making\x20system\x20calls.
  • \x0a\x09\x09
  • text\x20\xe2\x80\x94\x20packages\x20for\x20working\x20with\x20text.
  • \x0a\x09\x09
  • time\x20\xe2\x80\x94\x20additional\x20time\x20packages.
  • \x0a\x09\x09
  • tools\x20\xe2\x80\x94\x20godoc,\x20goimports,\x20gorename,\x20and\x20other\x20tools.
  • \x0a\x09\x09
  • tour\x20\xe2\x80\x94\x20tour.golang.org's\x20implementation.
  • \x0a\x09\x09
  • exp\x20\xe2\x80\x94\x20experimental\x20and\x20deprecated\x20packages\x20(handle\x20with\x20care;\x20may\x20change\x20without\x20warning).
  • \x0a\x09
\x0a\x0a\x09Community\x0a\x09

\x0a\x09These\x20services\x20can\x20help\x20you\x20find\x20Open\x20Source\x20packages\x20provided\x20by\x20the\x20community.\x0a\x09

\x0a\x09
    \x0a\x09\x09
  • GoDoc\x20-\x20a\x20package\x20index\x20and\x20search\x20engine.
  • \x0a\x09\x09
  • Go\x20Search\x20-\x20a\x20code\x20search\x20engine.
  • \x0a\x09\x09
  • Projects\x20at\x20the\x20Go\x20Wiki\x20-\x20a\x20curated\x20list\x20of\x20Go\x20projects.
  • \x0a\x09
\x0a{{end}}\x0a", - "package.txt": "{{$info\x20:=\x20.}}{{$filtered\x20:=\x20.IsFiltered}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20$filtered}}{{range\x20.PAst}}{{range\x20.Decls}}{{node\x20$info\x20.}}\x0a\x0a{{end}}{{end}}{{else}}{{with\x20.PAst}}{{range\x20$filename,\x20$ast\x20:=\x20.}}{{$filename}}:\x0a{{node\x20$\x20$ast}}{{end}}{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20and\x20$filtered\x20(not\x20(or\x20.PDoc\x20.PAst))}}No\x20match\x20found.\x0a{{end}}{{with\x20.PDoc}}{{if\x20$.IsMain}}COMMAND\x20DOCUMENTATION\x0a\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{else}}{{if\x20not\x20$filtered}}PACKAGE\x20DOCUMENTATION\x0a\x0apackage\x20{{.Name}}\x0a\x20\x20\x20\x20import\x20\"{{.ImportPath}}\"\x0a\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{example_text\x20$\x20\"\"\x20\"\x20\x20\x20\x20\"}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Consts}}{{if\x20not\x20$filtered}}CONSTANTS\x0a\x0a{{end}}{{range\x20.}}{{node\x20$\x20.Decl}}\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Vars}}{{if\x20not\x20$filtered}}VARIABLES\x0a\x0a{{end}}{{range\x20.}}{{node\x20$\x20.Decl}}\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Funcs}}{{if\x20not\x20$filtered}}FUNCTIONS\x0a\x0a{{end}}{{range\x20.}}{{node\x20$\x20.Decl}}\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{example_text\x20$\x20.Name\x20\"\x20\x20\x20\x20\"}}{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Types}}{{if\x20not\x20$filtered}}TYPES\x0a\x0a{{end}}{{range\x20.}}{{$tname\x20:=\x20.Name}}{{node\x20$\x20.Decl}}\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20.Consts}}{{range\x20.Consts}}{{node\x20$\x20.Decl}}\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20.Vars}}{{range\x20.Vars}}{{node\x20$\x20.Decl}}\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{range\x20$name\x20:=\x20.Names}}{{example_text\x20$\x20$name\x20\"\x20\x20\x20\x20\"}}{{end}}{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20.Funcs}}{{range\x20.Funcs}}{{node\x20$\x20.Decl}}\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{example_text\x20$\x20.Name\x20\"\x20\x20\x20\x20\"}}{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20.Methods}}{{range\x20.Methods}}{{node\x20$\x20.Decl}}\x0a{{comment_text\x20.Doc\x20\"\x20\x20\x20\x20\"\x20\"\\t\"}}\x0a{{$name\x20:=\x20printf\x20\"%s_%s\"\x20$tname\x20.Name}}{{example_text\x20$\x20$name\x20\"\x20\x20\x20\x20\"}}{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20and\x20$filtered\x20(not\x20(or\x20.Consts\x20(or\x20.Vars\x20(or\x20.Funcs\x20.Types))))}}No\x20match\x20found.\x0a{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20$.Notes}}\x0a{{range\x20$marker,\x20$content\x20:=\x20.}}\x0a{{$marker}}S\x0a\x0a{{range\x20$content}}{{comment_text\x20.Body\x20\"\x20\x20\x20\"\x20\"\\t\"}}\x0a{{end}}{{end}}{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20not\x20$filtered}}{{with\x20.Dirs}}SUBDIRECTORIES\x0a{{if\x20$.DirFlat}}{{range\x20.List}}{{if\x20.HasPkg}}\x0a\x09{{.Path}}{{end}}{{end}}\x0a{{else}}{{range\x20.List}}\x0a\x09{{repeat\x20`.\x20`\x20.Depth}}{{.Name}}{{end}}\x0a{{end}}{{end}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{end}}{{/*\x0aMake\x20sure\x20there\x20is\x20no\x20newline\x20at\x20the\x20end\x20of\x20this\x20file.\x0aperl\x20-i\x20-pe\x20'chomp\x20if\x20eof'\x20package.txt\x0a*/}}\x0a", - "play.js": "//\x20Copyright\x202012\x20The\x20Go\x20Authors.\x20All\x20rights\x20reserved.\x0a//\x20Use\x20of\x20this\x20source\x20code\x20is\x20governed\x20by\x20a\x20BSD-style\x0a//\x20license\x20that\x20can\x20be\x20found\x20in\x20the\x20LICENSE\x20file.\x0a\x0afunction\x20initPlayground(transport)\x20{\x0a\x09'use\x20strict';\x0a\x0a\x09function\x20text(node)\x20{\x0a\x09\x09var\x20s\x20=\x20'';\x0a\x09\x09for\x20(var\x20i\x20=\x200;\x20i\x20<\x20node.childNodes.length;\x20i++)\x20{\x0a\x09\x09\x09var\x20n\x20=\x20node.childNodes[i];\x0a\x09\x09\x09if\x20(n.nodeType\x20===\x201)\x20{\x0a\x09\x09\x09\x09if\x20(n.tagName\x20===\x20'BUTTON')\x20continue\x0a\x09\x09\x09\x09if\x20(n.tagName\x20===\x20'SPAN'\x20&&\x20n.className\x20===\x20'number')\x20continue;\x0a\x09\x09\x09\x09if\x20(n.tagName\x20===\x20'DIV'\x20||\x20n.tagName\x20==\x20'BR')\x20{\x0a\x09\x09\x09\x09\x09s\x20+=\x20\"\\n\";\x0a\x09\x09\x09\x09}\x0a\x09\x09\x09\x09s\x20+=\x20text(n);\x0a\x09\x09\x09\x09continue;\x0a\x09\x09\x09}\x0a\x09\x09\x09if\x20(n.nodeType\x20===\x203)\x20{\x0a\x09\x09\x09\x09s\x20+=\x20n.nodeValue;\x0a\x09\x09\x09}\x0a\x09\x09}\x0a\x09\x09return\x20s.replace('\\xA0',\x20'\x20');\x20//\x20replace\x20non-breaking\x20spaces\x0a\x09}\x0a\x0a\x09//\x20When\x20presenter\x20notes\x20are\x20enabled,\x20the\x20index\x20passed\x0a\x09//\x20here\x20will\x20identify\x20the\x20playground\x20to\x20be\x20synced\x0a\x09function\x20init(code,\x20index)\x20{\x0a\x09\x09var\x20output\x20=\x20document.createElement('div');\x0a\x09\x09var\x20outpre\x20=\x20document.createElement('pre');\x0a\x09\x09var\x20running;\x0a\x0a\x09\x09if\x20($\x20&&\x20$(output).resizable)\x20{\x0a\x09\x09\x09$(output).resizable({\x0a\x09\x09\x09\x09handles:\x20\x09'n,w,nw',\x0a\x09\x09\x09\x09minHeight:\x0927,\x0a\x09\x09\x09\x09minWidth:\x09135,\x0a\x09\x09\x09\x09maxHeight:\x09608,\x0a\x09\x09\x09\x09maxWidth:\x09990\x0a\x09\x09\x09});\x0a\x09\x09}\x0a\x0a\x09\x09function\x20onKill()\x20{\x0a\x09\x09\x09if\x20(running)\x20running.Kill();\x0a\x09\x09\x09if\x20(window.notesEnabled)\x20updatePlayStorage('onKill',\x20index);\x0a\x09\x09}\x0a\x0a\x09\x09function\x20onRun(e)\x20{\x0a\x09\x09\x09var\x20sk\x20=\x20e.shiftKey\x20||\x20localStorage.getItem('play-shiftKey')\x20===\x20'true';\x0a\x09\x09\x09if\x20(running)\x20running.Kill();\x0a\x09\x09\x09output.style.display\x20=\x20'block';\x0a\x09\x09\x09outpre.innerHTML\x20=\x20'';\x0a\x09\x09\x09run1.style.display\x20=\x20'none';\x0a\x09\x09\x09var\x20options\x20=\x20{Race:\x20sk};\x0a\x09\x09\x09running\x20=\x20transport.Run(text(code),\x20PlaygroundOutput(outpre),\x20options);\x0a\x09\x09\x09if\x20(window.notesEnabled)\x20updatePlayStorage('onRun',\x20index,\x20e);\x0a\x09\x09}\x0a\x0a\x09\x09function\x20onClose()\x20{\x0a\x09\x09\x09if\x20(running)\x20running.Kill();\x0a\x09\x09\x09output.style.display\x20=\x20'none';\x0a\x09\x09\x09run1.style.display\x20=\x20'inline-block';\x0a\x09\x09\x09if\x20(window.notesEnabled)\x20updatePlayStorage('onClose',\x20index);\x0a\x09\x09}\x0a\x0a\x09\x09if\x20(window.notesEnabled)\x20{\x0a\x09\x09\x09playgroundHandlers.onRun.push(onRun);\x0a\x09\x09\x09playgroundHandlers.onClose.push(onClose);\x0a\x09\x09\x09playgroundHandlers.onKill.push(onKill);\x0a\x09\x09}\x0a\x0a\x09\x09var\x20run1\x20=\x20document.createElement('button');\x0a\x09\x09run1.innerHTML\x20=\x20'Run';\x0a\x09\x09run1.className\x20=\x20'run';\x0a\x09\x09run1.addEventListener(\"click\",\x20onRun,\x20false);\x0a\x09\x09var\x20run2\x20=\x20document.createElement('button');\x0a\x09\x09run2.className\x20=\x20'run';\x0a\x09\x09run2.innerHTML\x20=\x20'Run';\x0a\x09\x09run2.addEventListener(\"click\",\x20onRun,\x20false);\x0a\x09\x09var\x20kill\x20=\x20document.createElement('button');\x0a\x09\x09kill.className\x20=\x20'kill';\x0a\x09\x09kill.innerHTML\x20=\x20'Kill';\x0a\x09\x09kill.addEventListener(\"click\",\x20onKill,\x20false);\x0a\x09\x09var\x20close\x20=\x20document.createElement('button');\x0a\x09\x09close.className\x20=\x20'close';\x0a\x09\x09close.innerHTML\x20=\x20'Close';\x0a\x09\x09close.addEventListener(\"click\",\x20onClose,\x20false);\x0a\x0a\x09\x09var\x20button\x20=\x20document.createElement('div');\x0a\x09\x09button.classList.add('buttons');\x0a\x09\x09button.appendChild(run1);\x0a\x09\x09//\x20Hack\x20to\x20simulate\x20insertAfter\x0a\x09\x09code.parentNode.insertBefore(button,\x20code.nextSibling);\x0a\x0a\x09\x09var\x20buttons\x20=\x20document.createElement('div');\x0a\x09\x09buttons.classList.add('buttons');\x0a\x09\x09buttons.appendChild(run2);\x0a\x09\x09buttons.appendChild(kill);\x0a\x09\x09buttons.appendChild(close);\x0a\x0a\x09\x09output.classList.add('output');\x0a\x09\x09output.appendChild(buttons);\x0a\x09\x09output.appendChild(outpre);\x0a\x09\x09output.style.display\x20=\x20'none';\x0a\x09\x09code.parentNode.insertBefore(output,\x20button.nextSibling);\x0a\x09}\x0a\x0a\x09var\x20play\x20=\x20document.querySelectorAll('div.playground');\x0a\x09for\x20(var\x20i\x20=\x200;\x20i\x20<\x20play.length;\x20i++)\x20{\x0a\x09\x09init(play[i],\x20i);\x0a\x09}\x0a}\x0a", "playground.js": "//\x20Copyright\x202012\x20The\x20Go\x20Authors.\x20All\x20rights\x20reserved.\x0a//\x20Use\x20of\x20this\x20source\x20code\x20is\x20governed\x20by\x20a\x20BSD-style\x0a//\x20license\x20that\x20can\x20be\x20found\x20in\x20the\x20LICENSE\x20file.\x0a\x0a/*\x0aIn\x20the\x20absence\x20of\x20any\x20formal\x20way\x20to\x20specify\x20interfaces\x20in\x20JavaScript,\x0ahere's\x20a\x20skeleton\x20implementation\x20of\x20a\x20playground\x20transport.\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20function\x20Transport()\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Set\x20up\x20any\x20transport\x20state\x20(eg,\x20make\x20a\x20websocket\x20connection).\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Run:\x20function(body,\x20output,\x20options)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Compile\x20and\x20run\x20the\x20program\x20'body'\x20with\x20'options'.\x0a\x09\x09\x09\x09//\x20Call\x20the\x20'output'\x20callback\x20to\x20display\x20program\x20output.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Kill:\x20function()\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Kill\x20the\x20running\x20program.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20};\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20};\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x0a\x09//\x20The\x20output\x20callback\x20is\x20called\x20multiple\x20times,\x20and\x20each\x20time\x20it\x20is\x0a\x09//\x20passed\x20an\x20object\x20of\x20this\x20form.\x0a\x20\x20\x20\x20\x20\x20\x20\x20var\x20write\x20=\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Kind:\x20'string',\x20//\x20'start',\x20'stdout',\x20'stderr',\x20'end'\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Body:\x20'string'\x20\x20//\x20content\x20of\x20write\x20or\x20end\x20status\x20message\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x0a\x09//\x20The\x20first\x20call\x20must\x20be\x20of\x20Kind\x20'start'\x20with\x20no\x20body.\x0a\x09//\x20Subsequent\x20calls\x20may\x20be\x20of\x20Kind\x20'stdout'\x20or\x20'stderr'\x0a\x09//\x20and\x20must\x20have\x20a\x20non-null\x20Body\x20string.\x0a\x09//\x20The\x20final\x20call\x20should\x20be\x20of\x20Kind\x20'end'\x20with\x20an\x20optional\x0a\x09//\x20Body\x20string,\x20signifying\x20a\x20failure\x20(\"killed\",\x20for\x20example).\x0a\x0a\x09//\x20The\x20output\x20callback\x20must\x20be\x20of\x20this\x20form.\x0a\x09//\x20See\x20PlaygroundOutput\x20(below)\x20for\x20an\x20implementation.\x0a\x20\x20\x20\x20\x20\x20\x20\x20function\x20outputCallback(write)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a*/\x0a\x0a//\x20HTTPTransport\x20is\x20the\x20default\x20transport.\x0a//\x20enableVet\x20enables\x20running\x20vet\x20if\x20a\x20program\x20was\x20compiled\x20and\x20ran\x20successfully.\x0a//\x20If\x20vet\x20returned\x20any\x20errors,\x20display\x20them\x20before\x20the\x20output\x20of\x20a\x20program.\x0afunction\x20HTTPTransport(enableVet)\x20{\x0a\x09'use\x20strict';\x0a\x0a\x09function\x20playback(output,\x20events)\x20{\x0a\x09\x09var\x20timeout;\x0a\x09\x09output({Kind:\x20'start'});\x0a\x09\x09function\x20next()\x20{\x0a\x09\x09\x09if\x20(!events\x20||\x20events.length\x20===\x200)\x20{\x0a\x09\x09\x09\x09output({Kind:\x20'end'});\x0a\x09\x09\x09\x09return;\x0a\x09\x09\x09}\x0a\x09\x09\x09var\x20e\x20=\x20events.shift();\x0a\x09\x09\x09if\x20(e.Delay\x20===\x200)\x20{\x0a\x09\x09\x09\x09output({Kind:\x20e.Kind,\x20Body:\x20e.Message});\x0a\x09\x09\x09\x09next();\x0a\x09\x09\x09\x09return;\x0a\x09\x09\x09}\x0a\x09\x09\x09timeout\x20=\x20setTimeout(function()\x20{\x0a\x09\x09\x09\x09output({Kind:\x20e.Kind,\x20Body:\x20e.Message});\x0a\x09\x09\x09\x09next();\x0a\x09\x09\x09},\x20e.Delay\x20/\x201000000);\x0a\x09\x09}\x0a\x09\x09next();\x0a\x09\x09return\x20{\x0a\x09\x09\x09Stop:\x20function()\x20{\x0a\x09\x09\x09\x09clearTimeout(timeout);\x0a\x09\x09\x09}\x0a\x09\x09};\x0a\x09}\x0a\x0a\x09function\x20error(output,\x20msg)\x20{\x0a\x09\x09output({Kind:\x20'start'});\x0a\x09\x09output({Kind:\x20'stderr',\x20Body:\x20msg});\x0a\x09\x09output({Kind:\x20'end'});\x0a\x09}\x0a\x0a\x09var\x20seq\x20=\x200;\x0a\x09return\x20{\x0a\x09\x09Run:\x20function(body,\x20output,\x20options)\x20{\x0a\x09\x09\x09seq++;\x0a\x09\x09\x09var\x20cur\x20=\x20seq;\x0a\x09\x09\x09var\x20playing;\x0a\x09\x09\x09$.ajax('/compile',\x20{\x0a\x09\x09\x09\x09type:\x20'POST',\x0a\x09\x09\x09\x09data:\x20{'version':\x202,\x20'body':\x20body},\x0a\x09\x09\x09\x09dataType:\x20'json',\x0a\x09\x09\x09\x09success:\x20function(data)\x20{\x0a\x09\x09\x09\x09\x09if\x20(seq\x20!=\x20cur)\x20return;\x0a\x09\x09\x09\x09\x09if\x20(!data)\x20return;\x0a\x09\x09\x09\x09\x09if\x20(playing\x20!=\x20null)\x20playing.Stop();\x0a\x09\x09\x09\x09\x09if\x20(data.Errors)\x20{\x0a\x09\x09\x09\x09\x09\x09error(output,\x20data.Errors);\x0a\x09\x09\x09\x09\x09\x09return;\x0a\x09\x09\x09\x09\x09}\x0a\x0a\x09\x09\x09\x09\x09if\x20(!enableVet)\x20{\x0a\x09\x09\x09\x09\x09\x09playing\x20=\x20playback(output,\x20data.Events);\x0a\x09\x09\x09\x09\x09\x09return;\x0a\x09\x09\x09\x09\x09}\x0a\x0a\x09\x09\x09\x09\x09$.ajax(\"/vet\",\x20{\x0a\x09\x09\x09\x09\x09\x09data:\x20{\"body\":\x20body},\x0a\x09\x09\x09\x09\x09\x09type:\x20\"POST\",\x0a\x09\x09\x09\x09\x09\x09dataType:\x20\"json\",\x0a\x09\x09\x09\x09\x09\x09success:\x20function(dataVet)\x20{\x0a\x09\x09\x09\x09\x09\x09\x09if\x20(dataVet.Errors)\x20{\x0a\x09\x09\x09\x09\x09\x09\x09\x09if\x20(!data.Events)\x20{\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09data.Events\x20=\x20[];\x0a\x09\x09\x09\x09\x09\x09\x09\x09}\x0a\x09\x09\x09\x09\x09\x09\x09\x09//\x20inject\x20errors\x20from\x20the\x20vet\x20as\x20the\x20first\x20events\x20in\x20the\x20output\x0a\x09\x09\x09\x09\x09\x09\x09\x09data.Events.unshift({Message:\x20'Go\x20vet\x20exited.\\n\\n',\x20Kind:\x20'system',\x20Delay:\x200});\x0a\x09\x09\x09\x09\x09\x09\x09\x09data.Events.unshift({Message:\x20dataVet.Errors,\x20Kind:\x20'stderr',\x20Delay:\x200});\x0a\x09\x09\x09\x09\x09\x09\x09}\x0a\x09\x09\x09\x09\x09\x09\x09playing\x20=\x20playback(output,\x20data.Events);\x0a\x09\x09\x09\x09\x09\x09},\x0a\x09\x09\x09\x09\x09\x09error:\x20function()\x20{\x0a\x09\x09\x09\x09\x09\x09\x09playing\x20=\x20playback(output,\x20data.Events);\x0a\x09\x09\x09\x09\x09\x09}\x0a\x09\x09\x09\x09\x09});\x0a\x09\x09\x09\x09},\x0a\x09\x09\x09\x09error:\x20function()\x20{\x0a\x09\x09\x09\x09\x09error(output,\x20'Error\x20communicating\x20with\x20remote\x20server.');\x0a\x09\x09\x09\x09}\x0a\x09\x09\x09});\x0a\x09\x09\x09return\x20{\x0a\x09\x09\x09\x09Kill:\x20function()\x20{\x0a\x09\x09\x09\x09\x09if\x20(playing\x20!=\x20null)\x20playing.Stop();\x0a\x09\x09\x09\x09\x09output({Kind:\x20'end',\x20Body:\x20'killed'});\x0a\x09\x09\x09\x09}\x0a\x09\x09\x09};\x0a\x09\x09}\x0a\x09};\x0a}\x0a\x0afunction\x20SocketTransport()\x20{\x0a\x09'use\x20strict';\x0a\x0a\x09var\x20id\x20=\x200;\x0a\x09var\x20outputs\x20=\x20{};\x0a\x09var\x20started\x20=\x20{};\x0a\x09var\x20websocket;\x0a\x09if\x20(window.location.protocol\x20==\x20\"http:\")\x20{\x0a\x09\x09websocket\x20=\x20new\x20WebSocket('ws://'\x20+\x20window.location.host\x20+\x20'/socket');\x0a\x09}\x20else\x20if\x20(window.location.protocol\x20==\x20\"https:\")\x20{\x0a\x09\x09websocket\x20=\x20new\x20WebSocket('wss://'\x20+\x20window.location.host\x20+\x20'/socket');\x0a\x09}\x0a\x0a\x09websocket.onclose\x20=\x20function()\x20{\x0a\x09\x09console.log('websocket\x20connection\x20closed');\x0a\x09};\x0a\x0a\x09websocket.onmessage\x20=\x20function(e)\x20{\x0a\x09\x09var\x20m\x20=\x20JSON.parse(e.data);\x0a\x09\x09var\x20output\x20=\x20outputs[m.Id];\x0a\x09\x09if\x20(output\x20===\x20null)\x0a\x09\x09\x09return;\x0a\x09\x09if\x20(!started[m.Id])\x20{\x0a\x09\x09\x09output({Kind:\x20'start'});\x0a\x09\x09\x09started[m.Id]\x20=\x20true;\x0a\x09\x09}\x0a\x09\x09output({Kind:\x20m.Kind,\x20Body:\x20m.Body});\x0a\x09};\x0a\x0a\x09function\x20send(m)\x20{\x0a\x09\x09websocket.send(JSON.stringify(m));\x0a\x09}\x0a\x0a\x09return\x20{\x0a\x09\x09Run:\x20function(body,\x20output,\x20options)\x20{\x0a\x09\x09\x09var\x20thisID\x20=\x20id+'';\x0a\x09\x09\x09id++;\x0a\x09\x09\x09outputs[thisID]\x20=\x20output;\x0a\x09\x09\x09send({Id:\x20thisID,\x20Kind:\x20'run',\x20Body:\x20body,\x20Options:\x20options});\x0a\x09\x09\x09return\x20{\x0a\x09\x09\x09\x09Kill:\x20function()\x20{\x0a\x09\x09\x09\x09\x09send({Id:\x20thisID,\x20Kind:\x20'kill'});\x0a\x09\x09\x09\x09}\x0a\x09\x09\x09};\x0a\x09\x09}\x0a\x09};\x0a}\x0a\x0afunction\x20PlaygroundOutput(el)\x20{\x0a\x09'use\x20strict';\x0a\x0a\x09return\x20function(write)\x20{\x0a\x09\x09if\x20(write.Kind\x20==\x20'start')\x20{\x0a\x09\x09\x09el.innerHTML\x20=\x20'';\x0a\x09\x09\x09return;\x0a\x09\x09}\x0a\x0a\x09\x09var\x20cl\x20=\x20'system';\x0a\x09\x09if\x20(write.Kind\x20==\x20'stdout'\x20||\x20write.Kind\x20==\x20'stderr')\x0a\x09\x09\x09cl\x20=\x20write.Kind;\x0a\x0a\x09\x09var\x20m\x20=\x20write.Body;\x0a\x09\x09if\x20(write.Kind\x20==\x20'end')\x20{\x0a\x09\x09\x09m\x20=\x20'\\nProgram\x20exited'\x20+\x20(m?(':\x20'+m):'.');\x0a\x09\x09}\x0a\x0a\x09\x09if\x20(m.indexOf('IMAGE:')\x20===\x200)\x20{\x0a\x09\x09\x09//\x20TODO(adg):\x20buffer\x20all\x20writes\x20before\x20creating\x20image\x0a\x09\x09\x09var\x20url\x20=\x20'data:image/png;base64,'\x20+\x20m.substr(6);\x0a\x09\x09\x09var\x20img\x20=\x20document.createElement('img');\x0a\x09\x09\x09img.src\x20=\x20url;\x0a\x09\x09\x09el.appendChild(img);\x0a\x09\x09\x09return;\x0a\x09\x09}\x0a\x0a\x09\x09//\x20^L\x20clears\x20the\x20screen.\x0a\x09\x09var\x20s\x20=\x20m.split('\\x0c');\x0a\x09\x09if\x20(s.length\x20>\x201)\x20{\x0a\x09\x09\x09el.innerHTML\x20=\x20'';\x0a\x09\x09\x09m\x20=\x20s.pop();\x0a\x09\x09}\x0a\x0a\x09\x09m\x20=\x20m.replace(/&/g,\x20'&');\x0a\x09\x09m\x20=\x20m.replace(//g,\x20'>');\x0a\x0a\x09\x09var\x20needScroll\x20=\x20(el.scrollTop\x20+\x20el.offsetHeight)\x20==\x20el.scrollHeight;\x0a\x0a\x09\x09var\x20span\x20=\x20document.createElement('span');\x0a\x09\x09span.className\x20=\x20cl;\x0a\x09\x09span.innerHTML\x20=\x20m;\x0a\x09\x09el.appendChild(span);\x0a\x0a\x09\x09if\x20(needScroll)\x0a\x09\x09\x09el.scrollTop\x20=\x20el.scrollHeight\x20-\x20el.offsetHeight;\x0a\x09};\x0a}\x0a\x0a(function()\x20{\x0a\x20\x20function\x20lineHighlight(error)\x20{\x0a\x20\x20\x20\x20var\x20regex\x20=\x20/prog.go:([0-9]+)/g;\x0a\x20\x20\x20\x20var\x20r\x20=\x20regex.exec(error);\x0a\x20\x20\x20\x20while\x20(r)\x20{\x0a\x20\x20\x20\x20\x20\x20$(\".lines\x20div\").eq(r[1]-1).addClass(\"lineerror\");\x0a\x20\x20\x20\x20\x20\x20r\x20=\x20regex.exec(error);\x0a\x20\x20\x20\x20}\x0a\x20\x20}\x0a\x20\x20function\x20highlightOutput(wrappedOutput)\x20{\x0a\x20\x20\x20\x20return\x20function(write)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(write.Body)\x20lineHighlight(write.Body);\x0a\x20\x20\x20\x20\x20\x20wrappedOutput(write);\x0a\x20\x20\x20\x20};\x0a\x20\x20}\x0a\x20\x20function\x20lineClear()\x20{\x0a\x20\x20\x20\x20$(\".lineerror\").removeClass(\"lineerror\");\x0a\x20\x20}\x0a\x0a\x20\x20//\x20opts\x20is\x20an\x20object\x20with\x20these\x20keys\x0a\x20\x20//\x20\x20codeEl\x20-\x20code\x20editor\x20element\x0a\x20\x20//\x20\x20outputEl\x20-\x20program\x20output\x20element\x0a\x20\x20//\x20\x20runEl\x20-\x20run\x20button\x20element\x0a\x20\x20//\x20\x20fmtEl\x20-\x20fmt\x20button\x20element\x20(optional)\x0a\x20\x20//\x20\x20fmtImportEl\x20-\x20fmt\x20\"imports\"\x20checkbox\x20element\x20(optional)\x0a\x20\x20//\x20\x20shareEl\x20-\x20share\x20button\x20element\x20(optional)\x0a\x20\x20//\x20\x20shareURLEl\x20-\x20share\x20URL\x20text\x20input\x20element\x20(optional)\x0a\x20\x20//\x20\x20shareRedirect\x20-\x20base\x20URL\x20to\x20redirect\x20to\x20on\x20share\x20(optional)\x0a\x20\x20//\x20\x20toysEl\x20-\x20toys\x20select\x20element\x20(optional)\x0a\x20\x20//\x20\x20enableHistory\x20-\x20enable\x20using\x20HTML5\x20history\x20API\x20(optional)\x0a\x20\x20//\x20\x20transport\x20-\x20playground\x20transport\x20to\x20use\x20(default\x20is\x20HTTPTransport)\x0a\x20\x20//\x20\x20enableShortcuts\x20-\x20whether\x20to\x20enable\x20shortcuts\x20(Ctrl+S/Cmd+S\x20to\x20save)\x20(default\x20is\x20false)\x0a\x20\x20//\x20\x20enableVet\x20-\x20enable\x20running\x20vet\x20and\x20displaying\x20its\x20errors\x0a\x20\x20function\x20playground(opts)\x20{\x0a\x20\x20\x20\x20var\x20code\x20=\x20$(opts.codeEl);\x0a\x20\x20\x20\x20var\x20transport\x20=\x20opts['transport']\x20||\x20new\x20HTTPTransport(opts['enableVet']);\x0a\x20\x20\x20\x20var\x20running;\x0a\x0a\x20\x20\x20\x20//\x20autoindent\x20helpers.\x0a\x20\x20\x20\x20function\x20insertTabs(n)\x20{\x0a\x20\x20\x20\x20\x20\x20//\x20find\x20the\x20selection\x20start\x20and\x20end\x0a\x20\x20\x20\x20\x20\x20var\x20start\x20=\x20code[0].selectionStart;\x0a\x20\x20\x20\x20\x20\x20var\x20end\x20\x20\x20=\x20code[0].selectionEnd;\x0a\x20\x20\x20\x20\x20\x20//\x20split\x20the\x20textarea\x20content\x20into\x20two,\x20and\x20insert\x20n\x20tabs\x0a\x20\x20\x20\x20\x20\x20var\x20v\x20=\x20code[0].value;\x0a\x20\x20\x20\x20\x20\x20var\x20u\x20=\x20v.substr(0,\x20start);\x0a\x20\x20\x20\x20\x20\x20for\x20(var\x20i=0;\x20i\x200)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20curpos--;\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(el.value[curpos]\x20==\x20\"\\t\")\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20tabs++;\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x20else\x20if\x20(tabs\x20>\x200\x20||\x20el.value[curpos]\x20==\x20\"\\n\")\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20break;\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20setTimeout(function()\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20insertTabs(tabs);\x0a\x20\x20\x20\x20\x20\x20},\x201);\x0a\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20//\x20NOTE(cbro):\x20e\x20is\x20a\x20jQuery\x20event,\x20not\x20a\x20DOM\x20event.\x0a\x20\x20\x20\x20function\x20handleSaveShortcut(e)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(e.isDefaultPrevented())\x20return\x20false;\x0a\x20\x20\x20\x20\x20\x20if\x20(!e.metaKey\x20&&\x20!e.ctrlKey)\x20return\x20false;\x0a\x20\x20\x20\x20\x20\x20if\x20(e.key\x20!=\x20\"S\"\x20&&\x20e.key\x20!=\x20\"s\")\x20return\x20false;\x0a\x0a\x20\x20\x20\x20\x20\x20e.preventDefault();\x0a\x0a\x20\x20\x20\x20\x20\x20//\x20Share\x20and\x20save\x0a\x20\x20\x20\x20\x20\x20share(function(url)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.location.href\x20=\x20url\x20+\x20\".go?download=true\";\x0a\x20\x20\x20\x20\x20\x20});\x0a\x0a\x20\x20\x20\x20\x20\x20return\x20true;\x0a\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20function\x20keyHandler(e)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(opts.enableShortcuts\x20&&\x20handleSaveShortcut(e))\x20return;\x0a\x0a\x20\x20\x20\x20\x20\x20if\x20(e.keyCode\x20==\x209\x20&&\x20!e.ctrlKey)\x20{\x20//\x20tab\x20(but\x20not\x20ctrl-tab)\x0a\x20\x20\x20\x20\x20\x20\x20\x20insertTabs(1);\x0a\x20\x20\x20\x20\x20\x20\x20\x20e.preventDefault();\x0a\x20\x20\x20\x20\x20\x20\x20\x20return\x20false;\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20if\x20(e.keyCode\x20==\x2013)\x20{\x20//\x20enter\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(e.shiftKey)\x20{\x20//\x20+shift\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20run();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20e.preventDefault();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20false;\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x20if\x20(e.ctrlKey)\x20{\x20//\x20+control\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20fmt();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20e.preventDefault();\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x20else\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20autoindent(e.target);\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20return\x20true;\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20code.unbind('keydown').bind('keydown',\x20keyHandler);\x0a\x20\x20\x20\x20var\x20outdiv\x20=\x20$(opts.outputEl).empty();\x0a\x20\x20\x20\x20var\x20output\x20=\x20$('
').appendTo(outdiv);\x0a\x0a\x20\x20\x20\x20function\x20body()\x20{\x0a\x20\x20\x20\x20\x20\x20return\x20$(opts.codeEl).val();\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20function\x20setBody(text)\x20{\x0a\x20\x20\x20\x20\x20\x20$(opts.codeEl).val(text);\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20function\x20origin(href)\x20{\x0a\x20\x20\x20\x20\x20\x20return\x20(\"\"+href).split(\"/\").slice(0,\x203).join(\"/\");\x0a\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20var\x20pushedEmpty\x20=\x20(window.location.pathname\x20==\x20\"/\");\x0a\x20\x20\x20\x20function\x20inputChanged()\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(pushedEmpty)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20return;\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20pushedEmpty\x20=\x20true;\x0a\x20\x20\x20\x20\x20\x20$(opts.shareURLEl).hide();\x0a\x20\x20\x20\x20\x20\x20window.history.pushState(null,\x20\"\",\x20\"/\");\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20function\x20popState(e)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(e\x20===\x20null)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20return;\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20if\x20(e\x20&&\x20e.state\x20&&\x20e.state.code)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20setBody(e.state.code);\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20var\x20rewriteHistory\x20=\x20false;\x0a\x20\x20\x20\x20if\x20(window.history\x20&&\x20window.history.pushState\x20&&\x20window.addEventListener\x20&&\x20opts.enableHistory)\x20{\x0a\x20\x20\x20\x20\x20\x20rewriteHistory\x20=\x20true;\x0a\x20\x20\x20\x20\x20\x20code[0].addEventListener('input',\x20inputChanged);\x0a\x20\x20\x20\x20\x20\x20window.addEventListener('popstate',\x20popState);\x0a\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20function\x20setError(error)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(running)\x20running.Kill();\x0a\x20\x20\x20\x20\x20\x20lineClear();\x0a\x20\x20\x20\x20\x20\x20lineHighlight(error);\x0a\x20\x20\x20\x20\x20\x20output.empty().addClass(\"error\").text(error);\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20function\x20loading()\x20{\x0a\x20\x20\x20\x20\x20\x20lineClear();\x0a\x20\x20\x20\x20\x20\x20if\x20(running)\x20running.Kill();\x0a\x20\x20\x20\x20\x20\x20output.removeClass(\"error\").text('Waiting\x20for\x20remote\x20server...');\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20function\x20run()\x20{\x0a\x20\x20\x20\x20\x20\x20loading();\x0a\x20\x20\x20\x20\x20\x20running\x20=\x20transport.Run(body(),\x20highlightOutput(PlaygroundOutput(output[0])));\x0a\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20function\x20fmt()\x20{\x0a\x20\x20\x20\x20\x20\x20loading();\x0a\x20\x20\x20\x20\x20\x20var\x20data\x20=\x20{\"body\":\x20body()};\x0a\x20\x20\x20\x20\x20\x20if\x20($(opts.fmtImportEl).is(\":checked\"))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20data[\"imports\"]\x20=\x20\"true\";\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20$.ajax(\"/fmt\",\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20data:\x20data,\x0a\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\"POST\",\x0a\x20\x20\x20\x20\x20\x20\x20\x20dataType:\x20\"json\",\x0a\x20\x20\x20\x20\x20\x20\x20\x20success:\x20function(data)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(data.Error)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20setError(data.Error);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x20else\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20setBody(data.Body);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20setError(\"\");\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20var\x20shareURL;\x20//\x20jQuery\x20element\x20to\x20show\x20the\x20shared\x20URL.\x0a\x20\x20\x20\x20var\x20sharing\x20=\x20false;\x20//\x20true\x20if\x20there\x20is\x20a\x20pending\x20request.\x0a\x20\x20\x20\x20var\x20shareCallbacks\x20=\x20[];\x0a\x20\x20\x20\x20function\x20share(opt_callback)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(opt_callback)\x20shareCallbacks.push(opt_callback);\x0a\x0a\x20\x20\x20\x20\x20\x20if\x20(sharing)\x20return;\x0a\x20\x20\x20\x20\x20\x20sharing\x20=\x20true;\x0a\x0a\x20\x20\x20\x20\x20\x20var\x20sharingData\x20=\x20body();\x0a\x20\x20\x20\x20\x20\x20$.ajax(\"/share\",\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20processData:\x20false,\x0a\x20\x20\x20\x20\x20\x20\x20\x20data:\x20sharingData,\x0a\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\"POST\",\x0a\x20\x20\x20\x20\x20\x20\x20\x20contentType:\x20\"text/plain;\x20charset=utf-8\",\x0a\x20\x20\x20\x20\x20\x20\x20\x20complete:\x20function(xhr)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20sharing\x20=\x20false;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(xhr.status\x20!=\x20200)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20alert(\"Server\x20error;\x20try\x20again.\");\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(opts.shareRedirect)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20window.location\x20=\x20opts.shareRedirect\x20+\x20xhr.responseText;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20var\x20path\x20=\x20\"/p/\"\x20+\x20xhr.responseText;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20var\x20url\x20=\x20origin(window.location)\x20+\x20path;\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20for\x20(var\x20i\x20=\x200;\x20i\x20<\x20shareCallbacks.length;\x20i++)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shareCallbacks[i](url);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shareCallbacks\x20=\x20[];\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(shareURL)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20shareURL.show().val(url).focus().select();\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(rewriteHistory)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20var\x20historyData\x20=\x20{\"code\":\x20sharingData};\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20window.history.pushState(historyData,\x20\"\",\x20path);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20pushedEmpty\x20=\x20false;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20$(opts.runEl).click(run);\x0a\x20\x20\x20\x20$(opts.fmtEl).click(fmt);\x0a\x0a\x20\x20\x20\x20if\x20(opts.shareEl\x20!==\x20null\x20&&\x20(opts.shareURLEl\x20!==\x20null\x20||\x20opts.shareRedirect\x20!==\x20null))\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(opts.shareURLEl)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20shareURL\x20=\x20$(opts.shareURLEl).hide();\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20$(opts.shareEl).click(function()\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20share();\x0a\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20if\x20(opts.toysEl\x20!==\x20null)\x20{\x0a\x20\x20\x20\x20\x20\x20$(opts.toysEl).bind('change',\x20function()\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20var\x20toy\x20=\x20$(this).val();\x0a\x20\x20\x20\x20\x20\x20\x20\x20$.ajax(\"/doc/play/\"+toy,\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20processData:\x20false,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\"GET\",\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20complete:\x20function(xhr)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(xhr.status\x20!=\x20200)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20alert(\"Server\x20error;\x20try\x20again.\");\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20setBody(xhr.responseText);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20}\x0a\x20\x20}\x0a\x0a\x20\x20window.playground\x20=\x20playground;\x0a})();\x0a",
 
 	"search.html": "\x0a{{with\x20.Alert}}\x0a\x09

\x0a\x09{{html\x20.}}\x0a\x09

\x0a{{end}}\x0a{{with\x20.Alt}}\x0a\x09

\x0a\x09Did\x20you\x20mean:\x20\x0a\x09{{range\x20.Alts}}\x0a\x09\x09{{html\x20.}}\x0a\x09{{end}}\x0a\x09

\x0a{{end}}\x0a", - "search.txt": "QUERY\x0a\x09{{.Query}}\x0a\x0a{{with\x20.Alert}}{{.}}\x0a{{end}}{{/*\x20.Alert\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Alt}}DID\x20YOU\x20MEAN\x0a\x0a{{range\x20.Alts}}\x09{{.}}\x0a{{end}}\x0a{{end}}{{/*\x20.Alt\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Pak}}PACKAGE\x20{{$.Query}}\x0a\x0a{{range\x20.}}\x09{{pkgLink\x20.Pak.Path}}\x0a{{end}}\x0a{{end}}{{/*\x20.Pak\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{range\x20$key,\x20$val\x20:=\x20.Idents}}{{if\x20$val}}{{$key.Name}}\x0a{{range\x20$val}}\x20\x20\x20\x20{{.Path}}.{{.Name}}\x0a{{end}}\x0a{{end}}{{end}}{{/*\x20.Idents\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Hit}}{{with\x20.Decls}}PACKAGE-LEVEL\x20DECLARATIONS\x0a\x0a{{range\x20.}}package\x20{{.Pak.Name}}\x0a{{range\x20$file\x20:=\x20.Files}}{{range\x20.Groups}}{{range\x20.}}\x09{{srcLink\x20$file.File.Path}}:{{infoLine\x20.}}{{end}}\x0a{{end}}{{end}}{{/*\x20.Files\x20*/}}\x0a{{end}}{{end}}{{/*\x20.Decls\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Others}}LOCAL\x20DECLARATIONS\x20AND\x20USES\x0a\x0a{{range\x20.}}package\x20{{.Pak.Name}}\x0a{{range\x20$file\x20:=\x20.Files}}{{range\x20.Groups}}{{range\x20.}}\x09{{srcLink\x20$file.File.Path}}:{{infoLine\x20.}}\x0a{{end}}{{end}}{{end}}{{/*\x20.Files\x20*/}}\x0a{{end}}{{end}}{{/*\x20.Others\x20*/}}{{end}}{{/*\x20.Hit\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20.Textual}}{{if\x20.Complete}}{{.Found}}\x20TEXTUAL\x20OCCURRENCES{{else}}MORE\x20THAN\x20{{.Found}}\x20TEXTUAL\x20OCCURRENCES{{end}}\x0a\x0a{{range\x20.Textual}}{{len\x20.Lines}}\x09{{srcLink\x20.Filename}}\x0a{{end}}{{if\x20not\x20.Complete}}...\x09...\x0a{{end}}{{end}}\x0a", - "searchcode.html": "\x0a{{$query_url\x20:=\x20urlquery\x20.Query}}\x0a{{if\x20not\x20.Idents}}\x0a\x09{{with\x20.Pak}}\x0a\x09\x09Package\x20{{html\x20$.Query}}\x0a\x09\x09

\x0a\x09\x09\x0a\x09\x09{{range\x20.}}\x0a\x09\x09\x09{{$pkg_html\x20:=\x20pkgLink\x20.Pak.Path\x20|\x20html}}\x0a\x09\x09\x09{{$pkg_html}}\x0a\x09\x09{{end}}\x0a\x09\x09\x0a\x09\x09

\x0a\x09{{end}}\x0a{{end}}\x0a{{with\x20.Hit}}\x0a\x09{{with\x20.Decls}}\x0a\x09\x09Package-level\x20declarations\x0a\x09\x09{{range\x20.}}\x0a\x09\x09\x09{{$pkg_html\x20:=\x20pkgLink\x20.Pak.Path\x20|\x20html}}\x0a\x09\x09\x09package\x20{{html\x20.Pak.Name}}\x0a\x09\x09\x09{{range\x20.Files}}\x0a\x09\x09\x09\x09{{$file\x20:=\x20.File.Path}}\x0a\x09\x09\x09\x09{{range\x20.Groups}}\x0a\x09\x09\x09\x09\x09{{range\x20.}}\x0a\x09\x09\x09\x09\x09\x09{{$line\x20:=\x20infoLine\x20.}}\x0a\x09\x09\x09\x09\x09\x09{{$file}}:{{$line}}\x0a\x09\x09\x09\x09\x09\x09{{infoSnippet_html\x20.}}\x0a\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09{{end}}\x0a\x09\x09{{end}}\x0a\x09{{end}}\x0a\x09{{with\x20.Others}}\x0a\x09\x09Local\x20declarations\x20and\x20uses\x0a\x09\x09{{range\x20.}}\x0a\x09\x09\x09{{$pkg_html\x20:=\x20pkgLink\x20.Pak.Path\x20|\x20html}}\x0a\x09\x09\x09package\x20{{html\x20.Pak.Name}}\x0a\x09\x09\x09{{range\x20.Files}}\x0a\x09\x09\x09\x09{{$file\x20:=\x20.File.Path}}\x0a\x09\x09\x09\x09{{$file}}\x0a\x09\x09\x09\x09\x0a\x09\x09\x09\x09{{range\x20.Groups}}\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09{{index\x20.\x200\x20|\x20infoKind_html}}\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09{{range\x20.}}\x0a\x09\x09\x09\x09\x09\x09{{$line\x20:=\x20infoLine\x20.}}\x0a\x09\x09\x09\x09\x09\x09{{$line}}\x0a\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x0a\x09\x09\x09{{end}}\x0a\x09\x09{{end}}\x0a\x09{{end}}\x0a{{end}}\x0a", "searchdoc.html": "\x0a{{range\x20$key,\x20$val\x20:=\x20.Idents}}\x0a\x09{{if\x20$val}}\x0a\x09\x09{{$key.Name}}\x0a\x09\x09{{range\x20$val}}\x0a\x09\x09\x09{{$pkg_html\x20:=\x20pkgLink\x20.Path\x20|\x20html}}\x0a\x09\x09\x09{{if\x20eq\x20\"Packages\"\x20$key.Name}}\x0a\x09\x09\x09\x09{{html\x20.Path}}\x0a\x09\x09\x09{{else}}\x0a\x09\x09\x09\x09{{$doc_html\x20:=\x20docLink\x20.Path\x20.Name|\x20html}}\x0a\x09\x09\x09\x09{{html\x20.Package}}.{{.Name}}\x0a\x09\x09\x09{{end}}\x0a\x09\x09\x09{{if\x20.Doc}}\x0a\x09\x09\x09\x09

{{comment_html\x20.Doc}}

\x0a\x09\x09\x09{{else}}\x0a\x09\x09\x09\x09

No\x20documentation\x20available

\x0a\x09\x09\x09{{end}}\x0a\x09\x09{{end}}\x0a\x09{{end}}\x0a{{end}}\x0a",