104 lines
1.8 KiB
Go
104 lines
1.8 KiB
Go
package note
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
type Section struct {
|
|
ID string
|
|
Heading string
|
|
Content string
|
|
}
|
|
|
|
// ParseH2Heading returns the heading text for a level-two markdown heading.
|
|
func ParseH2Heading(line string) (string, bool) {
|
|
trimmed := strings.TrimLeft(line, " \t")
|
|
if !strings.HasPrefix(trimmed, "## ") {
|
|
return "", false
|
|
}
|
|
return strings.TrimSpace(strings.TrimPrefix(trimmed, "## ")), true
|
|
}
|
|
|
|
// ParseSections splits markdown into level-two heading sections.
|
|
func ParseSections(content string) []Section {
|
|
if content == "" {
|
|
return nil
|
|
}
|
|
|
|
lines := strings.Split(content, "\n")
|
|
var sections []Section
|
|
|
|
var current *Section
|
|
var builder strings.Builder
|
|
counts := make(map[string]int)
|
|
|
|
flush := func() {
|
|
if current == nil {
|
|
return
|
|
}
|
|
current.Content = builder.String()
|
|
sections = append(sections, *current)
|
|
current = nil
|
|
builder.Reset()
|
|
}
|
|
|
|
for i, line := range lines {
|
|
heading, ok := ParseH2Heading(line)
|
|
if ok {
|
|
flush()
|
|
base := slugifyHeading(heading)
|
|
if base == "" {
|
|
base = "section"
|
|
}
|
|
counts[base]++
|
|
id := base
|
|
if counts[base] > 1 {
|
|
id = base + "-" + strconv.Itoa(counts[base])
|
|
}
|
|
current = &Section{
|
|
ID: id,
|
|
Heading: heading,
|
|
}
|
|
}
|
|
|
|
if current != nil {
|
|
builder.WriteString(line)
|
|
if i < len(lines)-1 {
|
|
builder.WriteString("\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
flush()
|
|
return sections
|
|
}
|
|
|
|
func slugifyHeading(input string) string {
|
|
in := strings.TrimSpace(strings.ToLower(input))
|
|
if in == "" {
|
|
return ""
|
|
}
|
|
|
|
var b strings.Builder
|
|
prevDash := false
|
|
|
|
for _, r := range in {
|
|
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
|
b.WriteRune(r)
|
|
prevDash = false
|
|
continue
|
|
}
|
|
|
|
if !prevDash {
|
|
b.WriteByte('-')
|
|
prevDash = true
|
|
}
|
|
}
|
|
|
|
out := b.String()
|
|
out = strings.Trim(out, "-")
|
|
return out
|
|
}
|