URI: 
       markup/highlight: Rework the return value from HighlightCodeblock - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 3ad39001df84c01a5da8ec7e008ee3835e1a7c4e
   DIR parent 39261b689e47116de5cfd3bee6b6e3af57deb97c
  HTML Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Sun, 27 Feb 2022 17:57:28 +0100
       
       markup/highlight: Rework the return value from HighlightCodeblock
       
       To make it possible to render it with a custom HTML ("<div>")  wrapper.
       
       Updates #9573
       
       Diffstat:
         M markup/goldmark/codeblocks/integra… |      51 +++++++++++++++++++++++++++++++
         M markup/highlight/highlight.go       |      90 +++++++++++++++++++++++--------
       
       2 files changed, 118 insertions(+), 23 deletions(-)
       ---
   DIR diff --git a/markup/goldmark/codeblocks/integration_test.go b/markup/goldmark/codeblocks/integration_test.go
       @@ -113,6 +113,57 @@ Go Language: golang|
                )
        }
        
       +func TestHighlightCodeblock(t *testing.T) {
       +        t.Parallel()
       +
       +        files := `
       +-- config.toml --
       +[markup]
       +[markup.highlight]
       +anchorLineNos = false
       +codeFences = true
       +guessSyntax = false
       +hl_Lines = ''
       +lineAnchors = ''
       +lineNoStart = 1
       +lineNos = false
       +lineNumbersInTable = true
       +noClasses = false
       +style = 'monokai'
       +tabWidth = 4
       +-- layouts/_default/_markup/render-codeblock.html --
       +{{ $result := transform.HighlightCodeBlock . }}
       +Inner: |{{ $result.Inner | safeHTML }}|
       +Wrapped: |{{ $result.Wrapped | safeHTML }}|
       +-- layouts/_default/single.html --
       +{{ .Content }}
       +-- content/p1.md --
       +---
       +title: "p1"
       +---
       +
       +## Go Code
       +
       +§§§go
       +fmt.Println("Hello, World!");
       +§§§
       +
       +`
       +
       +        b := hugolib.NewIntegrationTestBuilder(
       +                hugolib.IntegrationTestConfig{
       +                        T:           t,
       +                        TxtarString: files,
       +                        NeedsOsFS:   false,
       +                },
       +        ).Build()
       +
       +        b.AssertFileContent("public/p1/index.html",
       +                "Inner: |<span class=\"line\"><span class=\"cl\"><span class=\"nx\">fmt</span><span class=\"p\">.</span><span class=\"nf\">Println</span><span class=\"p\">(</span><span class=\"s\">&#34;Hello, World!&#34;</span><span class=\"p\">);</span></span></span>|",
       +                "Wrapped: |<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-go\" data-lang=\"go\"><span class=\"line\"><span class=\"cl\"><span class=\"nx\">fmt</span><span class=\"p\">.</span><span class=\"nf\">Println</span><span class=\"p\">(</span><span class=\"s\">&#34;Hello, World!&#34;</span><span class=\"p\">);</span></span></span></code></pre></div>|",
       +        )
       +}
       +
        func TestCodeChomp(t *testing.T) {
                t.Parallel()
        
   DIR diff --git a/markup/highlight/highlight.go b/markup/highlight/highlight.go
       @@ -75,7 +75,7 @@ func (h chromaHighlighter) Highlight(code, lang string, opts interface{}) (strin
                }
                var b strings.Builder
        
       -        if err := highlight(&b, code, lang, nil, cfg); err != nil {
       +        if _, _, err := highlight(&b, code, lang, nil, cfg); err != nil {
                        return "", err
                }
        
       @@ -103,13 +103,15 @@ func (h chromaHighlighter) HighlightCodeBlock(ctx hooks.CodeblockContext, opts i
                        return HightlightResult{}, err
                }
        
       -        err := highlight(&b, ctx.Inner(), ctx.Type(), attributes, cfg)
       +        low, high, err := highlight(&b, ctx.Inner(), ctx.Type(), attributes, cfg)
                if err != nil {
                        return HightlightResult{}, err
                }
        
                return HightlightResult{
       -                Body: template.HTML(b.String()),
       +                highlighted: template.HTML(b.String()),
       +                innerLow:    low,
       +                innerHigh:   high,
                }, nil
        }
        
       @@ -127,7 +129,8 @@ func (h chromaHighlighter) RenderCodeblock(w hugio.FlexiWriter, ctx hooks.Codebl
        
                code := text.Puts(ctx.Inner())
        
       -        return highlight(w, code, ctx.Type(), attributes, cfg)
       +        _, _, err := highlight(w, code, ctx.Type(), attributes, cfg)
       +        return err
        }
        
        func (h chromaHighlighter) IsDefaultCodeBlockRenderer() bool {
       @@ -141,14 +144,22 @@ func (h chromaHighlighter) GetIdentity() identity.Identity {
        }
        
        type HightlightResult struct {
       -        Body template.HTML
       +        innerLow    int
       +        innerHigh   int
       +        highlighted template.HTML
        }
        
       -func (h HightlightResult) Highlighted() template.HTML {
       -        return h.Body
       +func (h HightlightResult) Wrapped() template.HTML {
       +        return h.highlighted
        }
        
       -func highlight(w hugio.FlexiWriter, code, lang string, attributes []attributes.Attribute, cfg Config) error {
       +func (h HightlightResult) Inner() template.HTML {
       +        return h.highlighted[h.innerLow:h.innerHigh]
       +}
       +
       +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)
       @@ -162,12 +173,14 @@ func highlight(w hugio.FlexiWriter, code, lang string, attributes []attributes.A
                        lang = strings.ToLower(lexer.Config().Name)
                }
        
       +        w := &byteCountFlexiWriter{delegate: fw}
       +
                if lexer == nil {
       -                wrapper := getPreWrapper(lang)
       +                wrapper := getPreWrapper(lang, w)
                        fmt.Fprint(w, wrapper.Start(true, ""))
                        fmt.Fprint(w, gohtml.EscapeString(code))
                        fmt.Fprint(w, wrapper.End(true))
       -                return nil
       +                return low, high, nil
                }
        
                style := styles.Get(cfg.Style)
       @@ -178,42 +191,44 @@ func highlight(w hugio.FlexiWriter, code, lang string, attributes []attributes.A
        
                iterator, err := lexer.Tokenise(nil, code)
                if err != nil {
       -                return err
       +                return 0, 0, err
                }
        
                options := cfg.ToHTMLOptions()
       -        options = append(options, getHtmlPreWrapper(lang))
       +        preWrapper := getPreWrapper(lang, w)
       +        options = append(options, html.WithPreWrapper(preWrapper))
        
                formatter := html.New(options...)
        
                writeDivStart(w, attributes)
       +
                if err := formatter.Format(w, style, iterator); err != nil {
       -                return err
       +                return 0, 0, err
                }
                writeDivEnd(w)
        
       -        return nil
       +        return preWrapper.low, preWrapper.high, nil
        }
        
       -func getPreWrapper(language string) preWrapper {
       -        return preWrapper{language: language}
       -}
       -
       -func getHtmlPreWrapper(language string) html.Option {
       -        return html.WithPreWrapper(getPreWrapper(language))
       +func getPreWrapper(language string, writeCounter *byteCountFlexiWriter) *preWrapper {
       +        return &preWrapper{language: language, writeCounter: writeCounter}
        }
        
        type preWrapper struct {
       -        language string
       +        low          int
       +        high         int
       +        writeCounter *byteCountFlexiWriter
       +        language     string
        }
        
       -func (p preWrapper) Start(code bool, styleAttr string) string {
       +func (p *preWrapper) Start(code bool, styleAttr string) string {
                var language string
                if code {
                        language = p.language
                }
                w := &strings.Builder{}
                WritePreStart(w, language, styleAttr)
       +        p.low = p.writeCounter.counter + w.Len()
                return w.String()
        }
        
       @@ -229,7 +244,8 @@ func WritePreStart(w io.Writer, language, styleAttr string) {
        
        const preEnd = "</code></pre>"
        
       -func (p preWrapper) End(code bool) string {
       +func (p *preWrapper) End(code bool) string {
       +        p.high = p.writeCounter.counter
                return preEnd
        }
        
       @@ -258,3 +274,31 @@ func writeDivStart(w hugio.FlexiWriter, attrs []attributes.Attribute) {
        func writeDivEnd(w hugio.FlexiWriter) {
                w.WriteString("</div>")
        }
       +
       +type byteCountFlexiWriter struct {
       +        delegate hugio.FlexiWriter
       +        counter  int
       +}
       +
       +func (w *byteCountFlexiWriter) Write(p []byte) (int, error) {
       +        n, err := w.delegate.Write(p)
       +        w.counter += n
       +        return n, err
       +}
       +
       +func (w *byteCountFlexiWriter) WriteByte(c byte) error {
       +        w.counter++
       +        return w.delegate.WriteByte(c)
       +}
       +
       +func (w *byteCountFlexiWriter) WriteString(s string) (int, error) {
       +        n, err := w.delegate.WriteString(s)
       +        w.counter += n
       +        return n, err
       +}
       +
       +func (w *byteCountFlexiWriter) WriteRune(r rune) (int, error) {
       +        n, err := w.delegate.WriteRune(r)
       +        w.counter += n
       +        return n, err
       +}