passthrough.go - hugo - [fork] hugo port for 9front
 (HTM) git clone https://git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       passthrough.go (4332B)
       ---
            1 // Copyright 2024 The Hugo Authors. All rights reserved.
            2 //
            3 // Licensed under the Apache License, Version 2.0 (the "License");
            4 // you may not use this file except in compliance with the License.
            5 // You may obtain a copy of the License at
            6 // http://www.apache.org/licenses/LICENSE-2.0
            7 //
            8 // Unless required by applicable law or agreed to in writing, software
            9 // distributed under the License is distributed on an "AS IS" BASIS,
           10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           11 // See the License for the specific language governing permissions and
           12 // limitations under the License.
           13 
           14 package passthrough
           15 
           16 import (
           17         "bytes"
           18 
           19         "github.com/gohugoio/hugo-goldmark-extensions/passthrough"
           20         "github.com/gohugoio/hugo/markup/converter/hooks"
           21         "github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
           22         "github.com/gohugoio/hugo/markup/goldmark/internal/render"
           23         "github.com/gohugoio/hugo/markup/internal/attributes"
           24         "github.com/yuin/goldmark"
           25         "github.com/yuin/goldmark/ast"
           26         "github.com/yuin/goldmark/renderer"
           27         "github.com/yuin/goldmark/util"
           28 )
           29 
           30 func New(cfg goldmark_config.Passthrough) goldmark.Extender {
           31         if !cfg.Enable {
           32                 return nil
           33         }
           34         return &passthroughExtension{cfg: cfg}
           35 }
           36 
           37 type (
           38         passthroughExtension struct {
           39                 cfg goldmark_config.Passthrough
           40         }
           41         htmlRenderer struct{}
           42 )
           43 
           44 func (e *passthroughExtension) Extend(m goldmark.Markdown) {
           45         configuredInlines := e.cfg.Delimiters.Inline
           46         configuredBlocks := e.cfg.Delimiters.Block
           47 
           48         inlineDelimiters := make([]passthrough.Delimiters, len(configuredInlines))
           49         blockDelimiters := make([]passthrough.Delimiters, len(configuredBlocks))
           50 
           51         for i, d := range configuredInlines {
           52                 inlineDelimiters[i] = passthrough.Delimiters{
           53                         Open:  d[0],
           54                         Close: d[1],
           55                 }
           56         }
           57 
           58         for i, d := range configuredBlocks {
           59                 blockDelimiters[i] = passthrough.Delimiters{
           60                         Open:  d[0],
           61                         Close: d[1],
           62                 }
           63         }
           64 
           65         pse := passthrough.New(
           66                 passthrough.Config{
           67                         InlineDelimiters: inlineDelimiters,
           68                         BlockDelimiters:  blockDelimiters,
           69                 },
           70         )
           71 
           72         pse.Extend(m)
           73 
           74         // Set up render hooks if configured.
           75         // Upstream passthrough inline = 101
           76         // Upstream passthrough block = 99
           77         m.Renderer().AddOptions(renderer.WithNodeRenderers(
           78                 util.Prioritized(newHTMLRenderer(), 90),
           79         ))
           80 }
           81 
           82 func newHTMLRenderer() renderer.NodeRenderer {
           83         r := &htmlRenderer{}
           84         return r
           85 }
           86 
           87 func (r *htmlRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
           88         reg.Register(passthrough.KindPassthroughBlock, r.renderPassthroughBlock)
           89         reg.Register(passthrough.KindPassthroughInline, r.renderPassthroughBlock)
           90 }
           91 
           92 func (r *htmlRenderer) renderPassthroughBlock(w util.BufWriter, src []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
           93         ctx := w.(*render.Context)
           94 
           95         if entering {
           96                 return ast.WalkContinue, nil
           97         }
           98 
           99         var (
          100                 s      string
          101                 typ    string
          102                 delims *passthrough.Delimiters
          103         )
          104 
          105         switch nn := node.(type) {
          106         case *passthrough.PassthroughInline:
          107                 s = string(nn.Text(src))
          108                 typ = "inline"
          109                 delims = nn.Delimiters
          110         case (*passthrough.PassthroughBlock):
          111                 l := nn.Lines().Len()
          112                 var buff bytes.Buffer
          113                 for i := range l {
          114                         line := nn.Lines().At(i)
          115                         buff.Write(line.Value(src))
          116                 }
          117                 s = buff.String()
          118                 typ = "block"
          119                 delims = nn.Delimiters
          120         }
          121 
          122         renderer := ctx.RenderContext().GetRenderer(hooks.PassthroughRendererType, typ)
          123         if renderer == nil {
          124                 // Write the raw content if no renderer is found.
          125                 ctx.WriteString(s)
          126                 return ast.WalkContinue, nil
          127         }
          128 
          129         // Inline and block passthroughs share the same ordinal counter.
          130         ordinal := ctx.GetAndIncrementOrdinal(passthrough.KindPassthroughBlock)
          131 
          132         // Trim the delimiters.
          133         s = s[len(delims.Open) : len(s)-len(delims.Close)]
          134 
          135         pctx := &passthroughContext{
          136                 BaseContext:      render.NewBaseContext(ctx, renderer, node, src, nil, ordinal),
          137                 inner:            s,
          138                 typ:              typ,
          139                 AttributesHolder: attributes.New(node.Attributes(), attributes.AttributesOwnerGeneral),
          140         }
          141 
          142         pr := renderer.(hooks.PassthroughRenderer)
          143 
          144         if err := pr.RenderPassthrough(ctx.RenderContext().Ctx, w, pctx); err != nil {
          145                 return ast.WalkStop, err
          146         }
          147 
          148         return ast.WalkContinue, nil
          149 }
          150 
          151 type passthroughContext struct {
          152         hooks.BaseContext
          153 
          154         typ   string // inner or block
          155         inner string
          156 
          157         *attributes.AttributesHolder
          158 }
          159 
          160 func (p *passthroughContext) Type() string {
          161         return p.typ
          162 }
          163 
          164 func (p *passthroughContext) Inner() string {
          165         return p.inner
          166 }