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  )