package markup
import (
"fmt"
"html"
"strings"
)
// HyphaExists holds function that checks that a hypha is present.
var HyphaExists func(string) bool
//
var HyphaImageForOG func(string) string
// HyphaAccess holds function that accesses a hypha by its name.
var HyphaAccess func(string) (rawText, binaryHtml string, err error)
// HyphaIterate is a function that iterates all hypha names existing.
var HyphaIterate func(func(string))
// GemLexerState is used by markup parser to remember what is going on.
type GemLexerState struct {
// Name of hypha being parsed
name string
where string // "", "list", "pre"
// Line id
id int
buf string
// Temporaries
img *Img
}
type Line struct {
id int
// interface{} may be bad. TODO: a proper type
contents interface{}
}
func (md *MycoDoc) lex() (ast []Line) {
var state = GemLexerState{name: md.hyphaName}
for _, line := range append(strings.Split(md.contents, "\n"), "") {
lineToAST(line, &state, &ast)
}
return ast
}
// Lex `line` in markup and save it to `ast` using `state`.
func lineToAST(line string, state *GemLexerState, ast *[]Line) {
addLine := func(text interface{}) {
*ast = append(*ast, Line{id: state.id, contents: text})
}
// Process empty lines depending on the current state
if "" == strings.TrimSpace(line) {
switch state.where {
case "list":
state.where = ""
addLine(state.buf + "")
case "number":
state.where = ""
addLine(state.buf + "")
case "pre":
state.buf += "\n"
case "launchpad":
state.where = ""
addLine(state.buf + "")
}
return
}
startsWith := func(token string) bool {
return strings.HasPrefix(line, token)
}
addHeading := func(i int) {
addLine(fmt.Sprintf("
", state.id, strings.TrimPrefix(line, "```"))
default:
state.where = ""
addLine(state.buf + "")
goto normalState
}
return
numberState:
switch {
case startsWith("*. "):
state.buf += fmt.Sprintf("\t%s \n", ParagraphToHtml(state.name, line[3:]))
case startsWith("```"):
state.where = "pre"
addLine(state.buf + "")
state.id++
state.buf = fmt.Sprintf("", state.id, strings.TrimPrefix(line, "```"))
default:
state.where = ""
addLine(state.buf + "")
goto normalState
}
return
launchpadState:
switch {
case startsWith("=>"):
href, text, class, icon := Rocketlink(line, state.name)
state.buf += fmt.Sprintf(` %s%s `, class, href, text, icon)
case startsWith("```"):
state.where = "pre"
addLine(state.buf + "")
state.id++
state.buf = fmt.Sprintf("", state.id, strings.TrimPrefix(line, "```"))
default:
state.where = ""
addLine(state.buf + "")
goto normalState
}
return
normalState:
state.id++
switch {
case startsWith("```"):
state.where = "pre"
state.buf = fmt.Sprintf("", state.id, strings.TrimPrefix(line, "```"))
case startsWith("* "):
state.where = "list"
state.buf = fmt.Sprintf("\n", state.id)
goto listState
case startsWith("*. "):
state.where = "number"
state.buf = fmt.Sprintf("\n", state.id)
goto numberState
case startsWith("###### "):
addHeading(6)
case startsWith("##### "):
addHeading(5)
case startsWith("#### "):
addHeading(4)
case startsWith("### "):
addHeading(3)
case startsWith("## "):
addHeading(2)
case startsWith("# "):
addHeading(1)
case startsWith(">"):
addLine(fmt.Sprintf(
"%s
", state.id, remover(">")(line)))
case startsWith("=>"):
state.where = "launchpad"
state.buf = fmt.Sprintf("\n", state.id)
goto launchpadState
case startsWith("<="):
addLine(parseTransclusion(line, state.name))
case line == "----":
*ast = append(*ast, Line{id: -1, contents: "
"})
case MatchesImg(line):
img, shouldGoBackToNormal := ImgFromFirstLine(line, state.name)
if shouldGoBackToNormal {
addLine(*img)
} else {
state.where = "img"
state.img = img
}
default:
addLine(fmt.Sprintf("%s
", state.id, ParagraphToHtml(state.name, line)))
}
}