package mml
import (
"fmt"
"github.com/d2lang/mathjax-go/internal/ordered"
)
type TeXClass int8
const (
TeXClassNone TeXClass = -1
TeXClassOrd TeXClass = 0
TeXClassOp TeXClass = 1
TeXClassBin TeXClass = 2
TeXClassRel TeXClass = 3
TeXClassOpen TeXClass = 4
TeXClassClose TeXClass = 5
TeXClassPunct TeXClass = 6
TeXClassInner TeXClass = 7
TeXClassVCenter TeXClass = 8
)
var TeXClassNames = [...]string {
"ORD" , "OP" , "BIN" , "REL" , "OPEN" , "CLOSE" , "PUNCT" , "INNER" , "VCENTER" ,
}
var texSpaceLength = [...]string {"" , "thinmathspace" , "mediummathspace" , "thickmathspace" }
var texSpace = [8 ][8 ]int8 {
{0 , -1 , 2 , 3 , 0 , 0 , 0 , 1 },
{-1 , -1 , 0 , 3 , 0 , 0 , 0 , 1 },
{2 , 2 , 0 , 0 , 2 , 0 , 0 , 2 },
{3 , 3 , 0 , 0 , 3 , 0 , 0 , 3 },
{0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{0 , -1 , 2 , 3 , 0 , 0 , 0 , 1 },
{1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 },
{1 , -1 , 2 , 3 , 1 , 0 , 1 , 1 },
}
func TeXSpacing (left , right TeXClass , script bool ) string {
if left < TeXClassOrd || left > TeXClassInner || right < TeXClassOrd || right > TeXClassInner {
return ""
}
space := texSpace [left ][right ]
if script && space >= 0 {
return ""
}
if space < 0 {
space = -space
}
return texSpaceLength [space ]
}
type Flags struct {
Token bool
Embellished bool
Spacelike bool
LinebreakContainer bool
HasNewline bool
Inferred bool
NotParent bool
Arity int
CoreIndex int
}
type FencedNodes struct {
Open, Close *Node
Separators []*Node
}
type Node struct {
Kind string
Parent *Node
Children []*Node
Attributes *Attributes
Properties *ordered .Map [Property ]
Text string
Flags Flags
TeXClass TeXClass
PrevClass TeXClass
PrevLevel int
Fenced *FencedNodes
OperatorLspace, OperatorRspace float64
}
func NewNode (kind string , defaults , global *ordered .Map [Property ], children ...*Node ) *Node {
n := &Node {
Kind : kind ,
Attributes : NewAttributes (defaults , global ),
Properties : ordered .New [Property ](),
TeXClass : TeXClassNone ,
PrevClass : TeXClassNone ,
}
if kind == "mo" {
n .OperatorLspace , n .OperatorRspace = 5.0 /18 , 5.0 /18
}
n .SetChildren (children )
return n
}
func NewText (text string ) *Node {
n := NewNode ("text" , nil , nil )
n .Text = text
return n
}
func (n *Node ) IsKind (kind string ) bool { return n != nil && n .Kind == kind }
func (n *Node ) SetProperty (name string , value Property ) { n .Properties .Set (name , value ) }
func (n *Node ) Property (name string ) (Property , bool ) { return n .Properties .Get (name ) }
func (n *Node ) RemoveProperty (name string ) bool { return n .Properties .Delete (name ) }
func (n *Node ) SetChildren (children []*Node ) {
for _ , child := range n .Children {
if child != nil && child .Parent == n {
child .Parent = nil
}
}
n .Children = append (n .Children [:0 ], children ...)
for _ , child := range n .Children {
if child != nil {
child .Parent = n
}
}
}
func (n *Node ) AppendChild (child *Node ) *Node {
if child != nil {
child .Parent = n
}
n .Children = append (n .Children , child )
return child
}
func (n *Node ) ChildIndex (child *Node ) int {
for i , candidate := range n .Children {
if candidate == child {
return i
}
}
return -1
}
func (n *Node ) ReplaceChild (newChild , oldChild *Node ) error {
i := n .ChildIndex (oldChild )
if i < 0 {
return fmt .Errorf ("mml: child is not present in %s" , n .Kind )
}
if oldChild != nil && oldChild .Parent == n {
oldChild .Parent = nil
}
if newChild != nil {
newChild .Parent = n
}
n .Children [i ] = newChild
return nil
}
func (n *Node ) RemoveChild (child *Node ) error {
i := n .ChildIndex (child )
if i < 0 {
return fmt .Errorf ("mml: child is not present in %s" , n .Kind )
}
if child != nil && child .Parent == n {
child .Parent = nil
}
copy (n .Children [i :], n .Children [i +1 :])
n .Children [len (n .Children )-1 ] = nil
n .Children = n .Children [:len (n .Children )-1 ]
return nil
}
func (n *Node ) ParentNode () *Node {
parent := n .Parent
for parent != nil && (parent .Flags .Inferred || parent .Flags .NotParent ) {
parent = parent .Parent
}
return parent
}
func (n *Node ) Core () *Node {
if n == nil || !n .Flags .Embellished || n .Flags .CoreIndex < 0 || n .Flags .CoreIndex >= len (n .Children ) {
return n
}
return n .Children [n .Flags .CoreIndex ]
}
func (n *Node ) CoreMO () *Node {
current := n
for current != nil && current .Flags .Embellished {
next := current .Core ()
if next == current {
break
}
current = next
}
return current
}
func (n *Node ) Walk (visit func (*Node ) bool ) {
if n == nil || !visit (n ) {
return
}
for _ , child := range n .Children {
child .Walk (visit )
}
}
func (n *Node ) Find (kind string ) []*Node {
var found []*Node
n .Walk (func (node *Node ) bool {
if node .Kind == kind {
found = append (found , node )
}
return true
})
return found
}
func (n *Node ) Clone () *Node {
if n == nil {
return nil
}
clone := &Node {
Kind : n .Kind ,
Attributes : n .Attributes .Clone (),
Properties : n .Properties .Clone (),
Text : n .Text ,
Flags : n .Flags ,
TeXClass : n .TeXClass ,
PrevClass : n .PrevClass ,
PrevLevel : n .PrevLevel ,
OperatorLspace : n .OperatorLspace ,
OperatorRspace : n .OperatorRspace ,
}
children := make ([]*Node , len (n .Children ))
for i , child := range n .Children {
children [i ] = child .Clone ()
}
clone .SetChildren (children )
if n .Fenced != nil {
clone .Fenced = &FencedNodes {Open : n .Fenced .Open .Clone (), Close : n .Fenced .Close .Clone ()}
for _ , separator := range n .Fenced .Separators {
clone .Fenced .Separators = append (clone .Fenced .Separators , separator .Clone ())
}
for _ , fake := range append ([]*Node {clone .Fenced .Open , clone .Fenced .Close }, clone .Fenced .Separators ...) {
if fake != nil {
fake .Parent = clone
}
}
}
return clone
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .