From 3158a512835bc6a417f9b253a772ab921d26583d Mon Sep 17 00:00:00 2001 From: Joe Mooring Date: Tue, 22 Apr 2025 19:42:04 -0700 Subject: [PATCH] markup/highlight: Allow lineNos to be true, false, "inline", or "table" Closes #13481 --- markup/highlight/config.go | 40 ++++++++-- markup/highlight/highlight.go | 6 +- .../highlight/highlight_integration_test.go | 73 +++++++++++++++++++ 3 files changed, 112 insertions(+), 7 deletions(-) diff --git a/markup/highlight/config.go b/markup/highlight/config.go index fff9bfeca..6407cdff6 100644 --- a/markup/highlight/config.go +++ b/markup/highlight/config.go @@ -60,7 +60,7 @@ type Config struct { NoClasses bool // When set, line numbers will be printed. - LineNos bool + LineNos any LineNumbersInTable bool // When set, add links to line numbers @@ -85,16 +85,44 @@ type Config struct { GuessSyntax bool } -func (cfg Config) toHTMLOptions() []html.Option { - var lineAnchors string +const errLineNosMsg = `lineNos must be one of true, false, "inline", or "table"; got %[1]v (%[1]T)` + +func (cfg Config) toHTMLOptions() ([]html.Option, error) { + var ( + lineAnchors string + lineNos bool + inTable = cfg.LineNumbersInTable + ) + if cfg.LineAnchors != "" { lineAnchors = cfg.LineAnchors + "-" } + + switch v := cfg.LineNos.(type) { + case string: + switch v { + case "inline": + lineNos = true + inTable = false + case "table": + lineNos = true + inTable = true + default: + return nil, fmt.Errorf(errLineNosMsg, v) + } + case bool: + lineNos = v + case nil: + lineNos = false + default: + return nil, fmt.Errorf(errLineNosMsg, v) + } + options := []html.Option{ html.TabWidth(cfg.TabWidth), - html.WithLineNumbers(cfg.LineNos), + html.WithLineNumbers(lineNos), html.BaseLineNumber(cfg.LineNoStart), - html.LineNumbersInTable(cfg.LineNumbersInTable), + html.LineNumbersInTable(inTable), html.WithClasses(!cfg.NoClasses), html.WithLinkableLineNumbers(cfg.AnchorLineNos, lineAnchors), html.InlineCode(cfg.Hl_inline), @@ -117,7 +145,7 @@ func (cfg Config) toHTMLOptions() []html.Option { } } - return options + return options, nil } func applyOptions(opts any, cfg *Config) error { diff --git a/markup/highlight/highlight.go b/markup/highlight/highlight.go index ee07fb9ad..8fe304254 100644 --- a/markup/highlight/highlight.go +++ b/markup/highlight/highlight.go @@ -205,7 +205,11 @@ func highlight(fw hugio.FlexiWriter, code, lang string, attributes []attributes. writeDivStart(w, attributes, cfg.WrapperClass) } - options := cfg.toHTMLOptions() + options, err := cfg.toHTMLOptions() + if err != nil { + return 0, 0, err + } + var wrapper html.PreWrapper if cfg.Hl_inline { diff --git a/markup/highlight/highlight_integration_test.go b/markup/highlight/highlight_integration_test.go index a737d9a6a..19779fd2f 100644 --- a/markup/highlight/highlight_integration_test.go +++ b/markup/highlight/highlight_integration_test.go @@ -14,8 +14,10 @@ package highlight_test import ( + "strings" "testing" + qt "github.com/frankban/quicktest" "github.com/gohugoio/hugo/hugolib" ) @@ -129,3 +131,74 @@ xəx := 0
aaa`,
+		`! `,
+		`! 42`,
+	)
+
+	f := strings.ReplaceAll(files, "#LINENOS", `linenos = false`)
+	b = hugolib.Test(t, f)
+	b.AssertFileContent("public/index.html",
+		`aaa`,
+		`! 
`, + `! 42`, + ) + + f = strings.ReplaceAll(files, "#LINENOS", `linenos = true`) + b = hugolib.Test(t, f) + b.AssertFileContent("public/index.html", + `aaa`, + `
`, + `42`, + ) + + f = strings.ReplaceAll(files, "#LINENOS", `linenos = "table"`) + b = hugolib.Test(t, f) + b.AssertFileContent("public/index.html", + `aaa`, + `
`, + `42`, + ) + + f = strings.ReplaceAll(files, "#LINENOS", `linenos = "inline"`) + b = hugolib.Test(t, f) + b.AssertFileContent("public/index.html", + `aaa`, + `!
`, + `42`, + ) + + want := `.* lineNos must be one of .*` + + f = strings.ReplaceAll(files, "#LINENOS", `linenos = "foo"`) + b, err := hugolib.TestE(t, f) + b.Assert(err, qt.ErrorMatches, want) + + f = strings.ReplaceAll(files, "#LINENOS", `linenos = 123`) + b, err = hugolib.TestE(t, f) + b.Assert(err, qt.ErrorMatches, want) +} -- 2.39.5