github.com/jimmyfrasche/autoreadme@v0.0.0-20240504231658-aacd7e11c8ba/godoc.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"go/ast"
     6  	"go/doc"
     7  	"go/doc/comment"
     8  	"go/format"
     9  	"go/token"
    10  	"strings"
    11  )
    12  
    13  func Synopsis(text string) string {
    14  	d := ParseDoc(text)
    15  	text = string(newPrinter(1).Text(d))
    16  	var p doc.Package
    17  	return p.Synopsis(text)
    18  }
    19  
    20  func ParseDoc(text string) *comment.Doc {
    21  	p := &comment.Parser{
    22  		LookupPackage: func(string) (string, bool) {
    23  			return "", true
    24  		},
    25  		LookupSym: func(string, string) bool {
    26  			return true
    27  		},
    28  	}
    29  	return p.Parse(text)
    30  }
    31  
    32  type Doc struct {
    33  	Empty    bool
    34  	Synopsis string
    35  	*comment.Doc
    36  }
    37  
    38  func NewDoc(text string) *Doc {
    39  	return &Doc{
    40  		Empty:    strings.TrimSpace(strings.ReplaceAll(text, "\n", "")) == "",
    41  		Synopsis: Synopsis(text),
    42  		Doc:      ParseDoc(text),
    43  	}
    44  }
    45  
    46  func epsilon(*comment.Heading) string {
    47  	return ""
    48  }
    49  
    50  func noLink(*comment.DocLink) string {
    51  	return ""
    52  }
    53  
    54  func newPrinter(headingLevel int) *comment.Printer {
    55  	return &comment.Printer{
    56  		HeadingLevel: headingLevel,
    57  		HeadingID:    epsilon,
    58  		DocLinkURL:   noLink,
    59  	}
    60  }
    61  
    62  func (d *Doc) Markdown(headingLevel int) string {
    63  	p := newPrinter(headingLevel)
    64  	return string(p.Markdown(d.Doc))
    65  }
    66  
    67  func renderExample(buf *bytes.Buffer, fset *token.FileSet, in *doc.Example) Example {
    68  	out := Example{
    69  		Name:          in.Name,
    70  		Documentation: NewDoc(in.Doc),
    71  		Playable:      in.Play != nil,
    72  		Unordered:     in.Unordered,
    73  		EmptyOutput:   in.EmptyOutput,
    74  	}
    75  
    76  	code := []any{in.Play}
    77  	if !out.Playable {
    78  		code = []any{}
    79  		for _, line := range in.Code.(*ast.BlockStmt).List {
    80  			code = append(code, line)
    81  		}
    82  	}
    83  
    84  	buf.Reset()
    85  	buf.WriteString("```go\n")
    86  	for _, line := range code {
    87  		format.Node(buf, fset, line)
    88  
    89  		// playable examples end with a newline already
    90  		if !out.Playable {
    91  			buf.WriteString("\n")
    92  		}
    93  	}
    94  	buf.WriteString("```\n")
    95  	out.Code = buf.String()
    96  
    97  	if in.Output != "" {
    98  		out.Output = "```\n" + in.Output + "```\n"
    99  	}
   100  	return out
   101  }