-
Notifications
You must be signed in to change notification settings - Fork 0
/
sections.go
108 lines (87 loc) · 2.03 KB
/
sections.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
package main
import (
"fmt"
"regexp"
"strings"
)
type sectionInfo struct {
tags []string
name string
}
type section struct {
info sectionInfo
body string
}
func parse(contents string) ([]section, error) {
lines := strings.Split(contents, "\n")
sections := []section{}
var currentInfo, nextInfo sectionInfo
var i, j int
currentInfo = sectionInfo{}
for true {
for ; j < len(lines); j++ {
var ok bool
var err error
nextInfo, ok, err = sectionHeader(lines[j])
if err != nil {
return []section{}, err
}
if ok {
break
}
}
section := section{
info: currentInfo,
body: strings.Join(lines[i:j], "\n"),
}
sections = append(sections, section)
if j >= len(lines) {
break
}
currentInfo = nextInfo
j++
i = j
}
if sections[0].body == "" {
return sections[1:], nil
}
return sections, nil
}
var (
sectionHeaderRegexp = regexp.MustCompile(`^ {0,3}(\*{3}|-{3}|_{3})`)
sectionHeaderInfoRegexp = regexp.MustCompile(`^ {0,3}(\*{3}|-{3}|_{3}) *([0-9a-zA-Z_-]+|(\+[0-9a-zA-Z_-]+ *)*) *$`)
)
func sectionHeader(line string) (sectionInfo, bool, error) {
var info sectionInfo
if sectionHeaderRegexp.MatchString(line) {
if ok := sectionHeaderInfoRegexp.MatchString(line); !ok {
return info, true, errMalformedSectionHeader{line}
}
match := sectionHeaderInfoRegexp.FindStringSubmatch(line)
if match[2] == "" {
return info, true, nil
}
if match[2][0] == '+' {
tokens := strings.Split(match[2], " ")
for _, token := range tokens {
if token != "" {
info.tags = append(info.tags, token[1:])
}
}
} else {
info.name = match[2]
}
return info, true, nil
}
return info, false, nil
}
func dump(section section) string {
if section.info.name != "" {
return fmt.Sprintf("--- %v\n%v\n", section.info.name, section.body)
} else if len(section.info.tags) > 0 {
tagsWithoutLeadingPlus := strings.Join(section.info.tags, " +")
return fmt.Sprintf("--- +%v\n%v\n", tagsWithoutLeadingPlus, section.body)
} else {
return fmt.Sprintf("---\n%v\n", section.body)
}
}