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 }