Skip to content

Commit

Permalink
markup/highlight: Add hl_inline option
Browse files Browse the repository at this point in the history
Closes #9442
Closes #9635
Closes #9638
  • Loading branch information
bep committed Jun 15, 2022
1 parent 580b214 commit d863dde
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 14 deletions.
4 changes: 4 additions & 0 deletions markup/highlight/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ type Config struct {
// A space separated list of line numbers, e.g. “3-8 10-20”.
Hl_Lines string

// If set, the markup will not be wrapped in any container.
Hl_inline bool

// A parsed and ready to use list of line ranges.
HL_lines_parsed [][2]int `json:"-"`

Expand All @@ -93,6 +96,7 @@ func (cfg Config) ToHTMLOptions() []html.Option {
html.LineNumbersInTable(cfg.LineNumbersInTable),
html.WithClasses(!cfg.NoClasses),
html.LinkableLineNumbers(cfg.AnchorLineNos, lineAnchors),
html.InlineCode(cfg.Hl_inline),
}

if cfg.Hl_Lines != "" || cfg.HL_lines_parsed != nil {
Expand Down
87 changes: 73 additions & 14 deletions markup/highlight/highlight.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func (h chromaHighlighter) HighlightCodeBlock(ctx hooks.CodeblockContext, opts a
var b strings.Builder

attributes := ctx.(hooks.AttributesOptionsSliceProvider).AttributesSlice()

options := ctx.Options()

if err := applyOptionsFromMap(options, &cfg); err != nil {
Expand All @@ -108,15 +109,21 @@ func (h chromaHighlighter) HighlightCodeBlock(ctx hooks.CodeblockContext, opts a
return HightlightResult{}, err
}

highlighted := b.String()
if high == 0 {
high = len(highlighted)
}

return HightlightResult{
highlighted: template.HTML(b.String()),
highlighted: template.HTML(highlighted),
innerLow: low,
innerHigh: high,
}, nil
}

func (h chromaHighlighter) RenderCodeblock(w hugio.FlexiWriter, ctx hooks.CodeblockContext) error {
cfg := h.cfg

attributes := ctx.(hooks.AttributesOptionsSliceProvider).AttributesSlice()

if err := applyOptionsFromMap(ctx.Options(), &cfg); err != nil {
Expand Down Expand Up @@ -158,8 +165,6 @@ func (h HightlightResult) Inner() template.HTML {
}

func highlight(fw hugio.FlexiWriter, code, lang string, attributes []attributes.Attribute, cfg Config) (int, int, error) {
var low, high int

var lexer chroma.Lexer
if lang != "" {
lexer = lexers.Get(lang)
Expand All @@ -176,11 +181,15 @@ func highlight(fw hugio.FlexiWriter, code, lang string, attributes []attributes.
w := &byteCountFlexiWriter{delegate: fw}

if lexer == nil {
wrapper := getPreWrapper(lang, w)
fmt.Fprint(w, wrapper.Start(true, ""))
fmt.Fprint(w, gohtml.EscapeString(code))
fmt.Fprint(w, wrapper.End(true))
return low, high, nil
if cfg.Hl_inline {
fmt.Fprint(w, fmt.Sprintf("<code%s>%s</code>", inlineCodeAttrs(lang), gohtml.EscapeString(code)))
} else {
preWrapper := getPreWrapper(lang, w)
fmt.Fprint(w, preWrapper.Start(true, ""))
fmt.Fprint(w, gohtml.EscapeString(code))
fmt.Fprint(w, preWrapper.End(true))
}
return 0, 0, nil
}

style := styles.Get(cfg.Style)
Expand All @@ -194,20 +203,51 @@ func highlight(fw hugio.FlexiWriter, code, lang string, attributes []attributes.
return 0, 0, err
}

if !cfg.Hl_inline {
writeDivStart(w, attributes)
}

options := cfg.ToHTMLOptions()
preWrapper := getPreWrapper(lang, w)
options = append(options, html.WithPreWrapper(preWrapper))
var wrapper html.PreWrapper

if cfg.Hl_inline {
wrapper = startEnd{
start: func(code bool, styleAttr string) string {
if code {
return fmt.Sprintf(`<code%s>`, inlineCodeAttrs(lang))
}
return ``
},
end: func(code bool) string {
if code {
return `</code>`
}

return ``
},
}

formatter := html.New(options...)
} else {
wrapper = getPreWrapper(lang, w)
}

options = append(options, html.WithPreWrapper(wrapper))

writeDivStart(w, attributes)
formatter := html.New(options...)

if err := formatter.Format(w, style, iterator); err != nil {
return 0, 0, err
}
writeDivEnd(w)

return preWrapper.low, preWrapper.high, nil
if !cfg.Hl_inline {
writeDivEnd(w)
}

if p, ok := wrapper.(*preWrapper); ok {
return p.low, p.high, nil
}

return 0, 0, nil
}

func getPreWrapper(language string, writeCounter *byteCountFlexiWriter) *preWrapper {
Expand All @@ -232,6 +272,12 @@ func (p *preWrapper) Start(code bool, styleAttr string) string {
return w.String()
}

func inlineCodeAttrs(lang string) string {
if lang == "" {
}
return fmt.Sprintf(` class="code-inline language-%s"`, lang)
}

func WritePreStart(w io.Writer, language, styleAttr string) {
fmt.Fprintf(w, `<pre tabindex="0"%s>`, styleAttr)
fmt.Fprint(w, "<code")
Expand All @@ -249,6 +295,19 @@ func (p *preWrapper) End(code bool) string {
return preEnd
}

type startEnd struct {
start func(code bool, styleAttr string) string
end func(code bool) string
}

func (s startEnd) Start(code bool, styleAttr string) string {
return s.start(code, styleAttr)
}

func (s startEnd) End(code bool) string {
return s.end(code)
}

func WritePreEnd(w io.Writer) {
fmt.Fprint(w, preEnd)
}
Expand Down
85 changes: 85 additions & 0 deletions markup/highlight/integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2022 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package highlight_test

import (
"testing"

"github.com/gohugoio/hugo/hugolib"
)

func TestHighlightInline(t *testing.T) {
t.Parallel()

files := `
-- config.toml --
[markup]
[markup.highlight]
codeFences = true
noClasses = false
-- content/p1.md --
---
title: "p1"
---
## Inline in Shortcode
Inline:{{< highlight emacs "hl_inline=true" >}}(message "this highlight shortcode"){{< /highlight >}}:End.
Inline Unknown:{{< highlight foo "hl_inline=true" >}}(message "this highlight shortcode"){{< /highlight >}}:End.
## Inline in code block
Not sure if this makes sense, but add a test for it:
§§§bash {hl_inline=true}
(message "highlight me")
§§§
## HighlightCodeBlock in hook
§§§html
(message "highlight me 2")
§§§
## Unknown lexer
§§§foo {hl_inline=true}
(message "highlight me 3")
§§§
-- layouts/_default/_markup/render-codeblock-html.html --
{{ $opts := dict "hl_inline" true }}
{{ $result := transform.HighlightCodeBlock . $opts }}
HighlightCodeBlock: Wrapped:{{ $result.Wrapped }}|Inner:{{ $result.Inner }}
-- layouts/_default/single.html --
{{ .Content }}
`

b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
NeedsOsFS: false,
},
).Build()

b.AssertFileContent("public/p1/index.html",
"Inline:<code class=\"code-inline language-emacs\"><span class=\"p\">(</span><span class=\"nf\">message</span> <span class=\"s\">&#34;this highlight shortcode&#34;</span><span class=\"p\">)</span></code>:End.",
"Inline Unknown:<code class=\"code-inline language-foo\">(message &#34;this highlight shortcode&#34;)</code>:End.",
"Not sure if this makes sense, but add a test for it:</p>\n<code class=\"code-inline language-bash\"><span class=\"o\">(</span>message <span class=\"s2\">&#34;highlight me&#34;</span><span class=\"o\">)</span>\n</code>",
"HighlightCodeBlock: Wrapped:<code class=\"code-inline language-html\">(message &#34;highlight me 2&#34;)</code>|Inner:<code class=\"code-inline language-html\">(message &#34;highlight me 2&#34;)</code>",
"<code class=\"code-inline language-foo\">(message &#34;highlight me 3&#34;)\n</code>",
)
}
1 change: 1 addition & 0 deletions markup/internal/attributes/attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var chromaHightlightProcessingAttributes = map[string]bool{
"anchorLineNos": true,
"guessSyntax": true,
"hl_Lines": true,
"hl_inline": true,
"lineAnchors": true,
"lineNos": true,
"lineNoStart": true,
Expand Down

0 comments on commit d863dde

Please sign in to comment.