-
Notifications
You must be signed in to change notification settings - Fork 15
/
format_state.go
136 lines (102 loc) · 3.46 KB
/
format_state.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
package quill
import (
"bytes"
"sort"
"strconv"
)
// A formatState holds the current state of open tag, class, or style formats.
type formatState []*Format // the list of currently open attribute tags
// hasSet says if the given format is already opened.
func (fs *formatState) hasSet(fm *Format) bool {
for i := range *fs {
if (*fs)[i].Place == fm.Place && (*fs)[i].Val == fm.Val {
return true
}
}
return false
}
// closePrevious checks if the previous ops opened any formats that are not set on the current Op and closes those formats
// in the opposite order in which they were opened.
func (fs *formatState) closePrevious(buf *bytes.Buffer, o *Op, doingBlock bool) {
closedTemp := make(formatState, 0, 1)
for i := len(*fs) - 1; i >= 0; i-- { // Start with the last format opened.
f := (*fs)[i]
// If this format is not set on the current Op, close it.
if (!f.wrap && !f.fm.HasFormat(o)) || (f.wrap && f.fm.(FormatWrapper).Close(*fs, o, doingBlock)) {
// If we need to close a tag after which there are tags that should stay open, close the following tags for now.
if i < len(*fs)-1 {
for ij := len(*fs) - 1; ij > i; ij-- {
closedTemp.add((*fs)[ij])
fs.pop(buf)
}
}
fs.pop(buf)
}
}
// Re-open the temporarily closed formats.
closedTemp.writeFormats(buf)
*fs = append(*fs, closedTemp...) // Copy after the sorting.
}
// pop removes the last format from the state of currently open formats.
func (fs *formatState) pop(buf *bytes.Buffer) {
indx := len(*fs) - 1
if (*fs)[indx].wrap {
buf.WriteString((*fs)[indx].wrapPost)
} else if (*fs)[indx].Place == Tag {
closeTag(buf, (*fs)[indx].Val)
} else {
closeTag(buf, "span")
}
*fs = (*fs)[:indx]
}
// add adds a format that the string that will be written to buf right after this will have.
// Before calling add, check if the Format is already opened up earlier.
// Do not use add to write block-level styles (those are written by o.writeBlock after being merged).
func (fs *formatState) add(f *Format) {
if f.Place < 3 { // Check if the Place is valid.
*fs = append(*fs, f)
}
}
// writeFormats sorts the formats in the current formatState and writes them all out to buf. If a format implements
// the FormatWrapper interface, that format's opening wrap is printed.
func (fs *formatState) writeFormats(buf *bytes.Buffer) {
sort.Sort(fs) // Ensure that the serialization is consistent even if attribute ordering in a map changes.
for _, f := range *fs {
if f.wrap {
buf.WriteString(f.Val) // The complete opening or closing wrap is given.
continue
}
buf.WriteByte('<')
switch f.Place {
case Tag:
buf.WriteString(f.Val)
case Class:
buf.WriteString("span class=")
buf.WriteString(strconv.Quote(f.Val))
case Style:
buf.WriteString("span style=")
buf.WriteString(strconv.Quote(f.Val))
}
buf.WriteByte('>')
}
}
// Implement the sort.Interface interface.
func (fs *formatState) Len() int { return len(*fs) }
func (fs *formatState) Less(i, j int) bool {
fsi, fsj := (*fs)[i], (*fs)[j]
// Formats that implement the FormatWrapper interface are written first.
if _, ok := fsi.fm.(FormatWrapper); ok {
return true
} else if _, ok := fsj.fm.(FormatWrapper); ok {
return false
}
// Tags are written first, then classes, and then style attributes.
if fsi.Place != fsj.Place {
return fsi.Place < fsj.Place
}
// Simply check values.
return fsi.Val < fsj.Val
}
func (fs *formatState) Swap(i, j int) {
(*fs)[i], (*fs)[j] = (*fs)[j], (*fs)[i]
}