~emersion/drmdb

ref: 5046ca990b3604ebf4a535753d0da6b151f37645 drmdb/drmdoc/generate.go -rw-r--r-- 3.4 KiB
5046ca99Simon Ser drmdoc: sort props by name a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//+build ignore

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"go/format"
	"log"
	"net/http"
	"os"
	"sort"
	"strings"
	"unicode"
)

const baseURL = "https://cgit.freedesktop.org/drm-tip/plain"

func fetchDoc(filename, header string) (string, error) {
	resp, err := http.Get(baseURL + "/" + filename)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	scanner := bufio.NewScanner(resp.Body)
	inDocComment := false
	isDocHeader := false
	found := false
	var sb strings.Builder
	for scanner.Scan() {
		l := scanner.Text()
		if inDocComment {
			l = strings.TrimPrefix(l, " * ")
			if strings.Contains(l, "*/") {
				inDocComment = false
				if found {
					break
				}
			} else if isDocHeader {
				isDocHeader = false
				if strings.TrimSpace(l) == "DOC: "+header {
					found = true
				}
			} else if found {
				l = strings.TrimPrefix(l, " *")
				sb.WriteString(l + "\n")
			}
		} else if l == "/**" {
			inDocComment = true
			isDocHeader = true
		}
	}
	if err := scanner.Err(); err != nil {
		return "", err
	}
	if !found {
		return "", fmt.Errorf("doc comment %q not found", header)
	}
	return sb.String(), nil
}

func parseProps(s string) map[string]string {
	lines := strings.Split(s, "\n")
	m := make(map[string]string)
	var header, indent string
	var body strings.Builder
	for _, l := range lines {
		if len(l) > 0 && !unicode.IsSpace(rune(l[0])) && strings.HasSuffix(l, ":") {
			bodyStr := strings.TrimSpace(body.String())
			if bodyStr != "" {
				m[header] = bodyStr
			}
			body.Reset()
			if i := strings.Index(l, "("); i >= 0 {
				l = l[:i] // Strip comments in parentheses
			}
			header = strings.Trim(l, " :\"“”")
			indent = ""
			continue
		}
		if header == "" {
			continue
		}

		if indent == "" {
			for _, ch := range l {
				if !unicode.IsSpace(ch) {
					break
				}
				indent += string(ch)
			}
		}

		body.WriteString(strings.TrimPrefix(l, indent) + "\n")
	}
	bodyStr := strings.TrimSpace(body.String())
	if bodyStr != "" {
		m[header] = bodyStr
	}

	return m
}

func titleToFilename(title string) string {
	fields := strings.Fields(title)
	return strings.ToLower(strings.Join(fields, "-"))
}

func titleToSymbol(title string) string {
	fields := strings.Fields(title)
	var sym string
	for i, s := range fields {
		if i == 0 {
			s = strings.ToLower(s)
		} else {
			s = strings.Title(s)
		}
		sym += s
	}
	return sym
}

func main() {
	if len(os.Args) < 3 {
		fmt.Println("usage: generate <filename> <header> [title]")
		os.Exit(1)
	}
	filename := os.Args[1]
	header := os.Args[2]
	outTitle := header
	if len(os.Args) > 3 {
		outTitle = os.Args[3]
	}

	doc, err := fetchDoc(filename, header)
	if err != nil {
		log.Fatal(err)
	}

	props := parseProps(doc)

	symbol := titleToSymbol(outTitle)

	var out bytes.Buffer
	out.WriteString(`// Code generated by running "go generate". DO NOT EDIT.

package drmdoc

var ` + symbol + ` = map[string]string{
`)

	propNames := make([]string, 0, len(props))
	for name := range props {
		propNames = append(propNames, name)
	}
	sort.Strings(propNames)

	for _, name := range propNames {
		desc := props[name]
		fmt.Fprintf(&out, "\t%q: %q,\n", name, desc)
	}

	out.WriteString("}\n")

	b, err := format.Source(out.Bytes())
	if err != nil {
		log.Fatal(err)
	}

	f, err := os.Create(titleToFilename(outTitle) + ".go")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	if _, err := f.Write(b); err != nil {
		log.Fatal(err)
	}
	if err := f.Close(); err != nil {
		log.Fatal(err)
	}
}