From 786fd4302aa351c5a534c06b08c39c0897fd35f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sun, 7 Feb 2021 18:08:46 +0100 Subject: [PATCH] markup/goldmark: Add attributes support for blocks (tables etc.) E.g.: ``` > foo > bar {.myclass} ``` There are some current limitations: For tables you can currently only apply it to the full table, and for lists the ul/ol-nodes only, e.g.: ``` * Fruit * Apple * Orange * Banana {.fruits} * Dairy * Milk * Cheese {.dairies} {.list} ``` Fixes #7548 --- .../getting-started/configuration-markup.md | 28 +++++ docs/data/docs.json | 15 ++- markup/goldmark/convert.go | 8 +- markup/goldmark/convert_test.go | 99 +++++++++++++++ markup/goldmark/goldmark_config/config.go | 14 ++- .../extensions/attributes/attributes.go | 119 ++++++++++++++++++ markup/markup_config/config.go | 17 ++- markup/markup_config/config_test.go | 13 ++ 8 files changed, 303 insertions(+), 10 deletions(-) create mode 100644 markup/goldmark/internal/extensions/attributes/attributes.go diff --git a/docs/content/en/getting-started/configuration-markup.md b/docs/content/en/getting-started/configuration-markup.md index ed5163dce6e..4c4d270a6f8 100644 --- a/docs/content/en/getting-started/configuration-markup.md +++ b/docs/content/en/getting-started/configuration-markup.md @@ -40,6 +40,34 @@ unsafe typographer : This extension substitutes punctuations with typographic entities like [smartypants](https://daringfireball.net/projects/smartypants/). +attribute +: Enable custom attribute support for titles and blocks by adding attribute lists inside single curly brackets (`{.myclass class="class1 class2" }`) and placing it _after the Markdown element it decorates_, on the same line for titles and on a new line directly below for blocks. + +{{< new-in "0.81" >}} In Hugo 0.81.0 we added support for adding attributes (e.g. CSS classes) to Markdown blocks, e.g. tables, lists, paragraphs etc. + +A blockquote with a CSS class: + +```md +> foo +> bar +{.myclass} +``` + +There are some current limitations: For tables you can currently only apply it to the full table, and for lists the `ul`/`ol`-nodes only, e.g.: + +```md +* Fruit + * Apple + * Orange + * Banana + {.fruits} +* Dairy + * Milk + * Cheese + {.dairies} +{.list} +``` + autoHeadingIDType ("github") {{< new-in "0.62.2" >}} : The strategy used for creating auto IDs (anchor names). Available types are `github`, `github-ascii` and `blackfriday`. `github` produces GitHub-compatible IDs, `github-ascii` will drop any non-Ascii characters after accent normalization, and `blackfriday` will make the IDs work as with [Blackfriday](#blackfriday), the default Markdown engine before Hugo 0.60. Note that if Goldmark is your default Markdown engine, this is also the strategy used in the [anchorize](/functions/anchorize/) template func. diff --git a/docs/data/docs.json b/docs/data/docs.json index 70aee718ed2..8e4b1f95bb9 100644 --- a/docs/data/docs.json +++ b/docs/data/docs.json @@ -1509,7 +1509,10 @@ "parser": { "autoHeadingID": true, "autoHeadingIDType": "github", - "attribute": true + "attribute": { + "title": true, + "block": false + } }, "extensions": { "typographer": true, @@ -3023,7 +3026,7 @@ "Examples": [] }, "Merge": { - "Description": "Merge creates a copy of the final parameter and merges the preceeding\nparameters into it in reverse order.\nCurrently only maps are supported. Key handling is case insensitive.", + "Description": "Merge creates a copy of the final parameter and merges the preceding\nparameters into it in reverse order.\nCurrently only maps are supported. Key handling is case insensitive.", "Args": [ "params" ], @@ -3526,6 +3529,12 @@ "Aliases": null, "Examples": null }, + "Overlay": { + "Description": "", + "Args": null, + "Aliases": null, + "Examples": null + }, "Pixelate": { "Description": "", "Args": null, @@ -4371,7 +4380,7 @@ ] }, "CountRunes": { - "Description": "CountRunes returns the number of runes in s, excluding whitepace.", + "Description": "CountRunes returns the number of runes in s, excluding whitespace.", "Args": [ "s" ], diff --git a/markup/goldmark/convert.go b/markup/goldmark/convert.go index 50e7bcb8a71..629e2b15a18 100644 --- a/markup/goldmark/convert.go +++ b/markup/goldmark/convert.go @@ -21,6 +21,8 @@ import ( "path/filepath" "runtime/debug" + "github.com/gohugoio/hugo/markup/goldmark/internal/extensions/attributes" + "github.com/gohugoio/hugo/identity" "github.com/pkg/errors" @@ -137,10 +139,14 @@ func newMarkdown(pcfg converter.ProviderConfig) goldmark.Markdown { parserOptions = append(parserOptions, parser.WithAutoHeadingID()) } - if cfg.Parser.Attribute { + if cfg.Parser.Attribute.Title { parserOptions = append(parserOptions, parser.WithAttribute()) } + if cfg.Parser.Attribute.Block { + extensions = append(extensions, attributes.New()) + } + md := goldmark.New( goldmark.WithExtensions( extensions..., diff --git a/markup/goldmark/convert_test.go b/markup/goldmark/convert_test.go index f105afdc424..d35d4d1fd42 100644 --- a/markup/goldmark/convert_test.go +++ b/markup/goldmark/convert_test.go @@ -17,6 +17,8 @@ import ( "strings" "testing" + "github.com/spf13/cast" + "github.com/gohugoio/hugo/markup/goldmark/goldmark_config" "github.com/gohugoio/hugo/markup/highlight" @@ -193,6 +195,103 @@ func TestConvertAutoIDBlackfriday(t *testing.T) { c.Assert(got, qt.Contains, "

") } +func TestConvertAttributes(t *testing.T) { + c := qt.New(t) + + withBlockAttributes := func(conf *markup_config.Config) { + conf.Goldmark.Parser.Attribute.Block = true + conf.Goldmark.Parser.Attribute.Title = false + } + + withTitleAndBlockAttributes := func(conf *markup_config.Config) { + conf.Goldmark.Parser.Attribute.Block = true + conf.Goldmark.Parser.Attribute.Title = true + } + + for _, test := range []struct { + name string + withConfig func(conf *markup_config.Config) + input string + expect interface{} + }{ + { + "Title", + nil, + "## heading {#id .className attrName=attrValue class=\"class1 class2\"}", + "

heading

\n", + }, + { + "Blockquote", + withBlockAttributes, + "> foo\n> bar\n{#id .className attrName=attrValue class=\"class1 class2\"}\n", + "

foo\nbar

\n
\n", + }, + { + "Paragraph", + withBlockAttributes, + "\nHi there.\n{.myclass }", + "

Hi there.

\n", + }, + { + "Ordered list", + withBlockAttributes, + "\n1. First\n2. Second\n{.myclass }", + "
    \n
  1. First
  2. \n
  3. Second
  4. \n
\n", + }, + { + "Unordered list", + withBlockAttributes, + "\n* First\n* Second\n{.myclass }", + "\n", + }, + { + "Unordered list, indented", + withBlockAttributes, + `* Fruit + * Apple + * Orange + * Banana + {.fruits} +* Dairy + * Milk + * Cheese + {.dairies} +{.list}`, + []string{"