This repository has been archived by the owner on Mar 24, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
section_level.go
129 lines (116 loc) · 3.93 KB
/
section_level.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
package parser
import (
"github.com/demizer/go-rst/pkg/log"
doc "github.com/demizer/go-rst/pkg/document"
mes "github.com/demizer/go-rst/pkg/messages"
)
// sectionLevel is a single section level. sections contains a list of pointers to doc.SectionNode that are dertermined to be a
// section of the level indicated by level. rChar is the rune character that denotes the section level.
type sectionLevel struct {
rChar rune
level int
overLine bool // True if the section level has an overline.
sections []*doc.SectionNode // Sections matching level.
}
// sectionLevels contains the encountered section levels in order by level. levels[0] is section level 1 and levels[1] is
// section level 2. lastSectionNode is a pointer to the lastSectionNode added to levels.
type sectionLevels struct {
lastSectionNode *doc.SectionNode
levels []*sectionLevel
logConf log.Config
log.Logger
}
func newSectionLevels(logConf log.Config) *sectionLevels {
conf := logConf
conf.Name = "section_level"
return §ionLevels{
logConf: conf,
Logger: log.NewLogger(conf),
}
}
// FindByRune loops through the sectionLevels to find a section using a Rune as the key. If the section is found, a pointer
// to the SectionNode is returned.
func (s *sectionLevels) FindByRune(rChar rune) *sectionLevel {
for _, sec := range s.levels {
if sec.rChar == rChar {
return sec
}
}
return nil
}
// Add determines if the underline rune in the sec argument matches any existing sectionLevel in sectionLevels. Add also
// checks the section level ordering is correct and returns a mes.SectionErrorTitleLevelInconsistent ParserMessage if inconsistencies
// are found.
func (s *sectionLevels) Add(sec *doc.SectionNode) (err mes.MessageType) {
level := 1
secLvl := s.FindByRune(sec.UnderLine.Rune)
// Local function for creating a sectionLevel
var newSectionLevel = func() {
var oLine bool
if sec.OverLine != nil {
oLine = true
}
s.Msgr("Creating new sectionLevel", "level", level)
secLvl = §ionLevel{
rChar: sec.UnderLine.Rune,
level: level, overLine: oLine,
}
s.levels = append(s.levels, secLvl)
// secLvl.sections = append(secLvl.sections, sec)
}
if secLvl == nil {
if s.lastSectionNode != nil {
// Check if the provisional level of sec is already in sectionLevels; if it is and the adornment
// characters don't match, then we have an inconsistent level error.
level = s.lastSectionNode.Level + 1
nextLevel := s.SectionLevelByLevel(level)
if nextLevel != nil &&
nextLevel.rChar != sec.UnderLine.Rune {
return mes.SectionErrorTitleLevelInconsistent
}
} else {
level = len(s.levels) + 1
}
newSectionLevel()
} else {
if secLvl.overLine && sec.OverLine == nil ||
!secLvl.overLine && sec.OverLine != nil {
// If sec has an OverLine, but the matching sectionLevel with the same Rune as sec does not have an
// OverLine, then they are not in the same sectionLevel, and visa versa.
level = len(s.levels) + 1
newSectionLevel()
} else {
s.Msgr("using sectionLevel", "sectionLevel", secLvl.level)
level = secLvl.level
}
}
secLvl.sections = append(secLvl.sections, sec)
sec.Level = level
s.lastSectionNode = sec
return
}
// SectionLevelByLevel returns a pointer to a sectionLevel of level level. Nil is returned if l is greater than the number of
// section levels encountered.
func (s *sectionLevels) SectionLevelByLevel(level int) *sectionLevel {
if level > len(s.levels) {
return nil
}
return (s.levels)[level-1]
}
// LastSectionByLevel returns a pointer to the last section encountered by level.
func (s *sectionLevels) LastSectionByLevel(level int) (sec *doc.SectionNode) {
exit:
for i := len(s.levels) - 1; i >= 0; i-- {
if (s.levels)[i].level != level {
continue
}
for j := len((s.levels)[i].sections) - 1; j >= 0; j-- {
sec = (s.levels)[i].sections[j]
if sec.Level == level {
s.Msgr("found sectionLevel", "sectionLevel", sec.Level)
break exit
}
}
}
return
}