github.com/SuCicada/su-hugo@v1.0.0/parser/pageparser/item.go (about) 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 import ( 17 "bytes" 18 "fmt" 19 "regexp" 20 "strconv" 21 22 "github.com/yuin/goldmark/util" 23 ) 24 25 type lowHigh struct { 26 Low int 27 High int 28 } 29 30 type Item struct { 31 Type ItemType 32 Err error 33 34 // The common case is a single segment. 35 low int 36 high int 37 38 // This is the uncommon case. 39 segments []lowHigh 40 41 // Used for validation. 42 firstByte byte 43 44 isString bool 45 } 46 47 type Items []Item 48 49 func (i Item) Pos() int { 50 if len(i.segments) > 0 { 51 return i.segments[0].Low 52 } 53 return i.low 54 } 55 56 func (i Item) Val(source []byte) []byte { 57 if len(i.segments) == 0 { 58 return source[i.low:i.high] 59 } 60 61 if len(i.segments) == 1 { 62 return source[i.segments[0].Low:i.segments[0].High] 63 } 64 65 var b bytes.Buffer 66 for _, s := range i.segments { 67 b.Write(source[s.Low:s.High]) 68 } 69 return b.Bytes() 70 } 71 72 func (i Item) ValStr(source []byte) string { 73 return string(i.Val(source)) 74 } 75 76 func (i Item) ValTyped(source []byte) any { 77 str := i.ValStr(source) 78 if i.isString { 79 // A quoted value that is a string even if it looks like a number etc. 80 return str 81 } 82 83 if boolRe.MatchString(str) { 84 return str == "true" 85 } 86 87 if intRe.MatchString(str) { 88 num, err := strconv.Atoi(str) 89 if err != nil { 90 return str 91 } 92 return num 93 } 94 95 if floatRe.MatchString(str) { 96 num, err := strconv.ParseFloat(str, 64) 97 if err != nil { 98 return str 99 } 100 return num 101 } 102 103 return str 104 } 105 106 func (i Item) IsText() bool { 107 return i.Type == tText || i.Type == tIndentation 108 } 109 110 func (i Item) IsIndentation() bool { 111 return i.Type == tIndentation 112 } 113 114 func (i Item) IsNonWhitespace(source []byte) bool { 115 return len(bytes.TrimSpace(i.Val(source))) > 0 116 } 117 118 func (i Item) IsShortcodeName() bool { 119 return i.Type == tScName 120 } 121 122 func (i Item) IsInlineShortcodeName() bool { 123 return i.Type == tScNameInline 124 } 125 126 func (i Item) IsLeftShortcodeDelim() bool { 127 return i.Type == tLeftDelimScWithMarkup || i.Type == tLeftDelimScNoMarkup 128 } 129 130 func (i Item) IsRightShortcodeDelim() bool { 131 return i.Type == tRightDelimScWithMarkup || i.Type == tRightDelimScNoMarkup 132 } 133 134 func (i Item) IsShortcodeClose() bool { 135 return i.Type == tScClose 136 } 137 138 func (i Item) IsShortcodeParam() bool { 139 return i.Type == tScParam 140 } 141 142 func (i Item) IsShortcodeParamVal() bool { 143 return i.Type == tScParamVal 144 } 145 146 func (i Item) IsShortcodeMarkupDelimiter() bool { 147 return i.Type == tLeftDelimScWithMarkup || i.Type == tRightDelimScWithMarkup 148 } 149 150 func (i Item) IsFrontMatter() bool { 151 return i.Type >= TypeFrontMatterYAML && i.Type <= TypeFrontMatterORG 152 } 153 154 func (i Item) IsDone() bool { 155 return i.Type == tError || i.Type == tEOF 156 } 157 158 func (i Item) IsEOF() bool { 159 return i.Type == tEOF 160 } 161 162 func (i Item) IsError() bool { 163 return i.Type == tError 164 } 165 166 func (i Item) ToString(source []byte) string { 167 val := i.Val(source) 168 switch { 169 case i.Type == tEOF: 170 return "EOF" 171 case i.Type == tError: 172 return string(val) 173 case i.Type == tIndentation: 174 return fmt.Sprintf("%s:[%s]", i.Type, util.VisualizeSpaces(val)) 175 case i.Type > tKeywordMarker: 176 return fmt.Sprintf("<%s>", val) 177 case len(val) > 50: 178 return fmt.Sprintf("%v:%.20q...", i.Type, val) 179 } 180 return fmt.Sprintf("%v:[%s]", i.Type, val) 181 } 182 183 type ItemType int 184 185 const ( 186 tError ItemType = iota 187 tEOF 188 189 // page items 190 TypeLeadSummaryDivider // <!--more-->, # more 191 TypeFrontMatterYAML 192 TypeFrontMatterTOML 193 TypeFrontMatterJSON 194 TypeFrontMatterORG 195 TypeEmoji 196 TypeIgnore // // The BOM Unicode byte order marker and possibly others 197 198 // shortcode items 199 tLeftDelimScNoMarkup 200 tRightDelimScNoMarkup 201 tLeftDelimScWithMarkup 202 tRightDelimScWithMarkup 203 tScClose 204 tScName 205 tScNameInline 206 tScParam 207 tScParamVal 208 209 tIndentation 210 211 tText // plain text 212 213 // preserved for later - keywords come after this 214 tKeywordMarker 215 ) 216 217 var ( 218 boolRe = regexp.MustCompile(`^(true|false)$`) 219 intRe = regexp.MustCompile(`^[-+]?\d+$`) 220 floatRe = regexp.MustCompile(`^[-+]?\d*\.\d+$`) 221 )