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 }