]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Add a cache for lexers.Get
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Thu, 24 Nov 2022 11:13:19 +0000 (12:13 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Thu, 24 Nov 2022 12:18:33 +0000 (13:18 +0100)
```
name                            old time/op    new time/op    delta
Codeblocks/Default-10              152ms ±11%      12ms ± 1%  -92.44%  (p=0.029 n=4+4)
Codeblocks/Hook_no_higlight-10     142ms ± 0%       7ms ± 0%  -95.36%  (p=0.029 n=4+4)

name                            old alloc/op   new alloc/op   delta
Codeblocks/Default-10             11.9MB ± 0%    11.7MB ± 0%   -1.59%  (p=0.029 n=4+4)
Codeblocks/Hook_no_higlight-10    4.62MB ± 1%    4.43MB ± 0%   -4.08%  (p=0.029 n=4+4)

name                            old allocs/op  new allocs/op  delta
Codeblocks/Default-10               209k ± 0%      209k ± 0%   -0.03%  (p=0.029 n=4+4)
Codeblocks/Hook_no_higlight-10     68.4k ± 0%     68.3k ± 0%   -0.06%  (p=0.029 n=4+4)

```

hugolib/page__per_output.go
markup/goldmark/codeblocks/render.go
markup/highlight/chromalexers/chromalexers.go [new file with mode: 0644]
markup/highlight/highlight.go
tpl/transform/transform.go

index e8dc695076624290c34024d5daed9a1c5fdcea35..60e3a7f59844d6ecbf2244853577c64f2ee1c0f9 100644 (file)
@@ -33,10 +33,10 @@ import (
        "github.com/spf13/cast"
 
        "github.com/gohugoio/hugo/markup/converter/hooks"
+       "github.com/gohugoio/hugo/markup/highlight/chromalexers"
 
        "github.com/gohugoio/hugo/markup/converter"
 
-       "github.com/alecthomas/chroma/v2/lexers"
        "github.com/gohugoio/hugo/lazy"
 
        bp "github.com/gohugoio/hugo/bufferpool"
@@ -545,7 +545,7 @@ func (p *pageContentOutput) initRenderHooks() error {
                                layoutDescriptor.Kind = "render-codeblock"
                                if id != nil {
                                        lang := id.(string)
-                                       lexer := lexers.Get(lang)
+                                       lexer := chromalexers.Get(lang)
                                        if lexer != nil {
                                                layoutDescriptor.KindVariants = strings.Join(lexer.Config().Aliases, ",")
                                        } else {
index 3daad0af6d2b79125faa27d60a860abdad826735..739781de1c9c05d97de3f175aebbab4b75b7ad0e 100644 (file)
@@ -19,11 +19,11 @@ import (
        "strings"
        "sync"
 
-       "github.com/alecthomas/chroma/v2/lexers"
        "github.com/gohugoio/hugo/common/herrors"
        htext "github.com/gohugoio/hugo/common/text"
        "github.com/gohugoio/hugo/markup/converter/hooks"
        "github.com/gohugoio/hugo/markup/goldmark/internal/render"
+       "github.com/gohugoio/hugo/markup/highlight/chromalexers"
        "github.com/gohugoio/hugo/markup/internal/attributes"
        "github.com/yuin/goldmark"
        "github.com/yuin/goldmark/ast"
@@ -94,7 +94,7 @@ func (r *htmlRenderer) renderCodeBlock(w util.BufWriter, src []byte, node ast.No
        }
 
        attrtp := attributes.AttributesOwnerCodeBlockCustom
-       if isd, ok := renderer.(hooks.IsDefaultCodeBlockRendererProvider); (ok && isd.IsDefaultCodeBlockRenderer()) || lexers.Get(lang) != nil {
+       if isd, ok := renderer.(hooks.IsDefaultCodeBlockRendererProvider); (ok && isd.IsDefaultCodeBlockRenderer()) || chromalexers.Get(lang) != nil {
                // We say that this is a Chroma code block if it's the default code block renderer
                // or if the language is supported by Chroma.
                attrtp = attributes.AttributesOwnerCodeBlockChroma
diff --git a/markup/highlight/chromalexers/chromalexers.go b/markup/highlight/chromalexers/chromalexers.go
new file mode 100644 (file)
index 0000000..41fd762
--- /dev/null
@@ -0,0 +1,50 @@
+// 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 chromalexers
+
+import (
+       "sync"
+
+       "github.com/alecthomas/chroma/v2"
+       "github.com/alecthomas/chroma/v2/lexers"
+)
+
+type lexersMap struct {
+       lexers map[string]chroma.Lexer
+       mu     sync.RWMutex
+}
+
+var lexerCache = &lexersMap{lexers: make(map[string]chroma.Lexer)}
+
+// Get returns a lexer for the given language name, nil if not found.
+// This is just a wrapper around chromalexers.Get that caches the result.
+// Reasoning for this is that chromalexers.Get is slow in the case where the lexer is not found,
+// which is a common case in Hugo.
+func Get(name string) chroma.Lexer {
+       lexerCache.mu.RLock()
+       lexer, found := lexerCache.lexers[name]
+       lexerCache.mu.RUnlock()
+
+       if found {
+               return lexer
+       }
+
+       lexer = lexers.Get(name)
+
+       lexerCache.mu.Lock()
+       lexerCache.lexers[name] = lexer
+       lexerCache.mu.Unlock()
+
+       return lexer
+}
index 5b19d6e8e66000f8428b81492381027bb78f8f7e..010c941f74ae7ae4b2a8cf050f623cd1dd072cc3 100644 (file)
@@ -28,6 +28,7 @@ import (
        "github.com/gohugoio/hugo/common/text"
        "github.com/gohugoio/hugo/identity"
        "github.com/gohugoio/hugo/markup/converter/hooks"
+       "github.com/gohugoio/hugo/markup/highlight/chromalexers"
        "github.com/gohugoio/hugo/markup/internal/attributes"
 )
 
@@ -167,7 +168,7 @@ func (h HightlightResult) Inner() template.HTML {
 func highlight(fw hugio.FlexiWriter, code, lang string, attributes []attributes.Attribute, cfg Config) (int, int, error) {
        var lexer chroma.Lexer
        if lang != "" {
-               lexer = lexers.Get(lang)
+               lexer = chromalexers.Get(lang)
        }
 
        if lexer == nil && (cfg.GuessSyntax && !cfg.NoHl) {
index 36508c4284eda5ba4ca9b9469cf400cce30f0447..039d674c4248c2e6acdc6f5cc2f265e765617ac9 100644 (file)
@@ -18,10 +18,10 @@ import (
        "html"
        "html/template"
 
-       "github.com/alecthomas/chroma/v2/lexers"
        "github.com/gohugoio/hugo/cache/namedmemcache"
        "github.com/gohugoio/hugo/markup/converter/hooks"
        "github.com/gohugoio/hugo/markup/highlight"
+       "github.com/gohugoio/hugo/markup/highlight/chromalexers"
        "github.com/gohugoio/hugo/tpl"
 
        "github.com/gohugoio/hugo/deps"
@@ -93,7 +93,7 @@ func (ns *Namespace) HighlightCodeBlock(ctx hooks.CodeblockContext, opts ...any)
 
 // CanHighlight returns whether the given code language is supported by the Chroma highlighter.
 func (ns *Namespace) CanHighlight(language string) bool {
-       return lexers.Get(language) != nil
+       return chromalexers.Get(language) != nil
 }
 
 // HTMLEscape returns a copy of s with reserved HTML characters escaped.