forked from princjef/gomarkdoc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
github.go
164 lines (139 loc) · 5.68 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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package format
import (
"fmt"
"path/filepath"
"regexp"
"strings"
"github.com/chengyumeng/gomarkdoc/format/formatcore"
"github.com/chengyumeng/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 formatcore.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 formatcore.GFMCodeBlock(language, code), nil
}
// Anchor produces an anchor for the provided link.
func (f *GitHubFlavoredMarkdown) Anchor(anchor string) string {
return formatcore.Anchor(anchor)
}
// AnchorHeader converts the provided text and custom anchor link into a header
// of the provided level. The level is expected to be at least 1.
func (f *GitHubFlavoredMarkdown) AnchorHeader(level int, text, anchor string) (string, error) {
return formatcore.AnchorHeader(level, formatcore.Escape(text), anchor)
}
// 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 formatcore.Header(level, formatcore.Escape(text))
}
// RawAnchorHeader converts the provided text and custom anchor link into a
// header of the provided level without escaping the header text. The level is
// expected to be at least 1.
func (f *GitHubFlavoredMarkdown) RawAnchorHeader(level int, text, anchor string) (string, error) {
return formatcore.AnchorHeader(level, text, anchor)
}
// 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 formatcore.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 := formatcore.PlainText(headerText)
result = strings.ToLower(result)
result = strings.TrimSpace(result)
result = gfmWhitespaceRegex.ReplaceAllString(result, "-")
result = gfmRemoveRegex.ReplaceAllString(result, "")
return fmt.Sprintf("#%s", result), nil
}
// RawLocalHref generates an href within the same document but with a direct
// link provided instead of text to slugify.
func (f *GitHubFlavoredMarkdown) RawLocalHref(anchor string) string {
return fmt.Sprintf("#%s", anchor)
}
// Link generates a link with the given text and href values.
func (f *GitHubFlavoredMarkdown) Link(text, href string) (string, error) {
return formatcore.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 formatcore.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 formatcore.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 formatcore.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 formatcore.GFMAccordionTerminator(), nil
}
// Escape escapes special markdown characters from the provided text.
func (f *GitHubFlavoredMarkdown) Escape(text string) string {
return formatcore.Escape(text)
}