github.com/cozy/cozy-stack@v0.0.0-20240327093429-939e4a21320e/model/note/custom/span.go (about)

     1  package custom
     2  
     3  import (
     4  	"github.com/yuin/goldmark/ast"
     5  	"github.com/yuin/goldmark/parser"
     6  	"github.com/yuin/goldmark/text"
     7  )
     8  
     9  // A Span struct represents a span of text with attributes.
    10  type Span struct {
    11  	ast.BaseInline
    12  	Value string
    13  }
    14  
    15  // Dump implements Node.Dump.
    16  func (n *Span) Dump(source []byte, level int) {
    17  	ast.DumpHelper(n, source, level, nil, nil)
    18  }
    19  
    20  // KindSpan is a NodeKind of the Span node.
    21  var KindSpan = ast.NewNodeKind("Span")
    22  
    23  // Kind implements Node.Kind.
    24  func (n *Span) Kind() ast.NodeKind {
    25  	return KindSpan
    26  }
    27  
    28  // NewSpan returns a new Span node.
    29  func NewSpan(value string) *Span {
    30  	return &Span{
    31  		BaseInline: ast.BaseInline{},
    32  		Value:      value,
    33  	}
    34  }
    35  
    36  type spanParser struct{}
    37  
    38  var defaultSpanParser = &spanParser{}
    39  
    40  // NewSpanParser returns a new InlineParser that can parse spans with
    41  // attributes, like [foo bar]{.myClass}.
    42  // See https://talk.commonmark.org/t/consistent-attribute-syntax/272.
    43  // This parser must take precedence over the parser.LinkParser.
    44  func NewSpanParser() parser.InlineParser {
    45  	return defaultSpanParser
    46  }
    47  
    48  func (s *spanParser) Trigger() []byte {
    49  	return []byte{'['}
    50  }
    51  
    52  func (s *spanParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node {
    53  	line, _ := block.PeekLine()
    54  	for pos := 1; pos < len(line); pos++ {
    55  		if line[pos] == ']' {
    56  			pos++
    57  			if pos >= len(line) || line[pos] != '{' {
    58  				return nil
    59  			}
    60  			block.Advance(pos)
    61  			span := NewSpan(string(line[1 : pos-1]))
    62  			if attrs, ok := parser.ParseAttributes(block); ok {
    63  				for _, attr := range attrs {
    64  					if value, ok := attr.Value.([]byte); ok {
    65  						span.SetAttribute(attr.Name, string(value))
    66  					} else {
    67  						span.SetAttribute(attr.Name, attr.Value)
    68  					}
    69  				}
    70  			}
    71  			return span
    72  		}
    73  	}
    74  	return nil
    75  }
    76  
    77  func (s *spanParser) CloseBlock(parent ast.Node, pc parser.Context) {
    78  	// nothing to do
    79  }