func pageView(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") id := strings.TrimSpace(r.FormValue("id")) if id != "" { db := getDatabase() d, found := db.FindFullPackage(id) if !found { pageNotFound(w, r) return } if d.StarCount < 0 { d.StarCount = 0 } var descHTML bytesp.Slice doc.ToHTML(&descHTML, d.Description, nil) if err := templates.ExecuteTemplate(w, "view.html", struct { UIUtils gcse.HitInfo DescHTML template.HTML TotalDocCount int StaticRank int ShowReadme bool }{ HitInfo: d, DescHTML: template.HTML(descHTML), TotalDocCount: db.PackageCount(), StaticRank: d.StaticRank + 1, ShowReadme: len(d.Description) < 10 && len(d.ReadmeData) > 0, }); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } }
func main() { pkg, err := build.Import("robpike.io/ivy", "", build.ImportComment) if err != nil { log.Fatal(err) } fs := token.NewFileSet() pkgs, err := parser.ParseDir(fs, pkg.Dir, nil, parser.ParseComments) if err != nil { log.Fatal(err) } astPkg := pkgs[pkg.Name] if astPkg == nil { log.Fatalf("failed to locate %s package", pkg.Name) } docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls) htmlBuf := new(bytes.Buffer) fmt.Fprintln(htmlBuf, `<!-- auto-generated from robpike.io/ivy package doc -->`) fmt.Fprintln(htmlBuf, head) fmt.Fprintln(htmlBuf, `<body>`) doc.ToHTML(htmlBuf, docPkg.Doc, nil) fmt.Fprintln(htmlBuf, `</body></html>`) goBuf := new(bytes.Buffer) fmt.Fprintf(goBuf, "package mobile\n\n") fmt.Fprintf(goBuf, "// GENERATED; DO NOT EDIT\n") fmt.Fprintf(goBuf, "const help = `%s`\n", sanitize(htmlBuf.Bytes())) buf, err := format.Source(goBuf.Bytes()) if err != nil { log.Fatalf("failed to gofmt: %v", err) } os.Stdout.Write(buf) }
// Template formatter for "html-comment" format. func htmlCommentFmt(w io.Writer, format string, x ...interface{}) { var buf bytes.Buffer writeAny(&buf, fileset(x), x[0]) // TODO(gri) Provide list of words (e.g. function parameters) // to be emphasized by ToHTML. doc.ToHTML(w, buf.Bytes(), nil) // does html-escaping }
// commentFn formats a source code comment as HTML. func commentFn(v string) htemp.HTML { var buf bytes.Buffer godoc.ToHTML(&buf, v, nil) p := buf.Bytes() p = replaceAll(p, h3Pat, func(out, src []byte, m []int) []byte { out = append(out, src[m[0]:m[1]-1]...) out = append(out, '4') return out }) p = replaceAll(p, rfcPat, func(out, src []byte, m []int) []byte { out = append(out, `<a href="http://tools.ietf.org/html/rfc`...) out = append(out, src[m[2]:m[3]]...) out = append(out, `">`...) out = append(out, src[m[0]:m[1]]...) out = append(out, `</a>`...) return out }) p = replaceAll(p, packagePat, func(out, src []byte, m []int) []byte { path := bytes.TrimRight(src[m[2]:m[3]], ".!?:") if !doc.IsValidPath(string(path)) { return append(out, src[m[0]:m[1]]...) } out = append(out, src[m[0]:m[2]]...) out = append(out, `<a href="/`...) out = append(out, path...) out = append(out, `">`...) out = append(out, path...) out = append(out, `</a>`...) out = append(out, src[m[2]+len(path):m[1]]...) return out }) return htemp.HTML(p) }
func (p *Package) html(text string, scope string, ignored map[string]struct{}) template.HTML { var buf bytes.Buffer doc.ToHTML(&buf, text, nil) var out bytes.Buffer p.linkify(&out, buf.String(), scope, ignored) return template.HTML(out.String()) }
func comment_htmlFunc(comment string) string { var buf bytes.Buffer // TODO(gri) Provide list of words (e.g. function parameters) // to be emphasized by ToHTML. doc.ToHTML(&buf, comment, nil) // does html-escaping return buf.String() }
// commentFn formats a source code comment as HTML. func commentFn(v string) string { var buf bytes.Buffer godoc.ToHTML(&buf, v, nil) p := buf.Bytes() p = bytes.Replace(p, h3Open, h4Open, -1) p = bytes.Replace(p, h3Close, h4Close, -1) p = rfcRE.ReplaceAll(p, rfcReplace) return string(p) }
func pageView(w http.ResponseWriter, r *http.Request) { id := strings.TrimSpace(r.FormValue("id")) if id != "" { c := appengine.NewContext(r) ddb := NewCachedDocDB(c, "doc") var doc DocInfo err, exists := ddb.Get(id, &doc) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if !exists { fmt.Fprintf(w, `<html><body>No such entry!`) ent, _ := findCrawlingEntry(c, kindCrawlerPackage, id) if ent != nil { fmt.Fprintf(w, ` Scheduled to be crawled at %s`, ent.ScheduleTime.Format("2006-01-02 15:04:05")) } else { fmt.Fprintf(w, ` Not found yet!`) } fmt.Fprintf(w, ` Click to <a href="crawl?id=%s">crawl</a>.</body></html>`, template.URLQueryEscaper(id)) return } if doc.StarCount < 0 { doc.StarCount = 0 } var descHTML villa.ByteSlice godoc.ToHTML(&descHTML, doc.Description, nil) showReadme := len(doc.Description) < 10 && len(doc.ReadmeData) > 0 err = templates.ExecuteTemplate(w, "view.html", struct { DocInfo DescHTML template.HTML ShowReadme bool }{ DocInfo: doc, DescHTML: template.HTML(descHTML), ShowReadme: showReadme, }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } }
// commentFn formats a source code comment as HTML. func commentFn(v string) htemp.HTML { var buf bytes.Buffer godoc.ToHTML(&buf, v, nil) p := buf.Bytes() p = replaceAll(p, h3Pat, func(out, src []byte, m []int) []byte { out = append(out, `<h4 id="`...) out = append(out, src[m[2]:m[3]]...) out = append(out, `">`...) out = append(out, src[m[4]:m[5]]...) out = append(out, ` <a class="permalink" href="#`...) out = append(out, src[m[2]:m[3]]...) out = append(out, `">¶</a></h4>`...) return out }) p = replaceAll(p, rfcPat, func(out, src []byte, m []int) []byte { out = append(out, `<a href="http://tools.ietf.org/html/rfc`...) out = append(out, src[m[2]:m[3]]...) // If available, add major section fragment if m[6] != -1 { out = append(out, `#section-`...) out = append(out, src[m[8]:m[9]]...) // If available, add minor section fragment if m[13] != -1 { out = append(out, src[m[12]:m[13]]...) } } out = append(out, `">`...) out = append(out, src[m[0]:m[1]]...) out = append(out, `</a>`...) return out }) p = replaceAll(p, packagePat, func(out, src []byte, m []int) []byte { path := bytes.TrimRight(src[m[2]:m[3]], ".!?:") if !gosrc.IsValidPath(string(path)) { return append(out, src[m[0]:m[1]]...) } out = append(out, src[m[0]:m[2]]...) out = append(out, `<a href="/`...) out = append(out, path...) out = append(out, `">`...) out = append(out, path...) out = append(out, `</a>`...) out = append(out, src[m[2]+len(path):m[1]]...) return out }) return htemp.HTML(p) }
// toHTML returns Go documention in HTML format for the main package // in the current directory. It returns an error if it finds multiple // packages or a non-main package. func toHTML() ([]byte, error) { dir := "." // create a build.Package bpkg, err := build.ImportDir(dir, build.ImportComment) if err != nil { return nil, err } // create an ast.Package fset := token.NewFileSet() goFiles := map[string]struct{}{} for _, f := range bpkg.GoFiles { goFiles[f] = struct{}{} } for _, f := range bpkg.CgoFiles { goFiles[f] = struct{}{} } filter := func(fi os.FileInfo) bool { _, ok := goFiles[fi.Name()] return ok } apkgs, err := parser.ParseDir(fset, dir, filter, parser.ParseComments) if err != nil { return nil, err } if len(apkgs) > 1 { return nil, errors.New("multiple packages in directory") } var apkg *ast.Package var ok bool if apkg, ok = apkgs["main"]; !ok { return nil, errors.New("package is a non-main package") } // create a doc.Package dpkg := doc.New(apkg, bpkg.ImportPath, 0) // return html b := new(bytes.Buffer) doc.ToHTML(b, dpkg.Doc, nil) return b.Bytes(), nil }
func appendHeadings(list []string, comment string) []string { var buf bytes.Buffer doc.ToHTML(&buf, comment, nil) for s := buf.String(); ; { i := strings.Index(s, html_h) if i < 0 { break } i += len(html_h) j := strings.Index(s, html_endh) if j < 0 { list = append(list, s[i:]) // incorrect HTML break } list = append(list, s[i:j]) s = s[j+len(html_endh):] } return list }
func pageView(w http.ResponseWriter, r *http.Request) { id := strings.TrimSpace(r.FormValue("id")) if id != "" { var doc gcse.HitInfo if !findPackage(id, &doc) { http.Error(w, fmt.Sprintf("Package %s not found!", id), http.StatusNotFound) return } indexDB, _ := indexDBBox.Get().(*index.TokenSetSearcher) if doc.StarCount < 0 { doc.StarCount = 0 } var descHTML bytesp.Slice godoc.ToHTML(&descHTML, doc.Description, nil) showReadme := len(doc.Description) < 10 && len(doc.ReadmeData) > 0 docCount := 0 if indexDB != nil { docCount = indexDB.DocCount() } if err := templates.ExecuteTemplate(w, "view.html", struct { UIUtils gcse.HitInfo DescHTML template.HTML TotalDocCount int StaticRank int ShowReadme bool }{ HitInfo: doc, DescHTML: template.HTML(descHTML), TotalDocCount: docCount, StaticRank: doc.StaticRank + 1, ShowReadme: showReadme, }); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } }
func commentToHTML(comment string) string { b := bytes.NewBuffer(make([]byte, 0, 128)) doc.ToHTML(b, []byte(comment), nil) return b.String() }
func renderDoc(render macaron.Render, pdoc *Package, docPath string) error { data := make(map[string]interface{}) data["PkgFullIntro"] = pdoc.Doc exports := make([]exportSearchObject, 0, 10) var buf bytes.Buffer links := make([]*Link, 0, len(pdoc.Types)+len(pdoc.Imports)+len(pdoc.TestImports)+ len(pdoc.Funcs)+10) // Get all types, functions and import packages for _, t := range pdoc.Types { links = append(links, &Link{ Name: t.Name, Comment: template.HTMLEscapeString(t.Doc), }) exports = append(exports, exportSearchObject{t.Name}) // buf.WriteString("'" + t.Name + "',") } for _, f := range pdoc.Funcs { f.Code = template.HTMLEscapeString(f.Code) links = append(links, &Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) exports = append(exports, exportSearchObject{f.Name}) // buf.WriteString("'" + f.Name + "',") } for _, t := range pdoc.Types { for _, f := range t.Funcs { links = append(links, &Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) exports = append(exports, exportSearchObject{f.Name}) // buf.WriteString("'" + f.Name + "',") } for _, m := range t.Methods { exports = append(exports, exportSearchObject{t.Name + "." + m.Name}) // buf.WriteString("'" + t.Name + "_" + m.Name + "',") } } // Ignore C. for _, v := range append(pdoc.Imports, pdoc.TestImports...) { if v != "C" { links = append(links, &Link{ Name: path.Base(v) + ".", Path: v, }) } } // Set exported objects type-ahead. // exportDataSrc := buf.String() if len(exports) > 0 { pdoc.IsHasExport = true data["IsHasExports"] = true exportDataSrc, _ := json.Marshal(exports) data["ExportDataSrc"] = "<script>var exportDataSrc = " + string(exportDataSrc) + ";</script>" } pdoc.IsHasConst = len(pdoc.Consts) > 0 pdoc.IsHasVar = len(pdoc.Vars) > 0 if len(pdoc.Examples) > 0 { pdoc.IsHasExample = true data["IsHasExample"] = pdoc.IsHasExample data["Examples"] = pdoc.Examples } // Constants. data["IsHasConst"] = pdoc.IsHasConst data["Consts"] = pdoc.Consts for i, v := range pdoc.Consts { if len(v.Doc) > 0 { buf.Reset() doc.ToHTML(&buf, v.Doc, nil) v.Doc = buf.String() } buf.Reset() v.Decl = template.HTMLEscapeString(v.Decl) v.Decl = strings.Replace(v.Decl, """, "\"", -1) FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Consts[i] = v } // Variables. data["IsHasVar"] = pdoc.IsHasVar data["Vars"] = pdoc.Vars for i, v := range pdoc.Vars { if len(v.Doc) > 0 { buf.Reset() doc.ToHTML(&buf, v.Doc, nil) v.Doc = buf.String() } buf.Reset() FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Vars[i] = v } // Files. if len(pdoc.Files) > 0 { pdoc.IsHasFile = true data["IsHasFiles"] = pdoc.IsHasFile data["Files"] = pdoc.Files var query string if i := strings.Index(pdoc.Files[0].BrowseUrl, "?"); i > -1 { query = pdoc.Files[0].BrowseUrl[i:] } viewFilePath := path.Dir(pdoc.Files[0].BrowseUrl) + "/" + query // GitHub URL change. if strings.HasPrefix(viewFilePath, "github.com") { viewFilePath = strings.Replace(viewFilePath, "blob/", "tree/", 1) } data["ViewFilePath"] = viewFilePath } var err error renderFuncs(pdoc) data["Funcs"] = pdoc.Funcs for i, f := range pdoc.Funcs { if len(f.Doc) > 0 { buf.Reset() doc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() } buf.Reset() FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() + " {" if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 { f.Examples = exs } pdoc.Funcs[i] = f } data["Types"] = pdoc.Types for i, t := range pdoc.Types { for j, v := range t.Consts { if len(v.Doc) > 0 { buf.Reset() doc.ToHTML(&buf, v.Doc, nil) v.Doc = buf.String() } buf.Reset() v.Decl = template.HTMLEscapeString(v.Decl) v.Decl = strings.Replace(v.Decl, """, "\"", -1) FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() t.Consts[j] = v } for j, v := range t.Vars { if len(v.Doc) > 0 { buf.Reset() doc.ToHTML(&buf, v.Doc, nil) v.Doc = buf.String() } buf.Reset() FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() t.Vars[j] = v } for j, f := range t.Funcs { if len(f.Doc) > 0 { buf.Reset() doc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() } buf.Reset() FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() + " {" if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 { f.Examples = exs } t.Funcs[j] = f } for j, m := range t.Methods { if len(m.Doc) > 0 { buf.Reset() doc.ToHTML(&buf, m.Doc, nil) m.Doc = buf.String() } buf.Reset() FormatCode(&buf, &m.Decl, links) m.FmtDecl = buf.String() + " {" if exs := getExamples(pdoc, t.Name, m.Name); len(exs) > 0 { m.Examples = exs } t.Methods[j] = m } if len(t.Doc) > 0 { buf.Reset() doc.ToHTML(&buf, t.Doc, nil) t.Doc = buf.String() } buf.Reset() FormatCode(&buf, &t.Decl, links) t.FmtDecl = buf.String() if exs := getExamples(pdoc, "", t.Name); len(exs) > 0 { t.Examples = exs } pdoc.Types[i] = t } // Examples. links = append(links, &Link{ Name: path.Base(pdoc.ImportPath) + ".", }) for _, e := range pdoc.Examples { buf.Reset() FormatCode(&buf, &e.Code, links) e.Code = buf.String() } data["ProjectPath"] = pdoc.ProjectPath data["ImportPath"] = pdoc.ImportPath // GitHub redirects non-HTTPS link and Safari loses "#XXX". if strings.HasPrefix(pdoc.ProjectPath, "github") { data["Secure"] = "s" } result, err := render.HTMLBytes("docs/tpl", data) if err != nil { return fmt.Errorf("error rendering HTML: %v", err) } pdoc.JsNum = SaveDocPage(docPath, result) if pdoc.JsNum == -1 { return errors.New("Save JS file wasn't successful") } SavePkgDoc(pdoc.ImportPath, pdoc.Readme) data["UtcTime"] = time.Unix(pdoc.Created, 0).UTC() // data["TimeSince"] = calTimeSince(time.Unix(pdoc.Created, 0)) return nil }
// Template formatter for "html-comment" format. func htmlCommentFmt(w io.Writer, x interface{}, format string) { var buf bytes.Buffer writeAny(&buf, x, false) doc.ToHTML(w, buf.Bytes()) // does html-escaping }
// generatePage genarates documentation page for project. // it returns false when its a invaild(empty) project. func generatePage(this *HomeController, pdoc *doc.Package, q string, lang string) bool { // Set properties. this.TplNames = "docs_" + lang + ".html" // Refresh (within 10 seconds). this.Data["IsRefresh"] = pdoc.Created.Add(10 * time.Second).UTC().After(time.Now().UTC()) // Get project name. lastIndex := strings.LastIndex(q, "/") proName := q[lastIndex+1:] if i := strings.Index(proName, "?"); i > -1 { proName = proName[:i] } this.Data["ProName"] = proName // Project VCS home page. switch { case q[:4] == "code": // code.google.com if strings.Index(q, "source/") == -1 { this.Data["ProPath"] = strings.Replace(q, pdoc.ProjectName, pdoc.ProjectName+"/source/browse", 1) } else { this.Data["ProPath"] = q } case q[:3] == "git": // github.com if proName != pdoc.ProjectName { // Not root. this.Data["ProPath"] = strings.Replace(q, proName, "tree/master/"+proName, 1) } else { this.Data["ProPath"] = q + "/tree/master" } } this.Data["Views"] = pdoc.Views + 1 // Remove last "/". if urlLen := len(q); q[urlLen-1] == '/' { q = q[:urlLen-1] } if utils.IsGoRepoPath(pdoc.ImportPath) { this.Data["IsGoRepo"] = true } pkgDocPath := q[:lastIndex] this.Data["ProDocPath"] = pkgDocPath // Upper level project URL. // Introduction. this.Data["ImportPath"] = pdoc.ImportPath // Load project data from database. pdecl, err := models.LoadProject(pdoc.ImportPath) if err != nil { beego.Error("SearchController.generatePage(): models.LoadProject()", err) return false } var buf bytes.Buffer godoc.ToHTML(&buf, pdecl.Doc, nil) pkgInfo := buf.String() pkgInfo = strings.Replace(pkgInfo, "<p>", "<p><b>", 1) pkgInfo = strings.Replace(pkgInfo, "</p>", "</b></p>", 1) this.Data["PkgFullIntro"] = pkgInfo // Convert data format. err = ConvertDataFormat(pdoc, pdecl) if err != nil { beego.Error("SearchController.generatePage(): ConvertDataFormat", err) return false } links := make([]*utils.Link, 0, len(pdoc.Types)+len(pdoc.Imports)) // Get all types and import packages for _, t := range pdoc.Types { links = append(links, &utils.Link{ Name: t.Name, Comment: t.Doc, }) } for _, v := range pdoc.Imports { links = append(links, &utils.Link{ Name: path.Base(v) + ".", Path: v, }) } // Index. this.Data["IsHasConst"] = len(pdoc.Consts) > 0 this.Data["IsHasVar"] = len(pdoc.Vars) > 0 this.Data["Funcs"] = pdoc.Funcs for i, f := range pdoc.Funcs { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, f.Code, links) f.Code = buf.String() pdoc.Funcs[i] = f } this.Data["Types"] = pdoc.Types for i, t := range pdoc.Types { for j, f := range t.Funcs { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, f.Code, links) f.Code = buf.String() t.Funcs[j] = f } for j, m := range t.Methods { buf.Reset() godoc.ToHTML(&buf, m.Doc, nil) m.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, m.Decl, links) m.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, m.Code, links) m.Code = buf.String() t.Methods[j] = m } buf.Reset() godoc.ToHTML(&buf, t.Doc, nil) t.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, t.Decl, links) t.FmtDecl = buf.String() pdoc.Types[i] = t } // Constants. this.Data["Consts"] = pdoc.Consts for i, v := range pdoc.Consts { buf.Reset() utils.FormatCode(&buf, v.Decl, links) v.FmtDecl = buf.String() pdoc.Consts[i] = v } // Variables. this.Data["Vars"] = pdoc.Vars for i, v := range pdoc.Vars { buf.Reset() utils.FormatCode(&buf, v.Decl, links) v.FmtDecl = buf.String() pdoc.Vars[i] = v } // Dirs. this.Data["IsHasSubdirs"] = len(pdoc.Dirs) > 0 pinfos := make([]*models.PkgInfo, 0, len(pdoc.Dirs)) for _, v := range pdoc.Dirs { v = pdoc.ImportPath + "/" + v if pinfo, err := models.GetPkgInfo(v); err == nil { pinfos = append(pinfos, pinfo) } else { pinfos = append(pinfos, &models.PkgInfo{Path: v}) } } this.Data["Subdirs"] = pinfos this.Data["Files"] = pdoc.Files this.Data["ImportPkgs"] = pdecl.Imports this.Data["ImportPkgNum"] = len(pdoc.Imports) - 1 this.Data["UtcTime"] = pdoc.Created this.Data["GOOS"] = pdecl.Goos this.Data["GOARCH"] = pdecl.Goarch return true }
// commentFmt formats a source code control comment as HTML. func commentFmt(v string) template.HTML { var buf bytes.Buffer godoc.ToHTML(&buf, v, nil) return template.HTML(buf.String()) }
// build generates data from source files. func (w *walker) build(srcs []*source) (*Package, error) { // Set created time. w.pdoc.Created = time.Now().UTC() // Add source files to walker, I skipped references here. w.srcs = make(map[string]*source) for _, src := range srcs { srcName := strings.ToLower(src.name) // For readme comparation. switch { case strings.HasSuffix(src.name, ".go"): w.srcs[src.name] = src case len(w.pdoc.Tag) > 0: continue // Only save latest readme. case strings.HasPrefix(srcName, "readme_zh") || strings.HasPrefix(srcName, "readme_cn"): models.SavePkgDoc(w.pdoc.ImportPath, "zh", src.data) case strings.HasPrefix(srcName, "readme"): models.SavePkgDoc(w.pdoc.ImportPath, "en", src.data) } } w.fset = token.NewFileSet() // Find the package and associated files. ctxt := build.Context{ GOOS: runtime.GOOS, GOARCH: runtime.GOARCH, CgoEnabled: true, JoinPath: path.Join, IsAbsPath: path.IsAbs, SplitPathList: func(list string) []string { return strings.Split(list, ":") }, IsDir: func(path string) bool { panic("unexpected") }, HasSubdir: func(root, dir string) (rel string, ok bool) { panic("unexpected") }, ReadDir: func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) }, OpenFile: func(path string) (r io.ReadCloser, err error) { return w.openFile(path) }, Compiler: "gc", } bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0) // Continue if there are no Go source files; we still want the directory info. _, nogo := err.(*build.NoGoError) if err != nil { if nogo { err = nil beego.Info("doc.walker.build -> No Go Source file") } else { return w.pdoc, errors.New("doc.walker.build -> " + err.Error()) } } // Parse the Go files files := make(map[string]*ast.File) for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) { file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments) if err != nil { beego.Error("doc.walker.build -> parse go files:", err) continue } w.pdoc.Files = append(w.pdoc.Files, name) //w.pdoc.SourceSize += len(w.srcs[name].data) files[name] = file } apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil) // Find examples in the test files. for _, name := range append(bpkg.TestGoFiles, bpkg.XTestGoFiles...) { file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments) if err != nil { beego.Error("doc.walker.build -> find examples:", err) continue } //w.pdoc.TestFiles = append(w.pdoc.TestFiles, &File{Name: name, URL: w.srcs[name].browseURL}) //w.pdoc.TestSourceSize += len(w.srcs[name].data) w.examples = append(w.examples, doc.Examples(file)...) } //w.vetPackage(apkg) mode := doc.Mode(0) if w.pdoc.ImportPath == "builtin" { mode |= doc.AllDecls } pdoc := doc.New(apkg, w.pdoc.ImportPath, mode) w.pdoc.Synopsis = utils.Synopsis(pdoc.Doc) pdoc.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r") var buf bytes.Buffer doc.ToHTML(&buf, pdoc.Doc, nil) w.pdoc.Doc = w.pdoc.Doc + "<br />" + buf.String() w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "<p>", "<p><b>", 1) w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "</p>", "</b></p>", 1) w.pdoc.Doc = base32.StdEncoding.EncodeToString([]byte(w.pdoc.Doc)) w.pdoc.Examples = w.getExamples("") w.pdoc.IsCmd = bpkg.IsCommand() w.srcLines = make(map[string][]string) w.pdoc.Consts = w.values(pdoc.Consts) w.pdoc.Funcs = w.funcs(pdoc.Funcs) w.pdoc.Types = w.types(pdoc.Types) w.pdoc.Vars = w.values(pdoc.Vars) //w.pdoc.Notes = w.notes(pdoc.Notes) w.pdoc.Imports = bpkg.Imports w.pdoc.TestImports = bpkg.TestImports //w.pdoc.XTestImports = bpkg.XTestImports beego.Info("doc.walker.build(", pdoc.ImportPath, "), Goroutine #", runtime.NumGoroutine()) return w.pdoc, err }
// generatePage genarates documentation page for project. // it returns false when its a invaild(empty) project. func generatePage(this *HomeController, pdoc *doc.Package, q string, lang string) bool { // Load project data from database. pdecl, err := models.LoadProject(pdoc.ImportPath) if err != nil { beego.Error("HomeController.generatePage():", err) return false } // Set properties. this.TplNames = "docs_" + lang + ".html" // Refresh (within 10 seconds). this.Data["IsRefresh"] = pdoc.Created.Add(10 * time.Second).UTC().After(time.Now().UTC()) // Get VCS name, project name, project home page, and Upper level project URL. this.Data["VCS"], this.Data["ProName"], this.Data["ProPath"], this.Data["ProDocPath"] = getVCSInfo(q, pdoc) if utils.IsGoRepoPath(pdoc.ImportPath) && strings.Index(pdoc.ImportPath, ".") == -1 { this.Data["IsGoRepo"] = true } this.Data["Views"] = pdoc.Views + 1 // Tags. this.Data["Tags"] = getTags(pdoc.Tags, lang) // Introduction. this.Data["ImportPath"] = pdoc.ImportPath byts, _ := base32.StdEncoding.DecodeString(pdecl.Doc) this.Data["PkgFullIntro"] = string(byts) var buf bytes.Buffer // Convert data format. err = ConvertDataFormat(pdoc, pdecl) if err != nil { beego.Error("HomeController.generatePage(): ConvertDataFormat", err) return false } links := make([]*utils.Link, 0, len(pdoc.Types)+len(pdoc.Imports)+len(pdoc.Funcs)+10) // Get all types, functions and import packages for _, t := range pdoc.Types { links = append(links, &utils.Link{ Name: t.Name, Comment: template.HTMLEscapeString(t.Doc), }) buf.WriteString(""" + t.Name + "",") } for _, f := range pdoc.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString(""" + f.Name + "",") } for _, t := range pdoc.Types { for _, f := range t.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString(""" + f.Name + "",") } for _, m := range t.Methods { buf.WriteString(""" + t.Name + "." + m.Name + "",") } } for _, v := range pdoc.Imports { links = append(links, &utils.Link{ Name: path.Base(v) + ".", Path: v, }) } exportDataSrc := buf.String() if len(exportDataSrc) > 0 { this.Data["HasExports"] = true exportDataSrc = exportDataSrc[:len(exportDataSrc)-1] // Set export keyword type-ahead. this.Data["ExportDataSrc"] = exportDataSrc } // Index. this.Data["IsHasConst"] = len(pdoc.Consts) > 0 this.Data["IsHasVar"] = len(pdoc.Vars) > 0 this.Data["Funcs"] = pdoc.Funcs for i, f := range pdoc.Funcs { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Code, links) f.Code = buf.String() pdoc.Funcs[i] = f } this.Data["Types"] = pdoc.Types for i, t := range pdoc.Types { for j, f := range t.Funcs { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Code, links) f.Code = buf.String() t.Funcs[j] = f } for j, m := range t.Methods { buf.Reset() godoc.ToHTML(&buf, m.Doc, nil) m.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, &m.Decl, links) m.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &m.Code, links) m.Code = buf.String() t.Methods[j] = m } buf.Reset() godoc.ToHTML(&buf, t.Doc, nil) t.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, &t.Decl, links) t.FmtDecl = buf.String() pdoc.Types[i] = t } // Constants. this.Data["Consts"] = pdoc.Consts for i, v := range pdoc.Consts { buf.Reset() v.Decl = template.HTMLEscapeString(v.Decl) v.Decl = strings.Replace(v.Decl, """, "\"", -1) utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Consts[i] = v } // Variables. this.Data["Vars"] = pdoc.Vars for i, v := range pdoc.Vars { buf.Reset() utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Vars[i] = v } // Dirs. this.Data["IsHasSubdirs"] = len(pdoc.Dirs) > 0 pinfos := make([]*models.PkgInfo, 0, len(pdoc.Dirs)) for _, v := range pdoc.Dirs { v = pdoc.ImportPath + "/" + v if pinfo, err := models.GetPkgInfo(v); err == nil { pinfos = append(pinfos, pinfo) } else { pinfos = append(pinfos, &models.PkgInfo{Path: v}) } } this.Data["Subdirs"] = pinfos // Tags. this.Data["TagsDataSrc"] = tagSet this.Data["Files"] = pdoc.Files this.Data["ImportPkgs"] = pdecl.Imports this.Data["ImportPkgNum"] = len(pdoc.Imports) - 1 this.Data["IsImported"] = pdoc.ImportedNum > 0 this.Data["ImportPid"] = pdoc.ImportPid this.Data["ImportedNum"] = pdoc.ImportedNum this.Data["UtcTime"] = pdoc.Created this.Data["GOOS"] = pdecl.Goos this.Data["GOARCH"] = pdecl.Goarch return true }
func renderDoc(this *HomeRouter, pdoc *hv.Package, q, tag, docPath string) bool { this.Data["PkgFullIntro"] = pdoc.Doc var buf bytes.Buffer links := make([]*utils.Link, 0, len(pdoc.Types)+len(pdoc.Imports)+len(pdoc.TestImports)+ len(pdoc.Funcs)+10) // Get all types, functions and import packages for _, t := range pdoc.Types { links = append(links, &utils.Link{ Name: t.Name, Comment: template.HTMLEscapeString(t.Doc), }) buf.WriteString("'" + t.Name + "',") } for _, f := range pdoc.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString("'" + f.Name + "',") } for _, t := range pdoc.Types { for _, f := range t.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString("'" + f.Name + "',") } for _, m := range t.Methods { buf.WriteString("'" + t.Name + "." + m.Name + "',") } } // Ignore C. for _, v := range append(pdoc.Imports, pdoc.TestImports...) { if v != "C" { links = append(links, &utils.Link{ Name: path.Base(v) + ".", Path: v, }) } } // Set exported objects type-ahead. exportDataSrc := buf.String() if len(exportDataSrc) > 0 { pdoc.IsHasExport = true this.Data["IsHasExports"] = true exportDataSrc = exportDataSrc[:len(exportDataSrc)-1] this.Data["ExportDataSrc"] = "<script>$('.search-export').typeahead({local: [" + exportDataSrc + "],limit: 10});</script>" } pdoc.UserExamples = getUserExamples(pdoc.ImportPath) pdoc.IsHasConst = len(pdoc.Consts) > 0 pdoc.IsHasVar = len(pdoc.Vars) > 0 if len(pdoc.Examples)+len(pdoc.UserExamples) > 0 { pdoc.IsHasExample = true this.Data["IsHasExample"] = pdoc.IsHasExample this.Data["Examples"] = append(pdoc.Examples, pdoc.UserExamples...) } // Commented and total objects number. var comNum, totalNum int // Constants. this.Data["IsHasConst"] = pdoc.IsHasConst this.Data["Consts"] = pdoc.Consts for i, v := range pdoc.Consts { if len(v.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, v.Doc, nil) v.Doc = buf.String() } buf.Reset() v.Decl = template.HTMLEscapeString(v.Decl) v.Decl = strings.Replace(v.Decl, """, "\"", -1) utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Consts[i] = v } // Variables. this.Data["IsHasVar"] = pdoc.IsHasVar this.Data["Vars"] = pdoc.Vars for i, v := range pdoc.Vars { if len(v.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, v.Doc, nil) v.Doc = buf.String() } buf.Reset() utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Vars[i] = v } // Dirs. pinfos := models.GetSubPkgs(pdoc.ImportPath, tag, pdoc.Dirs) if len(pinfos) > 0 { pdoc.IsHasSubdir = true this.Data["IsHasSubdirs"] = pdoc.IsHasSubdir this.Data["Subdirs"] = pinfos this.Data["ViewDirPath"] = pdoc.ViewDirPath } // Files. if len(pdoc.Files) > 0 { pdoc.IsHasFile = true this.Data["IsHasFiles"] = pdoc.IsHasFile this.Data["Files"] = pdoc.Files var query string if i := strings.Index(pdoc.Files[0].BrowseUrl, "?"); i > -1 { query = pdoc.Files[0].BrowseUrl[i:] } this.Data["ViewFilePath"] = path.Dir(pdoc.Files[0].BrowseUrl) + "/" + query } var err error pfuncs := doc.RenderFuncs(pdoc) this.Data["Funcs"] = pdoc.Funcs for i, f := range pdoc.Funcs { if len(f.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() + " {" if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 { f.Examples = exs } totalNum++ pdoc.Funcs[i] = f } this.Data["Types"] = pdoc.Types for i, t := range pdoc.Types { for j, v := range t.Consts { if len(v.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, v.Doc, nil) v.Doc = buf.String() } buf.Reset() v.Decl = template.HTMLEscapeString(v.Decl) v.Decl = strings.Replace(v.Decl, """, "\"", -1) utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() t.Consts[j] = v } for j, v := range t.Vars { if len(v.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, v.Doc, nil) v.Doc = buf.String() } buf.Reset() utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() t.Vars[j] = v } for j, f := range t.Funcs { if len(f.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() + " {" if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 { f.Examples = exs } totalNum++ t.Funcs[j] = f } for j, m := range t.Methods { if len(m.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, m.Doc, nil) m.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &m.Decl, links) m.FmtDecl = buf.String() + " {" if exs := getExamples(pdoc, t.Name, m.Name); len(exs) > 0 { m.Examples = exs } totalNum++ t.Methods[j] = m } if len(t.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, t.Doc, nil) t.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &t.Decl, links) t.FmtDecl = buf.String() if exs := getExamples(pdoc, "", t.Name); len(exs) > 0 { t.Examples = exs } totalNum++ pdoc.Types[i] = t } if !pdoc.IsCmd { // Calculate documentation complete %. this.Data["DocCPLabel"], this.Data["DocCP"] = calDocCP(comNum, totalNum) } else { this.Data["IsCmd"] = true } // Examples. links = append(links, &utils.Link{ Name: path.Base(pdoc.ImportPath) + ".", }) for _, e := range pdoc.Examples { buf.Reset() utils.FormatCode(&buf, &e.Code, links) e.Code = buf.String() } for _, e := range pdoc.UserExamples { buf.Reset() utils.FormatCode(&buf, &e.Code, links) e.Code = buf.String() } this.Data["ImportPath"] = pdoc.ImportPath if len(tag) == 0 && (pdoc.IsCmd || pdoc.IsGoRepo || pdoc.IsGoSubrepo) { this.Data["IsHasHv"] = true } // GitHub redirects non-HTTPS link and Safari loses "#XXX". if strings.HasPrefix(pdoc.ImportPath, "github") { this.Data["Secure"] = "s" } this.TplNames = "tpl/docs.tpl" data, err := this.RenderBytes() if err != nil { beego.Error("generatePage(", pdoc.ImportPath, ") -> RenderBytes:", err) return false } n := utils.SaveDocPage(docPath, com.Html2JS(data)) if n == -1 { return false } pdoc.JsNum = n pdoc.Id, err = doc.SaveProject(pdoc, pfuncs) if err != nil { beego.Error("generatePage(", pdoc.ImportPath, ") -> SaveProject:", err) return false } models.SavePkgDoc(pdoc.ImportPath, pdoc.Readme) this.Data["UtcTime"] = pdoc.Created this.Data["TimeSince"] = calTimeSince(pdoc.Created) return true }
// generatePage genarates documentation page for project. // it returns false when its a invaild(empty) project. func generatePage(this *HomeRouter, pdoc *doc.Package, q, tag, lang string) bool { // Load project data from database. pdecl, err := models.LoadProject(pdoc.ImportPath, tag) if err != nil { beego.Error("HomeController.generatePage ->", err) return false } // Set properties. this.TplNames = "docs_" + lang + ".html" // Refresh (within 10 seconds). this.Data["IsRefresh"] = pdoc.Created.Add(10 * time.Second).UTC().After(time.Now().UTC()) // Get VCS name, project name, project home page, and Upper level project URL. this.Data["VCS"], this.Data["ProName"], this.Data["ProPath"], this.Data["ProDocPath"] = getVCSInfo(q, tag, pdoc) if utils.IsGoRepoPath(pdoc.ImportPath) && strings.Index(pdoc.ImportPath, ".") == -1 { this.Data["IsGoRepo"] = true } this.Data["Views"] = pdoc.Views + 1 // Labels. this.Data["Labels"] = getLabels(pdoc.Labels) // Introduction. this.Data["ImportPath"] = pdoc.ImportPath byts, _ := base32.StdEncoding.DecodeString( models.LoadPkgDoc(pdoc.ImportPath, lang, "rm")) this.Data["PkgDoc"] = string(byts) byts, _ = base32.StdEncoding.DecodeString(pdecl.Doc) this.Data["PkgFullIntro"] = string(byts) var buf bytes.Buffer // Convert data format. err = ConvertDataFormat(pdoc, pdecl) if err != nil { beego.Error("HomeController.generatePage -> ConvertDataFormat:", err) return false } links := make([]*utils.Link, 0, len(pdoc.Types)+len(pdoc.Imports)+len(pdoc.Funcs)+10) // Get all types, functions and import packages for _, t := range pdoc.Types { links = append(links, &utils.Link{ Name: t.Name, Comment: template.HTMLEscapeString(t.Doc), }) buf.WriteString(""" + t.Name + "",") } for _, f := range pdoc.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString(""" + f.Name + "",") } for _, t := range pdoc.Types { for _, f := range t.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString(""" + f.Name + "",") } for _, m := range t.Methods { buf.WriteString(""" + t.Name + "." + m.Name + "",") } } for _, v := range pdoc.Imports { links = append(links, &utils.Link{ Name: path.Base(v) + ".", Path: v, }) } exportDataSrc := buf.String() if len(exportDataSrc) > 0 { this.Data["HasExports"] = true exportDataSrc = exportDataSrc[:len(exportDataSrc)-1] // Set export keyword type-ahead. this.Data["ExportDataSrc"] = exportDataSrc } // Commented and total objects number. var comNum, totalNum int // Index. this.Data["IsHasConst"] = len(pdoc.Consts) > 0 this.Data["IsHasVar"] = len(pdoc.Vars) > 0 // Constants. this.Data["Consts"] = pdoc.Consts for i, v := range pdoc.Consts { buf.Reset() v.Decl = template.HTMLEscapeString(v.Decl) v.Decl = strings.Replace(v.Decl, """, "\"", -1) utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Consts[i] = v } // Variables. this.Data["Vars"] = pdoc.Vars for i, v := range pdoc.Vars { buf.Reset() utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Vars[i] = v } this.Data["Funcs"] = pdoc.Funcs for i, f := range pdoc.Funcs { if len(f.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Code, links) f.Code = buf.String() if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 { f.IsHasExam = true f.Exams = exs } totalNum++ pdoc.Funcs[i] = f } this.Data["Types"] = pdoc.Types for i, t := range pdoc.Types { for j, f := range t.Funcs { if len(f.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Code, links) f.Code = buf.String() if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 { f.IsHasExam = true f.Exams = exs } totalNum++ t.Funcs[j] = f } for j, m := range t.Methods { if len(m.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, m.Doc, nil) m.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &m.Decl, links) m.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &m.Code, links) m.Code = buf.String() if exs := getExamples(pdoc, t.Name, m.Name); len(exs) > 0 { m.IsHasExam = true m.Exams = exs } totalNum++ t.Methods[j] = m } if len(t.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, t.Doc, nil) t.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &t.Decl, links) t.FmtDecl = buf.String() if exs := getExamples(pdoc, "", t.Name); len(exs) > 0 { t.IsHasExam = true t.Exams = exs } totalNum++ pdoc.Types[i] = t } if !pdoc.IsCmd { // Calculate documentation complete %. this.Data["DocCPLabel"], this.Data["DocCP"] = calDocCP(comNum, totalNum) // Examples. this.Data["IsHasExams"] = len(pdoc.Examples)+len(pdoc.UserExamples) > 0 this.Data["Exams"] = append(pdoc.Examples, pdoc.UserExamples...) // Tags. this.Data["IsHasTags"] = len(pdoc.Tags) > 1 if len(tag) == 0 { tag = "master" } this.Data["CurTag"] = tag this.Data["Tags"] = pdoc.Tags } else { this.Data["IsCmd"] = true } // Dirs. this.Data["IsHasSubdirs"] = len(pdoc.Dirs) > 0 pinfos := make([]*models.PkgInfo, 0, len(pdoc.Dirs)) for _, v := range pdoc.Dirs { v = pdoc.ImportPath + "/" + v if pinfo, err := models.GetPkgInfo(v, tag); err == nil { pinfos = append(pinfos, pinfo) } else { pinfos = append(pinfos, &models.PkgInfo{Path: v}) } } this.Data["Subdirs"] = pinfos // Labels. this.Data["LabelDataSrc"] = labelSet this.Data["Files"] = pdoc.Files this.Data["ImportPkgs"] = pdecl.Imports this.Data["ImportPkgNum"] = len(pdoc.Imports) - 1 this.Data["IsImported"] = pdoc.ImportedNum > 0 this.Data["ImportPid"] = pdoc.ImportPid this.Data["ImportedNum"] = pdoc.ImportedNum this.Data["UtcTime"] = pdoc.Created return true }
// Build generates documentation from given source files through 'WalkType'. func (w *Walker) Build(wr *WalkRes) (*Package, error) { ctxt := build.Context{ CgoEnabled: true, ReleaseTags: build.Default.ReleaseTags, BuildTags: build.Default.BuildTags, Compiler: "gc", } if w.Pdoc.PkgDecl == nil { w.Pdoc.PkgDecl = &PkgDecl{} } // Check 'WalkType'. switch wr.WalkType { case WT_Local: // Check root path. if len(wr.RootPath) == 0 { return nil, errors.New("WT_Local: empty root path") } else if !com.IsDir(wr.RootPath) { return nil, errors.New("WT_Local: cannot find specific directory or it's a file") } w.setLocalContext(&ctxt) return nil, errors.New("Hasn't supported yet!") case WT_Memory: // Convert source files. w.SrcFiles = make(map[string]*Source) w.Pdoc.Readme = make(map[string][]byte) for _, src := range wr.Srcs { srcName := strings.ToLower(src.Name()) // For readme comparation. switch { case strings.HasSuffix(src.Name(), ".go"): w.SrcFiles[src.Name()] = src case len(w.Pdoc.Tag) > 0 || (wr.WalkMode&WM_NoReadme != 0): // This means we are not on the latest version of the code, // so we do not collect the README files. continue case strings.HasPrefix(srcName, "readme_zh") || strings.HasPrefix(srcName, "readme_cn"): w.Pdoc.Readme["zh"] = src.Data() case strings.HasPrefix(srcName, "readme"): w.Pdoc.Readme["en"] = src.Data() } } // Check source files. if w.SrcFiles == nil { return nil, errors.New("WT_Memory: no Go source file") } w.setMemoryContext(&ctxt) default: return nil, errors.New("Hasn't supported yet!") } var err error var bpkg *build.Package for _, env := range goEnvs { ctxt.GOOS = env.GOOS ctxt.GOARCH = env.GOARCH bpkg, err = ctxt.ImportDir(w.Pdoc.ImportPath, 0) // Continue if there are no Go source files; we still want the directory info. _, nogo := err.(*build.NoGoError) if err != nil { if nogo { err = nil } else { return nil, errors.New("hv.Walker.Build -> ImportDir: " + err.Error()) } } } w.Pdoc.IsCmd = bpkg.IsCommand() w.Pdoc.Synopsis = synopsis(bpkg.Doc) w.Pdoc.Imports = bpkg.Imports w.Pdoc.IsCgo = w.isCgo() w.Pdoc.TestImports = bpkg.TestImports // Check depth. if wr.WalkDepth <= WD_Imports { return w.Pdoc, nil } w.Fset = token.NewFileSet() // Parse the Go files files := make(map[string]*ast.File) for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) { file, err := parser.ParseFile(w.Fset, name, w.SrcFiles[name].Data(), parser.ParseComments) if err != nil { return nil, errors.New("hv.Walker.Build -> parse Go files: " + err.Error()) continue } w.Pdoc.Files = append(w.Pdoc.Files, w.SrcFiles[name]) w.Pdoc.SourceSize += int64(len(w.SrcFiles[name].Data())) files[name] = file } w.apkg, _ = ast.NewPackage(w.Fset, files, poorMansImporter, nil) // Find examples in the test files. for _, name := range append(bpkg.TestGoFiles, bpkg.XTestGoFiles...) { file, err := parser.ParseFile(w.Fset, name, w.SrcFiles[name].Data(), parser.ParseComments) if err != nil { return nil, errors.New("hv.Walker.Build -> find examples: " + err.Error()) continue } w.Pdoc.TestFiles = append(w.Pdoc.TestFiles, w.SrcFiles[name]) //w.pdoc.TestSourceSize += len(w.srcs[name].data) if wr.WalkMode&WM_NoExample != 0 { continue } w.Examples = append(w.Examples, doc.Examples(file)...) } mode := doc.Mode(0) if w.Pdoc.ImportPath == "builtin" || wr.BuildAll { mode |= doc.AllDecls } pdoc := doc.New(w.apkg, w.Pdoc.ImportPath, mode) // Get doc. pdoc.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r") var buf bytes.Buffer doc.ToHTML(&buf, pdoc.Doc, nil) w.Pdoc.Doc = buf.String() // Highlight first sentence. w.Pdoc.Doc = strings.Replace(w.Pdoc.Doc, "<p>", "<p><b>", 1) w.Pdoc.Doc = strings.Replace(w.Pdoc.Doc, "</p>", "</b></p>", 1) if wr.WalkMode&WM_NoExample == 0 { w.getExamples() } w.SrcLines = make(map[string][]string) w.Pdoc.Consts = w.values(pdoc.Consts) w.Pdoc.Funcs, w.Pdoc.Ifuncs = w.funcs(pdoc.Funcs) w.Pdoc.Types, w.Pdoc.Itypes = w.types(pdoc.Types) w.Pdoc.Vars = w.values(pdoc.Vars) //w.Pdoc.Notes = w.notes(pdoc.Notes) return w.Pdoc, nil }
// build generates data from source files. func (w *walker) build(srcs []*source) (*Package, error) { // Set created time. w.pdoc.Created = time.Now().UTC() // Add source files to walker, I skipped references here. w.srcs = make(map[string]*source) for _, src := range srcs { if strings.HasSuffix(src.name, ".go") { w.srcs[src.name] = src } else if strings.HasPrefix(strings.ToLower(src.name), "readme") { // Readme. w.pdoc.Doc = string(src.data) if len(w.pdoc.Doc) > 0 { if w.pdoc.Doc[0] == '\n' { w.pdoc.Doc = w.pdoc.Doc[1:] } // Remove title and `==========`. w.pdoc.Doc = w.pdoc.Doc[strings.Index(w.pdoc.Doc, "\n")+1:] if len(w.pdoc.Doc) == 0 { continue } if w.pdoc.Doc[0] == '=' { w.pdoc.Doc = w.pdoc.Doc[strings.Index(w.pdoc.Doc, "\n")+1:] } // Find all picture path of build system. for _, m := range buildPicPattern.FindAllString(w.pdoc.Doc, -1) { start := strings.Index(m, "http") end := strings.Index(m, ")") if (start > -1) && (end > -1) && (start < end) { picPath := m[start:end] w.pdoc.Doc = strings.Replace(w.pdoc.Doc, m, "![]("+picPath+")", 1) } } w.pdoc.Doc = string(blackfriday.MarkdownCommon([]byte(w.pdoc.Doc))) w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "h3>", "h5>", -1) w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "h2>", "h4>", -1) w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "h1>", "h3>", -1) w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "<center>", "", -1) w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "</center>", "", -1) w.pdoc.Doc = "<div style='display:block; padding: 3px; border:1px solid #4F4F4F;'>" + w.pdoc.Doc + "</div>" } } } w.fset = token.NewFileSet() // Find the package and associated files. ctxt := build.Context{ GOOS: runtime.GOOS, GOARCH: runtime.GOARCH, CgoEnabled: true, JoinPath: path.Join, IsAbsPath: path.IsAbs, SplitPathList: func(list string) []string { return strings.Split(list, ":") }, IsDir: func(path string) bool { panic("unexpected") }, HasSubdir: func(root, dir string) (rel string, ok bool) { panic("unexpected") }, ReadDir: func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) }, OpenFile: func(path string) (r io.ReadCloser, err error) { return w.openFile(path) }, Compiler: "gc", } bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0) // Continue if there are no Go source files; we still want the directory info. _, nogo := err.(*build.NoGoError) if err != nil { if nogo { err = nil beego.Info("doc.walker.build(): No Go Source file.") } else { return w.pdoc, errors.New("doc.walker.build(): " + err.Error()) } } // Parse the Go files files := make(map[string]*ast.File) for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) { file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments) if err != nil { beego.Error("doc.walker.build().[parse go files]:", err) continue } w.pdoc.Files = append(w.pdoc.Files, name) //w.pdoc.SourceSize += len(w.srcs[name].data) files[name] = file } apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil) // Find examples in the test files. // for _, name := range append(bpkg.TestGoFiles, bpkg.XTestGoFiles...) { // file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments) // if err != nil { // beego.Error("doc.walker.build().[find examples]:", err) // continue // } // //w.pdoc.TestFiles = append(w.pdoc.TestFiles, &File{Name: name, URL: w.srcs[name].browseURL}) // //w.pdoc.TestSourceSize += len(w.srcs[name].data) // w.examples = append(w.examples, doc.Examples(file)...) // } //w.vetPackage(apkg) mode := doc.Mode(0) if w.pdoc.ImportPath == "builtin" { mode |= doc.AllDecls } pdoc := doc.New(apkg, w.pdoc.ImportPath, mode) w.pdoc.Synopsis = utils.Synopsis(pdoc.Doc) pdoc.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r") var buf bytes.Buffer doc.ToHTML(&buf, pdoc.Doc, nil) w.pdoc.Doc = w.pdoc.Doc + "<br />" + buf.String() w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "<p>", "<p><b>", 1) w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "</p>", "</b></p>", 1) w.pdoc.Doc = base32.StdEncoding.EncodeToString([]byte(w.pdoc.Doc)) //w.pdoc.Examples = w.getExamples("") //w.pdoc.IsCmd = bpkg.IsCommand() w.pdoc.GOOS = ctxt.GOOS w.pdoc.GOARCH = ctxt.GOARCH w.srcLines = make(map[string][]string) w.pdoc.Consts = w.values(pdoc.Consts) w.pdoc.Funcs = w.funcs(pdoc.Funcs) w.pdoc.Types = w.types(pdoc.Types) w.pdoc.Vars = w.values(pdoc.Vars) //w.pdoc.Notes = w.notes(pdoc.Notes) w.pdoc.Imports = bpkg.Imports w.pdoc.TestImports = bpkg.TestImports //w.pdoc.XTestImports = bpkg.XTestImports beego.Info("doc.walker.build(", pdoc.ImportPath, "), Goroutine #", runtime.NumGoroutine()) return w.pdoc, err }
func (g *Grapher) emitDoc(obj types.Object, dc *ast.CommentGroup, docstring, filename string) bool { if docstring == "" { return false } if obj == nil { var htmlBuf bytes.Buffer doc.ToHTML(&htmlBuf, docstring, nil) var span [2]uint32 if dc != nil { span = makeSpan(g.program.Fset, dc) } g.addDoc(&Doc{ DefKey: nil, Format: "text/html", Data: htmlBuf.String(), File: filename, Span: span, }) g.addDoc(&Doc{ DefKey: nil, Format: "text/plain", Data: docstring, File: filename, Span: span, }) return true } if g.seenDocObjs == nil { g.seenDocObjs = make(map[types.Object]struct{}) } if _, seen := g.seenDocObjs[obj]; seen { return false } g.seenDocObjs[obj] = struct{}{} key, _, err := g.defInfo(obj) if err != nil { return false } if g.seenDocKeys == nil { g.seenDocKeys = make(map[string]struct{}) } if _, seen := g.seenDocKeys[key.String()]; seen { return false } g.seenDocKeys[key.String()] = struct{}{} var htmlBuf bytes.Buffer doc.ToHTML(&htmlBuf, docstring, nil) var span [2]uint32 if dc != nil { span = makeSpan(g.program.Fset, dc) } g.addDoc(&Doc{ DefKey: key, Format: "text/html", Data: htmlBuf.String(), File: filename, Span: span, }) g.addDoc(&Doc{ DefKey: key, Format: "text/plain", Data: docstring, File: filename, Span: span, }) return true }