forked from lug/matterbridge
		
	
		
			
				
	
	
		
			117 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package parser
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 
 | |
| 	"github.com/gomarkdown/markdown/ast"
 | |
| )
 | |
| 
 | |
| // attribute parses a (potential) block attribute and adds it to p.
 | |
| func (p *Parser) attribute(data []byte) []byte {
 | |
| 	if len(data) < 3 {
 | |
| 		return data
 | |
| 	}
 | |
| 	i := 0
 | |
| 	if data[i] != '{' {
 | |
| 		return data
 | |
| 	}
 | |
| 	i++
 | |
| 
 | |
| 	// last character must be a } otherwise it's not an attribute
 | |
| 	end := skipUntilChar(data, i, '\n')
 | |
| 	if data[end-1] != '}' {
 | |
| 		return data
 | |
| 	}
 | |
| 
 | |
| 	i = skipSpace(data, i)
 | |
| 	b := &ast.Attribute{Attrs: make(map[string][]byte)}
 | |
| 
 | |
| 	esc := false
 | |
| 	quote := false
 | |
| 	trail := 0
 | |
| Loop:
 | |
| 	for ; i < len(data); i++ {
 | |
| 		switch data[i] {
 | |
| 		case ' ', '\t', '\f', '\v':
 | |
| 			if quote {
 | |
| 				continue
 | |
| 			}
 | |
| 			chunk := data[trail+1 : i]
 | |
| 			if len(chunk) == 0 {
 | |
| 				trail = i
 | |
| 				continue
 | |
| 			}
 | |
| 			switch {
 | |
| 			case chunk[0] == '.':
 | |
| 				b.Classes = append(b.Classes, chunk[1:])
 | |
| 			case chunk[0] == '#':
 | |
| 				b.ID = chunk[1:]
 | |
| 			default:
 | |
| 				k, v := keyValue(chunk)
 | |
| 				if k != nil && v != nil {
 | |
| 					b.Attrs[string(k)] = v
 | |
| 				} else {
 | |
| 					// this is illegal in an attribute
 | |
| 					return data
 | |
| 				}
 | |
| 			}
 | |
| 			trail = i
 | |
| 		case '"':
 | |
| 			if esc {
 | |
| 				esc = !esc
 | |
| 				continue
 | |
| 			}
 | |
| 			quote = !quote
 | |
| 		case '\\':
 | |
| 			esc = !esc
 | |
| 		case '}':
 | |
| 			if esc {
 | |
| 				esc = !esc
 | |
| 				continue
 | |
| 			}
 | |
| 			chunk := data[trail+1 : i]
 | |
| 			if len(chunk) == 0 {
 | |
| 				return data
 | |
| 			}
 | |
| 			switch {
 | |
| 			case chunk[0] == '.':
 | |
| 				b.Classes = append(b.Classes, chunk[1:])
 | |
| 			case chunk[0] == '#':
 | |
| 				b.ID = chunk[1:]
 | |
| 			default:
 | |
| 				k, v := keyValue(chunk)
 | |
| 				if k != nil && v != nil {
 | |
| 					b.Attrs[string(k)] = v
 | |
| 				} else {
 | |
| 					return data
 | |
| 				}
 | |
| 			}
 | |
| 			i++
 | |
| 			break Loop
 | |
| 		default:
 | |
| 			esc = false
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	p.attr = b
 | |
| 	return data[i:]
 | |
| }
 | |
| 
 | |
| // key="value" quotes are mandatory.
 | |
| func keyValue(data []byte) ([]byte, []byte) {
 | |
| 	chunk := bytes.SplitN(data, []byte{'='}, 2)
 | |
| 	if len(chunk) != 2 {
 | |
| 		return nil, nil
 | |
| 	}
 | |
| 	key := chunk[0]
 | |
| 	value := chunk[1]
 | |
| 
 | |
| 	if len(value) < 3 || len(key) == 0 {
 | |
| 		return nil, nil
 | |
| 	}
 | |
| 	if value[0] != '"' || value[len(value)-1] != '"' {
 | |
| 		return key, nil
 | |
| 	}
 | |
| 	return key, value[1 : len(value)-1]
 | |
| }
 | 
