1// based on HUGO markup/goldmark/tables/tables.go -- Pet
2
3// Copyright 2024 The Hugo Authors. All rights reserved.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16package goldmark_extensions
17/*
18package tables
19
20import (
21 "github.com/gohugoio/hugo/common/herrors"
22 "github.com/gohugoio/hugo/common/types/hstring"
23 "github.com/gohugoio/hugo/markup/converter/hooks"
24 "github.com/gohugoio/hugo/markup/goldmark/internal/render"
25 "github.com/gohugoio/hugo/markup/internal/attributes"
26 "github.com/yuin/goldmark"
27 "github.com/yuin/goldmark/ast"
28 gast "github.com/yuin/goldmark/extension/ast"
29 "github.com/yuin/goldmark/renderer"
30 "github.com/yuin/goldmark/util"
31)
32
33type (
34 ext struct{}
35 htmlRenderer struct{}
36)
37
38func New() goldmark.Extender {
39 return &ext{}
40}
41
42func (e *ext) Extend(m goldmark.Markdown) {
43 m.Renderer().AddOptions(renderer.WithNodeRenderers(
44 util.Prioritized(newHTMLRenderer(), 100),
45 ))
46}
47
48func newHTMLRenderer() renderer.NodeRenderer {
49 r := &htmlRenderer{}
50 return r
51}
52
53func (r *htmlRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
54 reg.Register(gast.KindTable, r.renderTable)
55 reg.Register(gast.KindTableHeader, r.renderHeaderOrRow)
56 reg.Register(gast.KindTableRow, r.renderHeaderOrRow)
57 reg.Register(gast.KindTableCell, r.renderCell)
58}
59
60func (r *htmlRenderer) renderTable(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
61 ctx := w.(*render.Context)
62 if entering {
63 // This will be modified below.
64 table := &hooks.Table{}
65 ctx.PushValue(gast.KindTable, table)
66 return ast.WalkContinue, nil
67 }
68
69 v := ctx.PopValue(gast.KindTable)
70 if v == nil {
71 panic("table not found")
72 }
73
74 table := v.(*hooks.Table)
75
76 renderer := ctx.RenderContext().GetRenderer(hooks.TableRendererType, nil)
77 if renderer == nil {
78 panic("table hook renderer not found")
79 }
80
81 ordinal := ctx.GetAndIncrementOrdinal(gast.KindTable)
82
83 tctx := &tableContext{
84 BaseContext: render.NewBaseContext(ctx, renderer, n, source, nil, ordinal),
85 AttributesHolder: attributes.New(n.Attributes(), attributes.AttributesOwnerGeneral),
86 tHead: table.THead,
87 tBody: table.TBody,
88 }
89
90 cr := renderer.(hooks.TableRenderer)
91
92 err := cr.RenderTable(
93 ctx.RenderContext().Ctx,
94 w,
95 tctx,
96 )
97 if err != nil {
98 return ast.WalkContinue, herrors.NewFileErrorFromPos(err, tctx.Position())
99 }
100
101 return ast.WalkContinue, nil
102}
103
104func (r *htmlRenderer) peekTable(ctx *render.Context) *hooks.Table {
105 v := ctx.PeekValue(gast.KindTable)
106 if v == nil {
107 panic("table not found")
108 }
109 return v.(*hooks.Table)
110}
111
112func (r *htmlRenderer) renderCell(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
113 ctx := w.(*render.Context)
114
115 if entering {
116 // Store the current pos so we can capture the rendered text.
117 ctx.PushPos(ctx.Buffer.Len())
118 return ast.WalkContinue, nil
119 }
120
121 n := node.(*gast.TableCell)
122
123 text := ctx.PopRenderedString()
124
125 table := r.peekTable(ctx)
126
127 var alignment string
128 switch n.Alignment {
129 case gast.AlignLeft:
130 alignment = "left"
131 case gast.AlignRight:
132 alignment = "right"
133 case gast.AlignCenter:
134 alignment = "center"
135 default:
136 alignment = ""
137 }
138
139 cell := hooks.TableCell{Text: hstring.HTML(text), Alignment: alignment}
140
141 if node.Parent().Kind() == gast.KindTableHeader {
142 table.THead[len(table.THead)-1] = append(table.THead[len(table.THead)-1], cell)
143 } else {
144 table.TBody[len(table.TBody)-1] = append(table.TBody[len(table.TBody)-1], cell)
145 }
146
147 return ast.WalkContinue, nil
148}
149
150func (r *htmlRenderer) renderHeaderOrRow(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
151 ctx := w.(*render.Context)
152 table := r.peekTable(ctx)
153 if entering {
154 if n.Kind() == gast.KindTableHeader {
155 table.THead = append(table.THead, hooks.TableRow{})
156 } else {
157 table.TBody = append(table.TBody, hooks.TableRow{})
158 }
159 return ast.WalkContinue, nil
160 }
161
162 return ast.WalkContinue, nil
163}
164
165type tableContext struct {
166 hooks.BaseContext
167 *attributes.AttributesHolder
168
169 tHead []hooks.TableRow
170 tBody []hooks.TableRow
171}
172
173func (c *tableContext) THead() []hooks.TableRow {
174 return c.tHead
175}
176
177func (c *tableContext) TBody() []hooks.TableRow {
178 return c.tBody
179}
180*/