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 }