Skip to content

Commit 459cfcb

Browse files
committed
Prep work for auto generation of TOC.
1 parent 070578d commit 459cfcb

2 files changed

Lines changed: 81 additions & 1 deletion

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
[![CI][badge-build]][build]
32
[![GoDoc][go-docs-badge]][go-docs]
43
[![GoReportCard][go-report-card-badge]][go-report-card]

mdtopdf.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,87 @@ type PdfRenderer struct {
131131
ColumnWidths map[ast.Node][]float64
132132
}
133133

134+
// TOCEntry represents a table of contents entry
135+
type TOCEntry struct {
136+
Level int
137+
Title string
138+
ID string
139+
}
140+
141+
// TOCVisitor implements ast.NodeVisitor to collect headers
142+
type TOCVisitor struct {
143+
entries []TOCEntry
144+
}
145+
146+
// Visit implements the ast.NodeVisitor interface
147+
func (v *TOCVisitor) Visit(node ast.Node, entering bool) ast.WalkStatus {
148+
if !entering {
149+
return ast.GoToNext
150+
}
151+
152+
// Check if the node is a heading
153+
if heading, ok := node.(*ast.Heading); ok {
154+
// Extract the text content from the heading
155+
title := ExtractTextFromNode(heading)
156+
if title != "" {
157+
// Create a simple ID from the title (lowercase, replace spaces with hyphens)
158+
id := strings.ToLower(strings.ReplaceAll(strings.TrimSpace(title), " ", "-"))
159+
// Remove special characters for cleaner IDs
160+
id = strings.ReplaceAll(id, ".", "")
161+
id = strings.ReplaceAll(id, ",", "")
162+
id = strings.ReplaceAll(id, "!", "")
163+
id = strings.ReplaceAll(id, "?", "")
164+
165+
entry := TOCEntry{
166+
Level: heading.Level,
167+
Title: title,
168+
ID: id,
169+
}
170+
v.entries = append(v.entries, entry)
171+
}
172+
}
173+
174+
return ast.GoToNext
175+
}
176+
177+
// ExtractTextFromNode recursively extracts text content from AST nodes
178+
func ExtractTextFromNode(node ast.Node) string {
179+
var text strings.Builder
180+
181+
ast.WalkFunc(node, func(node ast.Node, entering bool) ast.WalkStatus {
182+
if entering {
183+
switch n := node.(type) {
184+
case *ast.Text:
185+
text.Write(n.Literal)
186+
case *ast.Code:
187+
text.Write(n.Literal)
188+
}
189+
}
190+
return ast.GoToNext
191+
})
192+
193+
return text.String()
194+
}
195+
196+
// GetTOCEntries returns TOC entries
197+
func GetTOCEntries(content []byte) ([]TOCEntry, error) {
198+
199+
// Create parser with extensions
200+
extensions := parser.CommonExtensions | parser.AutoHeadingIDs
201+
p := parser.NewWithExtensions(extensions)
202+
203+
// Parse the markdown content
204+
doc := markdown.Parse(content, p)
205+
206+
// Create visitor to collect TOC entries
207+
visitor := &TOCVisitor{}
208+
209+
// Walk the AST and collect headers
210+
ast.Walk(doc, visitor)
211+
212+
return visitor.entries, nil
213+
}
214+
134215
// SetLightTheme sets theme to 'light'
135216
func (r *PdfRenderer) SetLightTheme() {
136217
r.BackgroundColor = Colorlookup("white")

0 commit comments

Comments
 (0)