Repository: gohugoio/hugo (language: go)

Issue:
Improve Ordinal usage with lineAnchors in codeblock render hooks
Related to using the .Ordinal in the lineAnchors value when anchorLineNos is true...

1. Is this supposed to happen automatically? If so, under what conditions? I can't make it happen.
2. I see [this code](https://github.com/gohugoio/hugo/blob/master/markup/highlight/highlight.go#L153-L156), but I don't think the containing function is ever called.
3. Although an HTML5 id attribute may begin with a number, to be compatible with CSS/JS selectors it should not begin with a number (see https://github.com/gohugoio/hugo/issues/8997). Perhaps we can prepend the .Ordinal with hugo-hl- or hl-.


Discussion / hints:
You are right, the `Ordinal` is there and ready to use, but it's not in use in the default codeblock renderer, but it should. And you are right, we should prepend something.

Fix patch:
diff --git a/markup/highlight/config.go b/markup/highlight/config.go
index 86ac02c3d99..7b336f580bf 100644
--- a/markup/highlight/config.go
+++ b/markup/highlight/config.go
@@ -23,10 +23,19 @@ import (
 	"github.com/spf13/cast"
 
 	"github.com/gohugoio/hugo/config"
+	"github.com/gohugoio/hugo/markup/converter/hooks"
 
 	"github.com/mitchellh/mapstructure"
 )
 
+const (
+	lineanchorsKey = "lineanchors"
+	lineNosKey     = "linenos"
+	hlLinesKey     = "hl_lines"
+	linosStartKey  = "linenostart"
+	noHlKey        = "nohl"
+)
+
 var DefaultConfig = Config{
 	// The highlighter style to use.
 	// See https://xyproto.github.io/splash/docs/all.html
@@ -38,7 +47,6 @@ var DefaultConfig = Config{
 	TabWidth:           4,
 }
 
-//
 type Config struct {
 	Style string
 
@@ -133,6 +141,16 @@ func applyOptionsFromMap(optsm map[string]interface{}, cfg *Config) error {
 	return mapstructure.WeakDecode(optsm, cfg)
 }
 
+func applyOptionsFromCodeBlockContext(ctx hooks.CodeblockContext, cfg *Config) error {
+	if cfg.LineAnchors == "" {
+		const lineAnchorPrefix = "hl-"
+		// Set it to the ordinal with a prefix.
+		cfg.LineAnchors = fmt.Sprintf("%s%d", lineAnchorPrefix, ctx.Ordinal())
+	}
+
+	return nil
+}
+
 // ApplyLegacyConfig applies legacy config from back when we had
 // Pygments.
 func ApplyLegacyConfig(cfg config.Provider, conf *Config) error {
@@ -191,13 +209,6 @@ func normalizeHighlightOptions(m map[string]interface{}) {
 		return
 	}
 
-	const (
-		lineNosKey    = "linenos"
-		hlLinesKey    = "hl_lines"
-		linosStartKey = "linenostart"
-		noHlKey       = "nohl"
-	)
-
 	baseLineNumber := 1
 	if v, ok := m[linosStartKey]; ok {
 		baseLineNumber = cast.ToInt(v)
diff --git a/markup/highlight/highlight.go b/markup/highlight/highlight.go
index e9cbeb3c991..6013ba1c8b1 100644
--- a/markup/highlight/highlight.go
+++ b/markup/highlight/highlight.go
@@ -18,7 +18,6 @@ import (
 	gohtml "html"
 	"html/template"
 	"io"
-	"strconv"
 	"strings"
 
 	"github.com/alecthomas/chroma"
@@ -98,6 +97,10 @@ func (h chromaHighlighter) HighlightCodeBlock(ctx hooks.CodeblockContext, opts i
 		return HightlightResult{}, err
 	}
 
+	if err := applyOptionsFromCodeBlockContext(ctx, &cfg); err != nil {
+		return HightlightResult{}, err
+	}
+
 	err := highlight(&b, ctx.Code(), ctx.Lang(), attributes, cfg)
 	if err != nil {
 		return HightlightResult{}, err
@@ -116,6 +119,10 @@ func (h chromaHighlighter) RenderCodeblock(w hugio.FlexiWriter, ctx hooks.Codebl
 		return err
 	}
 
+	if err := applyOptionsFromCodeBlockContext(ctx, &cfg); err != nil {
+		return err
+	}
+
 	return highlight(w, ctx.Code(), ctx.Lang(), attributes, cfg)
 }
 
@@ -133,31 +140,6 @@ func (h HightlightResult) Highlighted() template.HTML {
 	return h.Body
 }
 
-func (h chromaHighlighter) toHighlightOptionsAttributes(ctx hooks.CodeblockContext) (map[string]interface{}, map[string]interface{}) {
-	attributes := ctx.Attributes()
-	if attributes == nil || len(attributes) == 0 {
-		return nil, nil
-	}
-
-	options := make(map[string]interface{})
-	attrs := make(map[string]interface{})
-
-	for k, v := range attributes {
-		klow := strings.ToLower(k)
-		if chromaHightlightProcessingAttributes[klow] {
-			options[klow] = v
-		} else {
-			attrs[k] = v
-		}
-	}
-	const lineanchorsKey = "lineanchors"
-	if _, found := options[lineanchorsKey]; !found {
-		// Set it to the ordinal.
-		options[lineanchorsKey] = strconv.Itoa(ctx.Ordinal())
-	}
-	return options, attrs
-}
-
 func highlight(w hugio.FlexiWriter, code, lang string, attributes []attributes.Attribute, cfg Config) error {
 	var lexer chroma.Lexer
 	if lang != "" {


Test patch:
diff --git a/markup/goldmark/convert_test.go b/markup/goldmark/convert_test.go
index 2227d6187cb..83d97f222b4 100644
--- a/markup/goldmark/convert_test.go
+++ b/markup/goldmark/convert_test.go
@@ -288,6 +288,20 @@ func TestConvertAttributes(t *testing.T) {
 			"```bash {linenos=table, anchorlinenos=true, lineanchors=org-coderef--xyz}\necho 'foo';\n```",
 			"<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\" id=\"org-coderef--xyz-1\"><a style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--xyz-1\">1</a>\n</span></code></pre></td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\"><span class=\"nb\">echo</span> <span class=\"s1\">&#39;foo&#39;</span><span class=\"p\">;</span>\n</span></span></code></pre></td></tr></table>\n</div>\n</div>",
 		},
+		{
+			"Code block, CodeFences=true,lineanchors, default ordinal",
+			func(conf *markup_config.Config) {
+				withBlockAttributes(conf)
+				conf.Highlight.CodeFences = true
+				conf.Highlight.NoClasses = false
+			},
+			"```bash {linenos=inline, anchorlinenos=true}\necho 'foo';\nnecho 'bar';\n```\n\n```bash {linenos=inline, anchorlinenos=true}\necho 'baz';\nnecho 'qux';\n```",
+			[]string{
+				"<span class=\"ln\" id=\"hl-0-1\"><a style=\"outline: none; text-decoration:none; color:inherit\" href=\"#hl-0-1\">1</a></span><span class=\"cl\"><span class=\"nb\">echo</span> <span class=\"s1\">&#39;foo&#39;</span>",
+				"<span class=\"ln\" id=\"hl-0-2\"><a style=\"outline: none; text-decoration:none; color:inherit\" href=\"#hl-0-2\">2</a></span><span class=\"cl\">necho <span class=\"s1\">&#39;bar&#39;</span>",
+				"<span class=\"ln\" id=\"hl-1-2\"><a style=\"outline: none; text-decoration:none; color:inherit\" href=\"#hl-1-2\">2</a></span><span class=\"cl\">necho <span class=\"s1\">&#39;qux&#39;</span>",
+			},
+		},
 		{
 			"Paragraph",
 			withBlockAttributes,