github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/_scripts/gen-faq-toc.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"log"
     9  	"os"
    10  	"regexp"
    11  	"strings"
    12  )
    13  
    14  func must(err error, fmtstr string, args ...interface{}) {
    15  	if err != nil {
    16  		log.Fatalf(fmtstr, args...)
    17  	}
    18  }
    19  
    20  func usage() {
    21  	os.Stderr.WriteString("gen-faq-to input-path output-path")
    22  	os.Exit(1)
    23  }
    24  
    25  var anchor = regexp.MustCompile(`### <a name="(.*?)"></a> (.*)`)
    26  
    27  type tocentry struct {
    28  	anchor, title string
    29  }
    30  
    31  const (
    32  	startOfToc = "<!-- BEGIN TOC -->"
    33  	endOfToc   = "<!-- END TOC -->"
    34  )
    35  
    36  func spliceDocs(docpath string, docs []byte, outpath string) {
    37  	docbuf, err := ioutil.ReadFile(docpath)
    38  	if err != nil {
    39  		log.Fatalf("could not read doc file: %v", err)
    40  	}
    41  
    42  	v := strings.Split(string(docbuf), startOfToc)
    43  	if len(v) != 2 {
    44  		log.Fatal("could not find start of mapping table")
    45  	}
    46  	header := v[0]
    47  	v = strings.Split(v[1], endOfToc)
    48  	if len(v) != 2 {
    49  		log.Fatal("could not find end of mapping table")
    50  	}
    51  	footer := v[1]
    52  
    53  	outbuf := bytes.NewBuffer(make([]byte, 0, len(header)+len(docs)+len(footer)+len(startOfToc)+len(endOfToc)+1))
    54  	outbuf.Write([]byte(header))
    55  	outbuf.Write([]byte(startOfToc))
    56  	outbuf.WriteByte('\n')
    57  	outbuf.Write(docs)
    58  	outbuf.Write([]byte(endOfToc))
    59  	outbuf.Write([]byte(footer))
    60  
    61  	if outpath != "-" {
    62  		err = ioutil.WriteFile(outpath, outbuf.Bytes(), 0664)
    63  		must(err, "could not write documentation file: %v", err)
    64  	} else {
    65  		os.Stdout.Write(outbuf.Bytes())
    66  	}
    67  }
    68  
    69  func readtoc(docpath string) []tocentry {
    70  	infh, err := os.Open(docpath)
    71  	must(err, "could not open %s: %v", docpath, err)
    72  	defer infh.Close()
    73  	scan := bufio.NewScanner(infh)
    74  	tocentries := []tocentry{}
    75  	seenAnchors := map[string]bool{}
    76  	for scan.Scan() {
    77  		line := scan.Text()
    78  		if !strings.HasPrefix(line, "### ") {
    79  			continue
    80  		}
    81  		m := anchor.FindStringSubmatch(line)
    82  		if len(m) != 3 {
    83  			log.Fatalf("entry %q does not have anchor", line)
    84  		}
    85  		if seenAnchors[m[1]] {
    86  			log.Fatalf("duplicate anchor %q", m[1])
    87  		}
    88  		anchor, title := m[1], m[2]
    89  		seenAnchors[anchor] = true
    90  		tocentries = append(tocentries, tocentry{anchor, title})
    91  
    92  	}
    93  	must(scan.Err(), "could not read %s: %v", scan.Err())
    94  	return tocentries
    95  }
    96  
    97  func writetoc(tocentries []tocentry) []byte {
    98  	b := new(bytes.Buffer)
    99  	for _, tocentry := range tocentries {
   100  		fmt.Fprintf(b, "* [%s](#%s)\n", tocentry.title, tocentry.anchor)
   101  	}
   102  	return b.Bytes()
   103  }
   104  
   105  func main() {
   106  	if len(os.Args) != 3 {
   107  		usage()
   108  	}
   109  
   110  	docpath, outpath := os.Args[1], os.Args[2]
   111  
   112  	tocentries := readtoc(docpath)
   113  
   114  	spliceDocs(docpath, []byte(writetoc(tocentries)), outpath)
   115  }