gen.go - hugo - [fork] hugo port for 9front
(HTM) git clone https://git.drkhsh.at/hugo.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
gen.go (10346B)
---
1 // Copyright 2024 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package commands
15
16 import (
17 "bytes"
18 "context"
19 "encoding/json"
20 "fmt"
21 "os"
22 "path"
23 "path/filepath"
24 "slices"
25 "strings"
26
27 "github.com/alecthomas/chroma/v2"
28 "github.com/alecthomas/chroma/v2/formatters/html"
29 "github.com/alecthomas/chroma/v2/styles"
30 "github.com/bep/simplecobra"
31 "github.com/gohugoio/hugo/common/hugo"
32 "github.com/gohugoio/hugo/docshelper"
33 "github.com/gohugoio/hugo/helpers"
34 "github.com/gohugoio/hugo/hugofs"
35 "github.com/gohugoio/hugo/hugolib"
36 "github.com/gohugoio/hugo/parser"
37 "github.com/spf13/cobra"
38 "github.com/spf13/cobra/doc"
39 "gopkg.in/yaml.v2"
40 )
41
42 func newGenCommand() *genCommand {
43 var (
44 // Flags.
45 gendocdir string
46 genmandir string
47
48 // Chroma flags.
49 style string
50 highlightStyle string
51 lineNumbersInlineStyle string
52 lineNumbersTableStyle string
53 omitEmpty bool
54 )
55
56 newChromaStyles := func() simplecobra.Commander {
57 return &simpleCommand{
58 name: "chromastyles",
59 short: "Generate CSS stylesheet for the Chroma code highlighter",
60 long: `Generate CSS stylesheet for the Chroma code highlighter for a given style. This stylesheet is needed if markup.highlight.noClasses is disabled in config.
61
62 See https://xyproto.github.io/splash/docs/all.html for a preview of the available styles`,
63
64 run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
65 style = strings.ToLower(style)
66 if !slices.Contains(styles.Names(), style) {
67 return fmt.Errorf("invalid style: %s", style)
68 }
69 builder := styles.Get(style).Builder()
70 if highlightStyle != "" {
71 builder.Add(chroma.LineHighlight, highlightStyle)
72 }
73 if lineNumbersInlineStyle != "" {
74 builder.Add(chroma.LineNumbers, lineNumbersInlineStyle)
75 }
76 if lineNumbersTableStyle != "" {
77 builder.Add(chroma.LineNumbersTable, lineNumbersTableStyle)
78 }
79 style, err := builder.Build()
80 if err != nil {
81 return err
82 }
83
84 var formatter *html.Formatter
85 if omitEmpty {
86 formatter = html.New(html.WithClasses(true))
87 } else {
88 formatter = html.New(html.WithAllClasses(true))
89 }
90
91 w := os.Stdout
92 fmt.Fprintf(w, "/* Generated using: hugo %s */\n\n", strings.Join(os.Args[1:], " "))
93 formatter.WriteCSS(w, style)
94 return nil
95 },
96 withc: func(cmd *cobra.Command, r *rootCommand) {
97 cmd.ValidArgsFunction = cobra.NoFileCompletions
98 cmd.PersistentFlags().StringVar(&style, "style", "friendly", "highlighter style (see https://xyproto.github.io/splash/docs/)")
99 _ = cmd.RegisterFlagCompletionFunc("style", cobra.NoFileCompletions)
100 cmd.PersistentFlags().StringVar(&highlightStyle, "highlightStyle", "", `foreground and background colors for highlighted lines, e.g. --highlightStyle "#fff000 bg:#000fff"`)
101 _ = cmd.RegisterFlagCompletionFunc("highlightStyle", cobra.NoFileCompletions)
102 cmd.PersistentFlags().StringVar(&lineNumbersInlineStyle, "lineNumbersInlineStyle", "", `foreground and background colors for inline line numbers, e.g. --lineNumbersInlineStyle "#fff000 bg:#000fff"`)
103 _ = cmd.RegisterFlagCompletionFunc("lineNumbersInlineStyle", cobra.NoFileCompletions)
104 cmd.PersistentFlags().StringVar(&lineNumbersTableStyle, "lineNumbersTableStyle", "", `foreground and background colors for table line numbers, e.g. --lineNumbersTableStyle "#fff000 bg:#000fff"`)
105 _ = cmd.RegisterFlagCompletionFunc("lineNumbersTableStyle", cobra.NoFileCompletions)
106 cmd.PersistentFlags().BoolVar(&omitEmpty, "omitEmpty", false, `omit empty CSS rules`)
107 _ = cmd.RegisterFlagCompletionFunc("omitEmpty", cobra.NoFileCompletions)
108 },
109 }
110 }
111
112 newMan := func() simplecobra.Commander {
113 return &simpleCommand{
114 name: "man",
115 short: "Generate man pages for the Hugo CLI",
116 long: `This command automatically generates up-to-date man pages of Hugo's
117 command-line interface. By default, it creates the man page files
118 in the "man" directory under the current directory.`,
119
120 run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
121 header := &doc.GenManHeader{
122 Section: "1",
123 Manual: "Hugo Manual",
124 Source: fmt.Sprintf("Hugo %s", hugo.CurrentVersion),
125 }
126 if !strings.HasSuffix(genmandir, helpers.FilePathSeparator) {
127 genmandir += helpers.FilePathSeparator
128 }
129 if found, _ := helpers.Exists(genmandir, hugofs.Os); !found {
130 r.Println("Directory", genmandir, "does not exist, creating...")
131 if err := hugofs.Os.MkdirAll(genmandir, 0o777); err != nil {
132 return err
133 }
134 }
135 cd.CobraCommand.Root().DisableAutoGenTag = true
136
137 r.Println("Generating Hugo man pages in", genmandir, "...")
138 doc.GenManTree(cd.CobraCommand.Root(), header, genmandir)
139
140 r.Println("Done.")
141
142 return nil
143 },
144 withc: func(cmd *cobra.Command, r *rootCommand) {
145 cmd.ValidArgsFunction = cobra.NoFileCompletions
146 cmd.PersistentFlags().StringVar(&genmandir, "dir", "man/", "the directory to write the man pages.")
147 _ = cmd.MarkFlagDirname("dir")
148 },
149 }
150 }
151
152 newGen := func() simplecobra.Commander {
153 const gendocFrontmatterTemplate = `---
154 title: "%s"
155 slug: %s
156 url: %s
157 ---
158 `
159
160 return &simpleCommand{
161 name: "doc",
162 short: "Generate Markdown documentation for the Hugo CLI",
163 long: `Generate Markdown documentation for the Hugo CLI.
164 This command is, mostly, used to create up-to-date documentation
165 of Hugo's command-line interface for https://gohugo.io/.
166
167 It creates one Markdown file per command with front matter suitable
168 for rendering in Hugo.`,
169 run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
170 cd.CobraCommand.VisitParents(func(c *cobra.Command) {
171 // Disable the "Auto generated by spf13/cobra on DATE"
172 // as it creates a lot of diffs.
173 c.DisableAutoGenTag = true
174 })
175 if !strings.HasSuffix(gendocdir, helpers.FilePathSeparator) {
176 gendocdir += helpers.FilePathSeparator
177 }
178 if found, _ := helpers.Exists(gendocdir, hugofs.Os); !found {
179 r.Println("Directory", gendocdir, "does not exist, creating...")
180 if err := hugofs.Os.MkdirAll(gendocdir, 0o777); err != nil {
181 return err
182 }
183 }
184 prepender := func(filename string) string {
185 name := filepath.Base(filename)
186 base := strings.TrimSuffix(name, path.Ext(name))
187 url := "/docs/reference/commands/" + strings.ToLower(base) + "/"
188 return fmt.Sprintf(gendocFrontmatterTemplate, strings.Replace(base, "_", " ", -1), base, url)
189 }
190
191 linkHandler := func(name string) string {
192 base := strings.TrimSuffix(name, path.Ext(name))
193 return "/docs/reference/commands/" + strings.ToLower(base) + "/"
194 }
195 r.Println("Generating Hugo command-line documentation in", gendocdir, "...")
196 doc.GenMarkdownTreeCustom(cd.CobraCommand.Root(), gendocdir, prepender, linkHandler)
197 r.Println("Done.")
198
199 return nil
200 },
201 withc: func(cmd *cobra.Command, r *rootCommand) {
202 cmd.ValidArgsFunction = cobra.NoFileCompletions
203 cmd.PersistentFlags().StringVar(&gendocdir, "dir", "/tmp/hugodoc/", "the directory to write the doc.")
204 _ = cmd.MarkFlagDirname("dir")
205 },
206 }
207 }
208
209 var docsHelperTarget string
210
211 newDocsHelper := func() simplecobra.Commander {
212 return &simpleCommand{
213 name: "docshelper",
214 short: "Generate some data files for the Hugo docs",
215
216 run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
217 r.Println("Generate docs data to", docsHelperTarget)
218
219 var buf bytes.Buffer
220 jsonEnc := json.NewEncoder(&buf)
221
222 configProvider := func() docshelper.DocProvider {
223 conf := hugolib.DefaultConfig()
224 conf.CacheDir = "" // The default value does not make sense in the docs.
225 defaultConfig := parser.NullBoolJSONMarshaller{Wrapped: parser.LowerCaseCamelJSONMarshaller{Value: conf}}
226 return docshelper.DocProvider{"config": defaultConfig}
227 }
228
229 docshelper.AddDocProviderFunc(configProvider)
230 if err := jsonEnc.Encode(docshelper.GetDocProvider()); err != nil {
231 return err
232 }
233
234 // Decode the JSON to a map[string]interface{} and then unmarshal it again to the correct format.
235 var m map[string]any
236 if err := json.Unmarshal(buf.Bytes(), &m); err != nil {
237 return err
238 }
239
240 targetFile := filepath.Join(docsHelperTarget, "docs.yaml")
241
242 f, err := os.Create(targetFile)
243 if err != nil {
244 return err
245 }
246 defer f.Close()
247 yamlEnc := yaml.NewEncoder(f)
248 if err := yamlEnc.Encode(m); err != nil {
249 return err
250 }
251
252 r.Println("Done!")
253 return nil
254 },
255 withc: func(cmd *cobra.Command, r *rootCommand) {
256 cmd.Hidden = true
257 cmd.ValidArgsFunction = cobra.NoFileCompletions
258 cmd.PersistentFlags().StringVarP(&docsHelperTarget, "dir", "", "docs/data", "data dir")
259 },
260 }
261 }
262
263 return &genCommand{
264 commands: []simplecobra.Commander{
265 newChromaStyles(),
266 newGen(),
267 newMan(),
268 newDocsHelper(),
269 },
270 }
271 }
272
273 type genCommand struct {
274 rootCmd *rootCommand
275
276 commands []simplecobra.Commander
277 }
278
279 func (c *genCommand) Commands() []simplecobra.Commander {
280 return c.commands
281 }
282
283 func (c *genCommand) Name() string {
284 return "gen"
285 }
286
287 func (c *genCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args []string) error {
288 return nil
289 }
290
291 func (c *genCommand) Init(cd *simplecobra.Commandeer) error {
292 cmd := cd.CobraCommand
293 cmd.Short = "Generate documentation and syntax highlighting styles"
294 cmd.Long = "Generate documentation for your project using Hugo's documentation engine, including syntax highlighting for various programming languages."
295
296 cmd.RunE = nil
297 return nil
298 }
299
300 func (c *genCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
301 c.rootCmd = cd.Root.Command.(*rootCommand)
302 return nil
303 }