pagelexer_intro.go (3813B)
1 // Copyright 2018 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package pageparser
15
16 func lexIntroSection(l *pageLexer) stateFunc {
17 l.summaryDivider = summaryDivider
18
19 LOOP:
20 for {
21 r := l.next()
22 if r == eof {
23 break
24 }
25
26 switch {
27 case r == '+':
28 return l.lexFrontMatterSection(TypeFrontMatterTOML, r, "TOML", delimTOML)
29 case r == '-':
30 return l.lexFrontMatterSection(TypeFrontMatterYAML, r, "YAML", delimYAML)
31 case r == '{':
32 return lexFrontMatterJSON
33 case r == '#':
34 return lexFrontMatterOrgMode
35 case r == byteOrderMark:
36 l.emit(TypeIgnore)
37 case !isSpace(r) && !isEndOfLine(r):
38 if r == '<' {
39 l.backup()
40 if l.hasPrefix(htmlCommentStart) {
41 // This may be commented out front matter, which should
42 // still be read.
43 l.consumeToNextLine()
44 l.isInHTMLComment = true
45 l.emit(TypeIgnore)
46 continue LOOP
47 } else {
48 return l.errorf("plain HTML documents not supported")
49 }
50 }
51 break LOOP
52 }
53 }
54
55 // Now move on to the shortcodes.
56 return lexMainSection
57 }
58
59 func lexEndFrontMatterHTMLComment(l *pageLexer) stateFunc {
60 l.isInHTMLComment = false
61 right := l.index(htmlCommentEnd)
62 if right == -1 {
63 return l.errorf("starting HTML comment with no end")
64 }
65 l.pos += right + len(htmlCommentEnd)
66 l.emit(TypeIgnore)
67
68 // Now move on to the shortcodes.
69 return lexMainSection
70 }
71
72 func lexFrontMatterJSON(l *pageLexer) stateFunc {
73 // Include the left delimiter
74 l.backup()
75
76 var (
77 inQuote bool
78 level int
79 )
80
81 for {
82
83 r := l.next()
84
85 switch {
86 case r == eof:
87 return l.errorf("unexpected EOF parsing JSON front matter")
88 case r == '{':
89 if !inQuote {
90 level++
91 }
92 case r == '}':
93 if !inQuote {
94 level--
95 }
96 case r == '"':
97 inQuote = !inQuote
98 case r == '\\':
99 // This may be an escaped quote. Make sure it's not marked as a
100 // real one.
101 l.next()
102 }
103
104 if level == 0 {
105 break
106 }
107 }
108
109 l.consumeCRLF()
110 l.emit(TypeFrontMatterJSON)
111
112 return lexMainSection
113 }
114
115 func lexFrontMatterOrgMode(l *pageLexer) stateFunc {
116 /*
117 #+TITLE: Test File For chaseadamsio/goorgeous
118 #+AUTHOR: Chase Adams
119 #+DESCRIPTION: Just another golang parser for org content!
120 */
121
122 l.summaryDivider = summaryDividerOrg
123
124 l.backup()
125
126 if !l.hasPrefix(delimOrg) {
127 return lexMainSection
128 }
129
130 // Read lines until we no longer see a #+ prefix
131 LOOP:
132 for {
133
134 r := l.next()
135
136 switch {
137 case r == '\n':
138 if !l.hasPrefix(delimOrg) {
139 break LOOP
140 }
141 case r == eof:
142 break LOOP
143
144 }
145 }
146
147 l.emit(TypeFrontMatterORG)
148
149 return lexMainSection
150 }
151
152 // Handle YAML or TOML front matter.
153 func (l *pageLexer) lexFrontMatterSection(tp ItemType, delimr rune, name string, delim []byte) stateFunc {
154 for i := 0; i < 2; i++ {
155 if r := l.next(); r != delimr {
156 return l.errorf("invalid %s delimiter", name)
157 }
158 }
159
160 // Let front matter start at line 1
161 wasEndOfLine := l.consumeCRLF()
162 // We don't care about the delimiters.
163 l.ignore()
164
165 var r rune
166
167 for {
168 if !wasEndOfLine {
169 r = l.next()
170 if r == eof {
171 return l.errorf("EOF looking for end %s front matter delimiter", name)
172 }
173 }
174
175 if wasEndOfLine || isEndOfLine(r) {
176 if l.hasPrefix(delim) {
177 l.emit(tp)
178 l.pos += 3
179 l.consumeCRLF()
180 l.ignore()
181 break
182 }
183 }
184
185 wasEndOfLine = false
186 }
187
188 return lexMainSection
189 }