Add support for configurable extensions via -e/--extensions and configuration file

This commit is contained in:
James Mills 2023-03-26 12:23:23 +10:00
parent d889349f2c
commit 40d6f8312a
No known key found for this signature in database
GPG Key ID: AC4C014F1440EBD6
2 changed files with 65 additions and 34 deletions

View File

@ -3,6 +3,7 @@
"abhg", "abhg",
"alecthomas", "alecthomas",
"chromahtml", "chromahtml",
"definitionlist",
"errbuf", "errbuf",
"Furqan", "Furqan",
"goldmark", "goldmark",
@ -15,6 +16,7 @@
"sirupsen", "sirupsen",
"stefanfritsch", "stefanfritsch",
"Strikethrough", "Strikethrough",
"tasklist",
"wikilink", "wikilink",
"yuin", "yuin",
"ZSCONFIG", "ZSCONFIG",

97
main.go
View File

@ -64,8 +64,12 @@ README.md`
// Ignore holds a set of patterns to ignore from parsing a .zsignore file // Ignore holds a set of patterns to ignore from parsing a .zsignore file
var Ignore *ignore.GitIgnore var Ignore *ignore.GitIgnore
// Parser holds a configured global instance of the goldmark markdown parser
var Parser goldmark.Markdown
var ( var (
configFile string configFile string
enabledExtensions []string
// Title site title // Title site title
Title string Title string
@ -80,9 +84,43 @@ var (
Production = false Production = false
) )
// Extensions is a mapping of name to extension and the default set of extensions enabled
// which can be overridden with -e/--extension or the extensions key
// in ia config file such as .zs/config.yml
var Extensions = map[string]goldmark.Extender{
"table": extension.Table,
"strikethrough": extension.Strikethrough,
"linkify": extension.Linkify,
"tasklist": extension.TaskList,
"definitionlist": extension.DefinitionList,
"footnote": extension.Footnote,
"typography": extension.Typographer,
"cjk": extension.CJK,
"highlighting": highlighting.NewHighlighting(
highlighting.WithStyle("github"),
highlighting.WithFormatOptions(
chromahtml.WithLineNumbers(true),
),
),
"anchor": &anchor.Extender{},
"d2": &d2.Extender{},
"embed": embed.New(),
"fences": &fences.Extender{},
"wikilink": &wikilink.Extender{},
}
// Vars holds a map of global variables // Vars holds a map of global variables
type Vars map[string]string type Vars map[string]string
// MapKeys returns a slice of keys from a map
func MapKeys[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
// NewTicker is a function that wraps a time.Ticker and ticks immediately instead of waiting for the first interval // NewTicker is a function that wraps a time.Ticker and ticks immediately instead of waiting for the first interval
func NewTicker(d time.Duration) *time.Ticker { func NewTicker(d time.Duration) *time.Ticker {
ticker := time.NewTicker(d) ticker := time.NewTicker(d)
@ -124,6 +162,28 @@ var RootCmd = &cobra.Command{
log.SetLevel(log.InfoLevel) log.SetLevel(log.InfoLevel)
} }
var extensions []goldmark.Extender
for _, name := range enabledExtensions {
if extender, valid := Extensions[name]; valid {
extensions = append(extensions, extender)
} else {
log.Warnf("invalid extension: %s", name)
}
}
Parser = goldmark.New(
goldmark.WithExtensions(extensions...),
goldmark.WithParserOptions(
parser.WithAttribute(),
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
html.WithHardWraps(),
html.WithXHTML(),
html.WithUnsafe(),
),
)
return nil return nil
}, },
} }
@ -425,39 +485,7 @@ func buildMarkdown(path string, w io.Writer, vars Vars) error {
} }
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
gm := goldmark.New( if err := Parser.Convert([]byte(content), buf); err != nil {
goldmark.WithExtensions(
extension.Table,
extension.Strikethrough,
extension.Linkify,
extension.TaskList,
extension.DefinitionList,
extension.Footnote,
extension.Typographer,
extension.CJK,
highlighting.NewHighlighting(
highlighting.WithStyle("github"),
highlighting.WithFormatOptions(
chromahtml.WithLineNumbers(true),
),
),
&anchor.Extender{},
&d2.Extender{},
embed.New(),
&fences.Extender{},
&wikilink.Extender{},
),
goldmark.WithParserOptions(
parser.WithAttribute(),
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
html.WithHardWraps(),
html.WithXHTML(),
html.WithUnsafe(),
),
)
if err := gm.Convert([]byte(content), buf); err != nil {
return err return err
} }
v["content"] = buf.String() v["content"] = buf.String()
@ -638,6 +666,7 @@ func init() {
RootCmd.PersistentFlags().BoolP("debug", "D", false, "enable debug logging $($ZS_DEBUG)") RootCmd.PersistentFlags().BoolP("debug", "D", false, "enable debug logging $($ZS_DEBUG)")
RootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "config file (default: .zs/config.yml)") RootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "config file (default: .zs/config.yml)")
RootCmd.PersistentFlags().StringSliceVarP(&enabledExtensions, "extensions", "e", MapKeys(Extensions), "override and enable specific extensions")
RootCmd.PersistentFlags().BoolVarP(&Production, "production", "p", false, "enable production mode ($ZS_PRODUCTION)") RootCmd.PersistentFlags().BoolVarP(&Production, "production", "p", false, "enable production mode ($ZS_PRODUCTION)")
RootCmd.PersistentFlags().StringVarP(&Title, "title", "t", "", "site title ($ZS_TITLE)") RootCmd.PersistentFlags().StringVarP(&Title, "title", "t", "", "site title ($ZS_TITLE)")
RootCmd.PersistentFlags().StringVarP(&Description, "description", "d", "", "site description ($ZS_DESCRIPTION)") RootCmd.PersistentFlags().StringVarP(&Description, "description", "d", "", "site description ($ZS_DESCRIPTION)")