1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 19:56:16 +00:00
mycorrhiza/gemtext/xclusion.go
2020-08-05 20:08:59 +05:00

107 lines
3.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package gemtext
import (
"fmt"
"path"
"strconv"
"strings"
)
const xclError = -9
// Transclusion is used by gemtext parser to remember what hyphae shall be transcluded.
type Transclusion struct {
name string
from int // inclusive
to int // inclusive
}
// Transclude transcludes `xcl` and returns html representation.
func Transclude(xcl Transclusion, state GemParserState) (html string) {
state.recursionLevel++
tmptOk := `<section class="transclusion transclusion_ok">
<a class="transclusion__link" href="/page/%s">%s</a>
<div class="transclusion__content">%s</div>
</section>`
tmptFailed := `<section class="transclusion transclusion_failed">
<p>Failed to transclude <a href="/page/%s">%s</a></p>
</section>`
if xcl.from == xclError || xcl.to == xclError || xcl.from > xcl.to {
return fmt.Sprintf(tmptFailed, xcl.name, xcl.name)
}
rawText, binaryHtml, err := HyphaAccess(xcl.name)
if err != nil {
return fmt.Sprintf(tmptFailed, xcl.name, xcl.name)
}
xclText := Parse(lex(xcl.name, rawText), xcl.from, xcl.to, state)
return fmt.Sprintf(tmptOk, xcl.name, xcl.name, binaryHtml+xclText)
}
/* Grammar from hypha transclusion:
transclusion_line ::= transclusion_token hypha_name LWS* [":" LWS* range LWS*]
transclusion_token ::= "<=" LWS+
hypha_name ::= canonical_name | noncanonical_name
range ::= id | (from_id two_dots to_id) | (from_id two_dots) | (two_dots to_id)
two_dots ::= ".."
*/
func parseTransclusion(line, hyphaName string) (xclusion Transclusion) {
line = strings.TrimSpace(remover("<=")(line))
if line == "" {
return Transclusion{"", xclError, xclError}
}
if strings.ContainsRune(line, ':') {
parts := strings.SplitN(line, ":", 2)
xclusion.name = xclCanonicalName(hyphaName, strings.TrimSpace(parts[0]))
selector := strings.TrimSpace(parts[1])
xclusion.from, xclusion.to = parseSelector(selector)
} else {
xclusion.name = xclCanonicalName(hyphaName, strings.TrimSpace(line))
}
return xclusion
}
func xclCanonicalName(hyphaName, xclName string) string {
switch {
case strings.HasPrefix(xclName, "./"):
return canonicalName(path.Join(hyphaName, strings.TrimPrefix(xclName, "./")))
case strings.HasPrefix(xclName, "../"):
return canonicalName(path.Join(path.Dir(hyphaName), strings.TrimPrefix(xclName, "../")))
default:
return canonicalName(xclName)
}
}
// At this point:
// selector ::= id
// | from ".."
// | from ".." to
// | ".." to
// If it is not, return (xclError, xclError).
func parseSelector(selector string) (from, to int) {
if selector == "" {
return 0, 0
}
if strings.Contains(selector, "..") {
parts := strings.Split(selector, "..")
var (
fromStr = strings.TrimSpace(parts[0])
from, fromErr = strconv.Atoi(fromStr)
toStr = strings.TrimSpace(parts[1])
to, toErr = strconv.Atoi(toStr)
)
if fromStr == "" && toStr == "" {
return 0, 0
}
if fromErr == nil || toErr == nil {
return from, to
}
} else if id, err := strconv.Atoi(selector); err == nil {
return id, id
}
return xclError, xclError
}