|
1 | 1 | package main
|
2 | 2 |
|
3 | 3 | import (
|
4 |
| - "bytes" |
5 | 4 | "context"
|
| 5 | + _ "embed" |
6 | 6 | "fmt"
|
7 |
| - "os/exec" |
| 7 | + "regexp" |
8 | 8 | "strings"
|
9 | 9 |
|
10 |
| - "github.com/russross/blackfriday" |
| 10 | + "github.com/charmbracelet/glamour" |
11 | 11 | )
|
12 | 12 |
|
| 13 | +//go:embed description.json |
| 14 | +var descriptionJSONBytes []byte |
| 15 | + |
| 16 | +// reformatForControl reformats the wrapped description |
| 17 | +// to conform to Debian’s control format. |
13 | 18 | func reformatForControl(raw string) string {
|
14 |
| - // Reformat the wrapped description to conform to Debian’s control format. |
15 |
| - for strings.Contains(raw, "\n\n") { |
16 |
| - raw = strings.Replace(raw, "\n\n", "\n.\n", -1) |
| 19 | + output := "" |
| 20 | + next_prefix := "" |
| 21 | + re := regexp.MustCompile(`^ \d+\. `) |
| 22 | + |
| 23 | + for _, line := range strings.Split(strings.TrimSpace(raw), "\n") { |
| 24 | + // Remove paddings that Glamour currently add to the end of each line |
| 25 | + line = strings.TrimRight(line, " ") |
| 26 | + |
| 27 | + // Try to add hanging indent for list items that span over one line |
| 28 | + prefix := next_prefix |
| 29 | + if strings.HasPrefix(line, " * ") { |
| 30 | + // unordered list |
| 31 | + prefix = "" |
| 32 | + next_prefix = " " |
| 33 | + } |
| 34 | + if re.MatchString(line) { |
| 35 | + // ordered list |
| 36 | + prefix = "" |
| 37 | + next_prefix = " " |
| 38 | + } |
| 39 | + if line == "" { |
| 40 | + // blank line, implying end of list |
| 41 | + line = "." |
| 42 | + prefix = "" |
| 43 | + next_prefix = "" |
| 44 | + } |
| 45 | + output += " " + prefix + line + "\n" |
| 46 | + } |
| 47 | + return output |
| 48 | +} |
| 49 | + |
| 50 | +// markdownToLongDescription converts Markdown to plain text |
| 51 | +// and reformat it for expanded description in debian/control. |
| 52 | +func markdownToLongDescription(markdown string) (string, error) { |
| 53 | + r, _ := glamour.NewTermRenderer( |
| 54 | + glamour.WithStylesFromJSONBytes(descriptionJSONBytes), |
| 55 | + glamour.WithWordWrap(72), |
| 56 | + ) |
| 57 | + out, err := r.Render(markdown) |
| 58 | + if err != nil { |
| 59 | + return "", fmt.Errorf("fail to render Markdown: %w", err) |
17 | 60 | }
|
18 |
| - return strings.Replace(raw, "\n", "\n ", -1) |
| 61 | + //fmt.Println(out) |
| 62 | + //fmt.Println(reformatForControl(out)) |
| 63 | + return reformatForControl(out), nil |
19 | 64 | }
|
20 | 65 |
|
21 | 66 | // getDescriptionForGopkg reads from README.md (or equivalent) from GitHub,
|
22 |
| -// intended for the extended description in debian/control. |
| 67 | +// intended for extended description in debian/control. |
23 | 68 | func getLongDescriptionForGopkg(gopkg string) (string, error) {
|
24 | 69 | owner, repo, err := findGitHubRepo(gopkg)
|
25 | 70 | if err != nil {
|
@@ -47,151 +92,8 @@ func getLongDescriptionForGopkg(gopkg string) (string, error) {
|
47 | 92 | !strings.HasSuffix(rr.GetName(), "markdown") &&
|
48 | 93 | !strings.HasSuffix(rr.GetName(), "mdown") &&
|
49 | 94 | !strings.HasSuffix(rr.GetName(), "mkdn") {
|
50 |
| - return reformatForControl(strings.TrimSpace(string(content))), nil |
| 95 | + return reformatForControl(content), nil |
51 | 96 | }
|
52 | 97 |
|
53 |
| - output := blackfriday.Markdown([]byte(content), &TextRenderer{}, 0) |
54 |
| - // Shell out to fmt(1) to line-wrap the output. |
55 |
| - cmd := exec.Command("fmt") |
56 |
| - cmd.Stdin = bytes.NewBuffer(output) |
57 |
| - out, err := cmd.Output() |
58 |
| - if err != nil { |
59 |
| - return "", fmt.Errorf("fmt: %w", err) |
60 |
| - } |
61 |
| - return reformatForControl(strings.TrimSpace(string(out))), nil |
62 |
| -} |
63 |
| - |
64 |
| -type TextRenderer struct { |
65 |
| -} |
66 |
| - |
67 |
| -func (options *TextRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string) { |
68 |
| - out.Write(text) |
69 |
| -} |
70 |
| - |
71 |
| -func (options *TextRenderer) BlockQuote(out *bytes.Buffer, text []byte) { |
72 |
| - out.Write(text) |
73 |
| -} |
74 |
| - |
75 |
| -func (options *TextRenderer) BlockHtml(out *bytes.Buffer, text []byte) { |
76 |
| - out.Write(text) |
77 |
| -} |
78 |
| - |
79 |
| -func (options *TextRenderer) Header(out *bytes.Buffer, text func() bool, level int, id string) { |
80 |
| - text() |
81 |
| -} |
82 |
| - |
83 |
| -func (options *TextRenderer) HRule(out *bytes.Buffer) { |
84 |
| - out.WriteString("--------------------------------------------------------------------------------\n") |
85 |
| -} |
86 |
| - |
87 |
| -func (options *TextRenderer) List(out *bytes.Buffer, text func() bool, flags int) { |
88 |
| - text() |
89 |
| -} |
90 |
| - |
91 |
| -func (options *TextRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) { |
92 |
| - out.WriteString("• ") |
93 |
| - out.Write(text) |
94 |
| -} |
95 |
| - |
96 |
| -func (options *TextRenderer) Paragraph(out *bytes.Buffer, text func() bool) { |
97 |
| - out.WriteString("\n") |
98 |
| - text() |
99 |
| - out.WriteString("\n") |
100 |
| -} |
101 |
| - |
102 |
| -func (options *TextRenderer) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) { |
103 |
| - out.Write(header) |
104 |
| - out.Write(body) |
105 |
| -} |
106 |
| - |
107 |
| -func (options *TextRenderer) TableRow(out *bytes.Buffer, text []byte) { |
108 |
| - out.Write(text) |
109 |
| -} |
110 |
| - |
111 |
| -func (options *TextRenderer) TableHeaderCell(out *bytes.Buffer, text []byte, flags int) { |
112 |
| - out.Write(text) |
113 |
| -} |
114 |
| - |
115 |
| -func (options *TextRenderer) TableCell(out *bytes.Buffer, text []byte, flags int) { |
116 |
| - out.Write(text) |
117 |
| -} |
118 |
| - |
119 |
| -func (options *TextRenderer) Footnotes(out *bytes.Buffer, text func() bool) { |
120 |
| - text() |
121 |
| -} |
122 |
| - |
123 |
| -func (options *TextRenderer) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) { |
124 |
| - out.WriteString("[") |
125 |
| - out.Write(name) |
126 |
| - out.WriteString("]") |
127 |
| - out.Write(text) |
128 |
| -} |
129 |
| - |
130 |
| -func (options *TextRenderer) TitleBlock(out *bytes.Buffer, text []byte) { |
131 |
| -} |
132 |
| - |
133 |
| -// Span-level callbacks |
134 |
| -func (options *TextRenderer) AutoLink(out *bytes.Buffer, link []byte, kind int) { |
135 |
| - out.Write(link) |
136 |
| -} |
137 |
| - |
138 |
| -func (options *TextRenderer) CodeSpan(out *bytes.Buffer, text []byte) { |
139 |
| - out.Write(text) |
140 |
| -} |
141 |
| - |
142 |
| -func (options *TextRenderer) DoubleEmphasis(out *bytes.Buffer, text []byte) { |
143 |
| - out.Write(text) |
144 |
| -} |
145 |
| - |
146 |
| -func (options *TextRenderer) Emphasis(out *bytes.Buffer, text []byte) { |
147 |
| - out.Write(text) |
148 |
| -} |
149 |
| - |
150 |
| -func (options *TextRenderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { |
151 |
| - out.Write(alt) |
152 |
| -} |
153 |
| - |
154 |
| -func (options *TextRenderer) LineBreak(out *bytes.Buffer) { |
155 |
| - out.WriteString("\n") |
156 |
| -} |
157 |
| - |
158 |
| -func (options *TextRenderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { |
159 |
| - out.Write(content) |
160 |
| - out.WriteString(" (") |
161 |
| - out.Write(link) |
162 |
| - out.WriteString(")") |
163 |
| -} |
164 |
| - |
165 |
| -func (options *TextRenderer) RawHtmlTag(out *bytes.Buffer, tag []byte) { |
166 |
| -} |
167 |
| - |
168 |
| -func (options *TextRenderer) TripleEmphasis(out *bytes.Buffer, text []byte) { |
169 |
| - out.Write(text) |
170 |
| -} |
171 |
| - |
172 |
| -func (options *TextRenderer) StrikeThrough(out *bytes.Buffer, text []byte) { |
173 |
| - out.Write(text) |
174 |
| -} |
175 |
| - |
176 |
| -func (options *TextRenderer) FootnoteRef(out *bytes.Buffer, ref []byte, id int) { |
177 |
| -} |
178 |
| - |
179 |
| -// Low-level callbacks |
180 |
| -func (options *TextRenderer) Entity(out *bytes.Buffer, entity []byte) { |
181 |
| - out.Write(entity) |
182 |
| -} |
183 |
| - |
184 |
| -func (options *TextRenderer) NormalText(out *bytes.Buffer, text []byte) { |
185 |
| - out.Write(text) |
186 |
| -} |
187 |
| - |
188 |
| -// Header and footer |
189 |
| -func (options *TextRenderer) DocumentHeader(out *bytes.Buffer) { |
190 |
| -} |
191 |
| - |
192 |
| -func (options *TextRenderer) DocumentFooter(out *bytes.Buffer) { |
193 |
| -} |
194 |
| - |
195 |
| -func (options *TextRenderer) GetFlags() int { |
196 |
| - return 0 |
| 98 | + return markdownToLongDescription(content) |
197 | 99 | }
|
0 commit comments