/
github.go
144 lines (122 loc) · 4.66 KB
/
github.go
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
package format
import (
"fmt"
"path/filepath"
"regexp"
"strings"
"github.com/princjef/gomarkdoc/lang"
)
// GitHubFlavoredMarkdown provides a Format which is compatible with GitHub
// Flavored Markdown's syntax and semantics. See GitHub's documentation for
// more details about their markdown format:
// https://guides.github.com/features/mastering-markdown/
type GitHubFlavoredMarkdown struct{}
// Bold converts the provided text to bold
func (f *GitHubFlavoredMarkdown) Bold(text string) (string, error) {
return bold(text), nil
}
// CodeBlock wraps the provided code as a code block and tags it with the
// provided language (or no language if the empty string is provided).
func (f *GitHubFlavoredMarkdown) CodeBlock(language, code string) (string, error) {
return gfmCodeBlock(language, code), nil
}
// Header converts the provided text into a header of the provided level. The
// level is expected to be at least 1.
func (f *GitHubFlavoredMarkdown) Header(level int, text string) (string, error) {
return header(level, escape(text))
}
// RawHeader converts the provided text into a header of the provided level
// without escaping the header text. The level is expected to be at least 1.
func (f *GitHubFlavoredMarkdown) RawHeader(level int, text string) (string, error) {
return header(level, text)
}
var (
gfmWhitespaceRegex = regexp.MustCompile(`\s`)
gfmRemoveRegex = regexp.MustCompile(`[^\pL-_\d]+`)
)
// LocalHref generates an href for navigating to a header with the given
// headerText located within the same document as the href itself.
func (f *GitHubFlavoredMarkdown) LocalHref(headerText string) (string, error) {
result := plainText(headerText)
result = strings.ToLower(result)
result = strings.TrimSpace(result)
result = gfmWhitespaceRegex.ReplaceAllString(result, "-")
result = gfmRemoveRegex.ReplaceAllString(result, "")
return fmt.Sprintf("#%s", result), nil
}
// Link generates a link with the given text and href values.
func (f *GitHubFlavoredMarkdown) Link(text, href string) (string, error) {
return link(text, href), nil
}
// CodeHref generates an href to the provided code entry.
func (f *GitHubFlavoredMarkdown) CodeHref(loc lang.Location) (string, error) {
// If there's no repo, we can't compute an href
if loc.Repo == nil {
return "", nil
}
var (
relative string
err error
)
if filepath.IsAbs(loc.Filepath) {
relative, err = filepath.Rel(loc.WorkDir, loc.Filepath)
if err != nil {
return "", err
}
} else {
relative = loc.Filepath
}
full := filepath.Join(loc.Repo.PathFromRoot, relative)
p, err := filepath.Rel(string(filepath.Separator), full)
if err != nil {
return "", err
}
var locStr string
if loc.Start.Line == loc.End.Line {
locStr = fmt.Sprintf("L%d", loc.Start.Line)
} else {
locStr = fmt.Sprintf("L%d-L%d", loc.Start.Line, loc.End.Line)
}
return fmt.Sprintf(
"%s/blob/%s/%s#%s",
loc.Repo.Remote,
loc.Repo.DefaultBranch,
filepath.ToSlash(p),
locStr,
), nil
}
// ListEntry generates an unordered list entry with the provided text at the
// provided zero-indexed depth. A depth of 0 is considered the topmost level of
// list.
func (f *GitHubFlavoredMarkdown) ListEntry(depth int, text string) (string, error) {
return listEntry(depth, text), nil
}
// Accordion generates a collapsible content. The accordion's visible title
// while collapsed is the provided title and the expanded content is the body.
func (f *GitHubFlavoredMarkdown) Accordion(title, body string) (string, error) {
return gfmAccordion(title, body), nil
}
// AccordionHeader generates the header visible when an accordion is collapsed.
//
// The AccordionHeader is expected to be used in conjunction with
// AccordionTerminator() when the demands of the body's rendering requires it to
// be generated independently. The result looks conceptually like the following:
//
// accordion := format.AccordionHeader("Accordion Title") + "Accordion Body" + format.AccordionTerminator()
func (f *GitHubFlavoredMarkdown) AccordionHeader(title string) (string, error) {
return gfmAccordionHeader(title), nil
}
// AccordionTerminator generates the code necessary to terminate an accordion
// after the body. It is expected to be used in conjunction with
// AccordionHeader(). See AccordionHeader for a full description.
func (f *GitHubFlavoredMarkdown) AccordionTerminator() (string, error) {
return gfmAccordionTerminator(), nil
}
// Paragraph formats a paragraph with the provided text as the contents.
func (f *GitHubFlavoredMarkdown) Paragraph(text string) (string, error) {
return paragraph(text), nil
}
// Escape escapes special markdown characters from the provided text.
func (f *GitHubFlavoredMarkdown) Escape(text string) string {
return escape(text)
}