File: hook.go

package info (click to toggle)
mmark 2.2.25%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 996 kB
  • sloc: xml: 228; makefile: 81; ansic: 3
file content (156 lines) | stat: -rw-r--r-- 4,212 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package mhtml

import (
	"fmt"
	"io"

	"github.com/mmarkdown/mmark/v2/lang"
	"github.com/mmarkdown/mmark/v2/mast"

	"github.com/gomarkdown/markdown/ast"
)

var (
	// IndexReturnLinkContents is the string to use for index item return links.
	IndexReturnLinkContents = "<sup>[go]</sup>"
)

// RenderOptions are options for RenderHook.
type RendererOptions struct {
	Language lang.Lang
}

// RenderHook is used to render mmark specific AST nodes.
func (r RendererOptions) RenderHook(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {
	switch node := node.(type) {
	case *ast.Footnotes:
		if !entering {
			io.WriteString(w, "</h1>\n")
			return ast.GoToNext, true
		}
		io.WriteString(w, `<h1 id="footnote-section">`)
		io.WriteString(w, r.Language.Footnotes())
	case *mast.Bibliography:
		if !entering {
			io.WriteString(w, "</dl>\n")
			return ast.GoToNext, true
		}
		io.WriteString(w, "<h1 id=\"bibliography-section\">"+r.Language.Bibliography()+"</h1>\n<div class=\"bibliography\">\n")
		io.WriteString(w, "<dl>\n")
		return ast.GoToNext, true
	case *mast.BibliographyItem:
		if !entering {
			return ast.GoToNext, true
		}
		bibliographyItem(w, node, entering)
		return ast.GoToNext, true
	case *mast.Title:
		// we out if in mmark.go with a hack to capture it.
		return ast.GoToNext, true
	case *mast.DocumentIndex:
		if !entering {
			io.WriteString(w, "\n</div>\n")
			return ast.GoToNext, true
		}
		io.WriteString(w, "<h1 id=\"index-section\">"+r.Language.Index()+"</h1>\n<div class=\"index\">\n")
		return ast.GoToNext, true
	case *mast.IndexLetter:
		if !entering {
			io.WriteString(w, "</ul>\n")
			io.WriteString(w, "</dd>\n")
			io.WriteString(w, "</dl>\n")
			return ast.GoToNext, true
		}
		// use id= idxref idxitm.
		io.WriteString(w, "<dl>\n")
		io.WriteString(w, `<dt>`)
		io.WriteString(w, string(node.Literal))
		io.WriteString(w, "</dt>\n")
		io.WriteString(w, "<dd>\n")
		io.WriteString(w, "<ul>\n")
		return ast.GoToNext, true
	case *mast.IndexItem:
		if !entering {
			io.WriteString(w, "</li>\n")
			return ast.GoToNext, true
		}
		io.WriteString(w, "<li>\n")
		w.Write(node.Item)
		return ast.GoToNext, true
	case *mast.IndexSubItem:
		if !entering {
			if lastSubItem(node) {
				io.WriteString(w, "</ul>\n")
			}
			io.WriteString(w, "</li>\n")
			return ast.GoToNext, true
		}
		if firstSubItem(node) {
			io.WriteString(w, "<ul>\n")
		}
		io.WriteString(w, "<li>\n")
		w.Write(node.Subitem)
		return ast.GoToNext, true
	case *mast.IndexLink:
		if !entering {
			io.WriteString(w, "</a>")
			return ast.GoToNext, true
		}
		io.WriteString(w, ` <a class="index-return" href="#`+string(node.Destination)+`">`)
		io.WriteString(w, IndexReturnLinkContents)
		return ast.GoToNext, true
	case *mast.ReferenceBlock:
		// ignore these for HTML output as this is XML and not used at all.
		return ast.GoToNext, true
	}
	return ast.GoToNext, false
}

func bibliographyItem(w io.Writer, bib *mast.BibliographyItem, entering bool) {
	io.WriteString(w, `<dt class="bibliography-cite" id="`+string(bib.Anchor)+`">`+fmt.Sprintf("[%s]", bib.Anchor)+"</dt>\n")
	io.WriteString(w, `<dd>`)
	defer io.WriteString(w, "</dd>\n")
	if bib.Reference == nil {
		return
	}
	for _, author := range bib.Reference.Front.Authors {
		io.WriteString(w, `<span class="bibliography-author">`+author.Fullname+"</span>\n")
	}
	io.WriteString(w, `<span class="bibliography-title">`+bib.Reference.Front.Title+"</span>\n")
	if bib.Reference.Target != "" {
		io.WriteString(w, `<a class="bliography-target" href="`+bib.Reference.Target+"\">"+bib.Reference.Target+"</a>\n")
	}
	if bib.Reference.Front.Date.Year != "" {
		io.WriteString(w, `<date class="bibliography-date">`+bib.Reference.Front.Date.Year+"</date>\n")
	}
}

func firstSubItem(node ast.Node) bool {
	prev := ast.GetPrevNode(node)
	if prev == nil {
		return true
	}
	for prev != nil {
		_, ok := prev.(*mast.IndexSubItem)
		if ok {
			return false
		}
		prev = ast.GetPrevNode(prev)
	}
	return true
}

func lastSubItem(node ast.Node) bool {
	next := ast.GetNextNode(node)
	if next == nil {
		return true
	}
	for next != nil {
		_, ok := next.(*mast.IndexSubItem)
		if ok {
			return false
		}
		next = ast.GetNextNode(next)
	}
	return true
}