diff --git a/GNUmakefile b/GNUmakefile index 95577470..49308710 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -7,7 +7,7 @@ all: apidoc: $(BLOG)/blog -site -lib $(BLOG) -draft -t templates/mpcl -o $(OUTPUT) docs/apidoc/ - ./apps/mpcldoc/mpcldoc -dir $(OUTPUT) pkg + ./apps/mpcldoc/mpcldoc -dir $(OUTPUT) pkg apps/garbled/examples public: make apidoc OUTPUT=$(HOME)/work/www/mpcl diff --git a/apps/mpcldoc/doc.go b/apps/mpcldoc/doc.go index b728e891..e9d818f4 100644 --- a/apps/mpcldoc/doc.go +++ b/apps/mpcldoc/doc.go @@ -1,7 +1,7 @@ // // doc.go // -// Copyright (c) 2021-2023 Markku Rossi +// Copyright (c) 2021-2024 Markku Rossi // // All rights reserved. // @@ -9,6 +9,7 @@ package main import ( + "fmt" "os" "path" "regexp" @@ -38,7 +39,7 @@ type Documenter interface { New(name string) (Output, error) // Index creates an index page for the documentation. - Index(pkgs []*Package) error + Index(pkgs, mains []*Package) error } // Output implements document output @@ -84,12 +85,14 @@ type Output interface { var packages = make(map[string]*Package) var typeDefs = make(map[string]*Package) +var mains = make(map[string]*Package) func documentation(files []string, doc Documenter) error { err := parseInputs(files) if err != nil { return err } + var pkgs []*Package for _, pkg := range packages { pkgs = append(pkgs, pkg) @@ -103,14 +106,35 @@ func documentation(files []string, doc Documenter) error { return pkgs[i].Name < pkgs[j].Name }) - doc.Index(pkgs) + var mns []*Package + for _, pkg := range mains { + mns = append(mns, pkg) + } + sort.Slice(mns, func(i, j int) bool { + return mns[i].Name < mns[j].Name + }) + + doc.Index(pkgs, mns) for _, pkg := range pkgs { - out, err := doc.New(pkg.Name) + out, err := doc.New("pkg_" + pkg.Docfile()) + if err != nil { + return err + } + if err := documentPackage("Package", out, pkg); err != nil { + out.Close() + return err + } + if err := out.Close(); err != nil { + return err + } + } + for _, pkg := range mns { + out, err := doc.New("prg_" + pkg.Docfile()) if err != nil { return err } - if err := documentPackage(out, pkg); err != nil { + if err := documentPackage("Program", out, pkg); err != nil { out.Close() return err } @@ -166,12 +190,26 @@ func parseFile(name string) error { if err != nil { return err } - p, ok := packages[pkg.Name] - if !ok { + + var p *Package + var ok bool + if pkg.Name == "main" { + p, ok = mains[pkg.Source] + if ok { + return fmt.Errorf("file '%v' already processed", name) + } p = &Package{ - Name: pkg.Name, + Name: pkg.Source, + } + mains[pkg.Source] = p + } else { + p, ok = packages[pkg.Name] + if !ok { + p = &Package{ + Name: pkg.Name, + } + packages[pkg.Name] = p } - packages[pkg.Name] = p } p.Annotations = append(p.Annotations, pkg.Annotations...) p.Constants = append(p.Constants, pkg.Constants...) @@ -185,10 +223,10 @@ func parseFile(name string) error { return nil } -func documentPackage(out Output, pkg *Package) error { +func documentPackage(kind string, out Output, pkg *Package) error { builtin := pkg.Name == "builtin" - if err := out.H1(text.New().Plainf("Package %s", pkg.Name)); err != nil { + if err := out.H1(text.New().Plainf("%s %s", kind, pkg.Name)); err != nil { return nil } err := annotations(out, pkg.Annotations) @@ -551,3 +589,8 @@ type Package struct { Functions []*ast.Func Types []*ast.TypeInfo } + +// Docfile returns the package's documentation filename. +func (pkg *Package) Docfile() string { + return strings.ReplaceAll(pkg.Name, "/", "_") +} diff --git a/apps/mpcldoc/doc_html.go b/apps/mpcldoc/doc_html.go index 7b800e63..fb20b106 100644 --- a/apps/mpcldoc/doc_html.go +++ b/apps/mpcldoc/doc_html.go @@ -1,7 +1,7 @@ // // doc.go // -// Copyright (c) 2021-2023 Markku Rossi +// Copyright (c) 2021-2024 Markku Rossi // // All rights reserved. // @@ -10,6 +10,7 @@ package main import ( "fmt" + "html" "io" "os" "path" @@ -38,7 +39,7 @@ func NewHTMLDoc(dir string) (*HTMLDoc, error) { // New implements Documenter.New. func (doc *HTMLDoc) New(name string) (Output, error) { - file := path.Join(doc.dir, fmt.Sprintf("pkg_%s.html", name)) + file := path.Join(doc.dir, fmt.Sprintf("%s.html", name)) f, err := os.Create(file) if err != nil { return nil, err @@ -56,7 +57,7 @@ func (doc *HTMLDoc) New(name string) (Output, error) { } // Index implements Documenter.Index. -func (doc *HTMLDoc) Index(pkgs []*Package) error { +func (doc *HTMLDoc) Index(pkgs, mains []*Package) error { file := path.Join(doc.dir, "apidoc.html") f, err := os.Create(file) if err != nil { @@ -64,7 +65,7 @@ func (doc *HTMLDoc) Index(pkgs []*Package) error { } defer f.Close() - err = index(f, pkgs) + err = index(f, pkgs, mains) if err != nil { os.Remove(file) return err @@ -72,7 +73,7 @@ func (doc *HTMLDoc) Index(pkgs []*Package) error { return nil } -func index(out io.Writer, pkgs []*Package) error { +func index(out io.Writer, pkgs, mains []*Package) error { err := header(out) if err != nil { return err @@ -85,19 +86,44 @@ func index(out io.Writer, pkgs []*Package) error { if err != nil { return err } - for _, pkg := range pkgs { first := pkg.Annotations.FirstSentence() _, err := fmt.Fprintf(out, `
Package %s
`, - fmt.Sprintf("pkg_%s.html", pkg.Name), pkg.Name) + fmt.Sprintf("pkg_%s.html", pkg.Docfile()), + html.EscapeString(pkg.Name)) + if err != nil { + return err + } + if len(first) > 0 { + _, err = fmt.Fprintf(out, "

%s

\n", html.EscapeString(first)) + if err != nil { + return err + } + } + } + + _, err = fmt.Fprintf(out, ` +

Programs

+`) + if err != nil { + return err + } + for _, pkg := range mains { + first := pkg.Annotations.FirstSentence() + _, err := fmt.Fprintf(out, `
+%s +
+`, + fmt.Sprintf("prg_%s.html", pkg.Docfile()), + html.EscapeString(pkg.Name)) if err != nil { return err } if len(first) > 0 { - _, err = fmt.Fprintf(out, "

%s

\n", first) + _, err = fmt.Fprintf(out, "

%s

\n", html.EscapeString(first)) if err != nil { return err }