Get inline stuff kinda working
I think I'll have to sort out delimiters or something...gross
This commit is contained in:
parent
7268b6011a
commit
9e353c715f
Binary file not shown.
|
@ -104,15 +104,19 @@ func extract(re *regexp.Regexp, src []byte, subexpName string) []byte {
|
||||||
return m[re.SubexpIndex(subexpName)]
|
return m[re.SubexpIndex(subexpName)]
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractMap(re *regexp.Regexp, src []byte, subexpNames ...string) map[string][]byte {
|
func extractMap(re *regexp.Regexp, src []byte) map[string][]byte {
|
||||||
m := re.FindSubmatch(src)
|
m := re.FindSubmatch(src)
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
res := make(map[string][]byte)
|
res := make(map[string][]byte)
|
||||||
for _, name := range subexpNames {
|
for _, name := range re.SubexpNames() {
|
||||||
res[name] = m[re.SubexpIndex(name)]
|
if name != "" {
|
||||||
|
i := re.SubexpIndex(name)
|
||||||
|
res[name] = m[i]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
res["all"] = m[0]
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,15 +128,22 @@ func extractAll(re *regexp.Regexp, src []byte, subexpName string) [][]byte {
|
||||||
return m[re.SubexpIndex(subexpName)]
|
return m[re.SubexpIndex(subexpName)]
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractAllMap(re *regexp.Regexp, src []byte, subexpNames ...string) map[string][][]byte {
|
func extractAllMap(re *regexp.Regexp, src []byte) map[string][][]byte {
|
||||||
m := re.FindAllSubmatch(src, -1)
|
m := re.FindAllSubmatch(src, -1)
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
res := make(map[string][][]byte)
|
res := make(map[string][][]byte)
|
||||||
for _, name := range subexpNames {
|
for i, name := range re.SubexpNames() {
|
||||||
res[name] = m[re.SubexpIndex(name)]
|
if name != "" {
|
||||||
|
var vals [][]byte
|
||||||
|
for _, specificMatch := range m {
|
||||||
|
vals = append(vals, specificMatch[i])
|
||||||
|
}
|
||||||
|
res[name] = vals
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
res["all"] = m[0]
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@ package parsing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
|
"git.handmade.network/hmn/hmn/src/hmnurl"
|
||||||
"github.com/yuin/goldmark"
|
"github.com/yuin/goldmark"
|
||||||
"github.com/yuin/goldmark/ast"
|
"github.com/yuin/goldmark/ast"
|
||||||
gast "github.com/yuin/goldmark/ast"
|
gast "github.com/yuin/goldmark/ast"
|
||||||
|
@ -38,6 +40,19 @@ import (
|
||||||
type ggcodeRenderer = func(w util.BufWriter, n *ggcodeNode, entering bool) error
|
type ggcodeRenderer = func(w util.BufWriter, n *ggcodeNode, entering bool) error
|
||||||
|
|
||||||
var ggcodeTags = map[string]ggcodeRenderer{
|
var ggcodeTags = map[string]ggcodeRenderer{
|
||||||
|
"glossary": func(w util.BufWriter, n *ggcodeNode, entering bool) error {
|
||||||
|
if entering {
|
||||||
|
term, _ := n.Args["term"]
|
||||||
|
w.WriteString(fmt.Sprintf(
|
||||||
|
`<a href="%s" class="glossary-term" data-term="%s">`,
|
||||||
|
hmnurl.BuildEducationGlossary(term),
|
||||||
|
term,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
w.WriteString("</a>")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
"resource": func(w util.BufWriter, n *ggcodeNode, entering bool) error {
|
"resource": func(w util.BufWriter, n *ggcodeNode, entering bool) error {
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteString("a node :o")
|
w.WriteString("a node :o")
|
||||||
|
@ -53,25 +68,28 @@ var ggcodeTags = map[string]ggcodeRenderer{
|
||||||
// ----------------------
|
// ----------------------
|
||||||
|
|
||||||
var reGGCodeBlockOpen = regexp.MustCompile(`^!!!(?P<name>[a-zA-Z0-9-_]+)(\{(?P<args>.*?)\})?$`)
|
var reGGCodeBlockOpen = regexp.MustCompile(`^!!!(?P<name>[a-zA-Z0-9-_]+)(\{(?P<args>.*?)\})?$`)
|
||||||
var reGGCodeBlockArgs = regexp.MustCompile(`(?P<arg>[a-zA-Z0-9-_]+)="(?P<val>.*?)"`)
|
var reGGCodeInline = regexp.MustCompile(`^!!(?P<name>[a-zA-Z0-9-_]+)(\{(?P<args>.*?)\})?(\((?P<content>.*?)\))?`)
|
||||||
|
var reGGCodeArgs = regexp.MustCompile(`(?P<arg>[a-zA-Z0-9-_]+)="(?P<val>.*?)"`)
|
||||||
|
|
||||||
type ggcodeParserBlock struct {
|
// Block parser stuff
|
||||||
|
|
||||||
|
type ggcodeBlockParser struct {
|
||||||
Preview bool
|
Preview bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ parser.BlockParser = ggcodeParserBlock{}
|
var _ parser.BlockParser = ggcodeBlockParser{}
|
||||||
|
|
||||||
func (s ggcodeParserBlock) Trigger() []byte {
|
func (s ggcodeBlockParser) Trigger() []byte {
|
||||||
return []byte("!!!")
|
return []byte("!")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s ggcodeParserBlock) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) {
|
func (s ggcodeBlockParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) {
|
||||||
restOfLine, _ := reader.PeekLine()
|
restOfLine, _ := reader.PeekLine()
|
||||||
|
|
||||||
if match := extractMap(reGGCodeBlockOpen, bytes.TrimSpace(restOfLine), "name", "args"); match != nil {
|
if match := extractMap(reGGCodeBlockOpen, bytes.TrimSpace(restOfLine)); match != nil {
|
||||||
name := string(match["name"])
|
name := string(match["name"])
|
||||||
var args map[string]string
|
var args map[string]string
|
||||||
if argsMatch := extractAllMap(reGGCodeBlockArgs, match["args"]); argsMatch != nil {
|
if argsMatch := extractAllMap(reGGCodeArgs, match["args"]); argsMatch != nil {
|
||||||
args = make(map[string]string)
|
args = make(map[string]string)
|
||||||
for i := range argsMatch["arg"] {
|
for i := range argsMatch["arg"] {
|
||||||
arg := string(argsMatch["arg"][i])
|
arg := string(argsMatch["arg"][i])
|
||||||
|
@ -90,7 +108,7 @@ func (s ggcodeParserBlock) Open(parent ast.Node, reader text.Reader, pc parser.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s ggcodeParserBlock) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State {
|
func (s ggcodeBlockParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State {
|
||||||
line, _ := reader.PeekLine()
|
line, _ := reader.PeekLine()
|
||||||
if string(bytes.TrimSpace(line)) == "!!!" {
|
if string(bytes.TrimSpace(line)) == "!!!" {
|
||||||
reader.Advance(3)
|
reader.Advance(3)
|
||||||
|
@ -99,16 +117,80 @@ func (s ggcodeParserBlock) Continue(node ast.Node, reader text.Reader, pc parser
|
||||||
return parser.Continue | parser.HasChildren
|
return parser.Continue | parser.HasChildren
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s ggcodeParserBlock) Close(node ast.Node, reader text.Reader, pc parser.Context) {}
|
func (s ggcodeBlockParser) Close(node ast.Node, reader text.Reader, pc parser.Context) {}
|
||||||
|
|
||||||
func (s ggcodeParserBlock) CanInterruptParagraph() bool {
|
func (s ggcodeBlockParser) CanInterruptParagraph() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s ggcodeParserBlock) CanAcceptIndentedLine() bool {
|
func (s ggcodeBlockParser) CanAcceptIndentedLine() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inline parser stuff
|
||||||
|
|
||||||
|
type ggcodeInlineParser struct {
|
||||||
|
Preview bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ parser.InlineParser = ggcodeInlineParser{}
|
||||||
|
|
||||||
|
func (s ggcodeInlineParser) Trigger() []byte {
|
||||||
|
return []byte("!()")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ggcodeInlineParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node {
|
||||||
|
restOfLine, segment := block.PeekLine() // Gets the rest of the line (starting at the current parser cursor index), and the segment representing the indices in the source text.
|
||||||
|
if match := extractMap(reGGCodeInline, restOfLine); match != nil {
|
||||||
|
name := string(match["name"])
|
||||||
|
var args map[string]string
|
||||||
|
if argsMatch := extractAllMap(reGGCodeArgs, match["args"]); argsMatch != nil {
|
||||||
|
args = make(map[string]string)
|
||||||
|
for i := range argsMatch["arg"] {
|
||||||
|
arg := string(argsMatch["arg"][i])
|
||||||
|
val := string(argsMatch["val"][i])
|
||||||
|
args[arg] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node := &ggcodeNode{
|
||||||
|
Name: name,
|
||||||
|
Args: args,
|
||||||
|
}
|
||||||
|
contentLength := len(match["content"])
|
||||||
|
if contentLength > 0 {
|
||||||
|
contentSegmentStart := segment.Start + len(match["all"]) - (contentLength + 1) // the 1 is for the end parenthesis
|
||||||
|
contentSegmentEnd := contentSegmentStart + contentLength
|
||||||
|
contentSegment := text.NewSegment(contentSegmentStart, contentSegmentEnd)
|
||||||
|
node.AppendChild(node, ast.NewTextSegment(contentSegment))
|
||||||
|
}
|
||||||
|
|
||||||
|
block.Advance(len(match["all"]))
|
||||||
|
return node
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ggcodeDelimiterParser struct {
|
||||||
|
Node *ggcodeNode // We need to pass this through 🙄
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p ggcodeDelimiterParser) IsDelimiter(b byte) bool {
|
||||||
|
fmt.Println("delmit", string(b))
|
||||||
|
return b == '(' || b == ')'
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p ggcodeDelimiterParser) CanOpenCloser(opener, closer *parser.Delimiter) bool {
|
||||||
|
fmt.Println("oopen")
|
||||||
|
return opener.Char == '(' && closer.Char == ')'
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p ggcodeDelimiterParser) OnMatch(consumes int) gast.Node {
|
||||||
|
fmt.Println("out!")
|
||||||
|
return p.Node
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------
|
// ----------------------
|
||||||
// AST node
|
// AST node
|
||||||
// ----------------------
|
// ----------------------
|
||||||
|
@ -180,7 +262,10 @@ type ggcodeExtension struct {
|
||||||
|
|
||||||
func (e ggcodeExtension) Extend(m goldmark.Markdown) {
|
func (e ggcodeExtension) Extend(m goldmark.Markdown) {
|
||||||
m.Parser().AddOptions(parser.WithBlockParsers(
|
m.Parser().AddOptions(parser.WithBlockParsers(
|
||||||
util.Prioritized(ggcodeParserBlock{Preview: e.Preview}, 500),
|
util.Prioritized(ggcodeBlockParser{Preview: e.Preview}, 500),
|
||||||
|
))
|
||||||
|
m.Parser().AddOptions(parser.WithInlineParsers(
|
||||||
|
util.Prioritized(ggcodeInlineParser{Preview: e.Preview}, 500),
|
||||||
))
|
))
|
||||||
m.Renderer().AddOptions(renderer.WithNodeRenderers(
|
m.Renderer().AddOptions(renderer.WithNodeRenderers(
|
||||||
util.Prioritized(newGGCodeHTMLRenderer(), 500),
|
util.Prioritized(newGGCodeHTMLRenderer(), 500),
|
||||||
|
|
Loading…
Reference in New Issue