package tex
import (
"math"
"github.com/d2lang/mathjax-go/internal/mml"
)
func limitsCore(n *mml .Node ) *mml .Node {
for n != nil {
index := 0
switch n .Kind {
case "mrow" :
if !n .Flags .Embellished {
return n
}
index = n .Flags .CoreIndex
case "msub" , "msup" , "msubsup" , "munder" , "mover" , "munderover" , "mmultiscripts" , "TeXAtom" , "mstyle" , "mpadded" , "mphantom" , "semantics" , "mfrac" , "math" , "mtd" :
case "maction" :
value , exists := n .Attributes .Get ("selection" )
selection := limitsSelection (value , exists )
selected := math .Max (1 , math .Min (float64 (len (n .Children )), selection )) - 1
if math .IsNaN (selected ) || selected != math .Trunc (selected ) || selected < 0 || selected >= float64 (len (n .Children )) || n .Children [int (selected )] == nil {
return texMMLFactory .Create ("mrow" )
}
index = int (selected )
default :
return n
}
if index < 0 || index >= len (n .Children ) || n .Children [index ] == nil {
return n
}
n = n .Children [index ]
}
return nil
}
func (p *parser ) setLimits (nodes []*mml .Node , name string ) ([]*mml .Node , error ) {
var op *mml .Node
if len (nodes ) != 0 {
op = nodes [len (nodes )-1 ]
}
core := limitsCore (op )
var moves any
if op != nil {
moves , _ = op .Property ("movesupsub" )
}
if op == nil || core == nil || (core .TeXClass != mml .TeXClassOp && moves == nil ) {
return nil , texError ("MisplacedLimits" , "%s is allowed only on operators" , "\\" +name )
}
enabled := name == "limits"
kind := ""
switch op .Kind {
case "munder" , "mover" , "munderover" :
if !enabled {
kind = "msubsup"
}
case "msub" , "msup" , "msubsup" , "mmultiscripts" :
if enabled {
kind = "munderover"
}
}
if kind != "" {
multiscripts := op .Kind == "mmultiscripts"
replacement := texMMLFactory .Create (kind )
replacement .SetChildren (op .Children )
refreshDynamicFlags (replacement )
if multiscripts {
replacement .SetProperty (poppedScriptOrigin , true )
p .notePoppedScript (replacement )
}
op = replacement
nodes [len (nodes )-1 ] = op
}
op .SetProperty ("movesupsub" , enabled )
applySourceObject (limitsCore (op ), mjSourceObject {{Name : "movablelimits" , Value : false }})
attr , _ := op .Attributes .Get ("movablelimits" )
prop , _ := op .Property ("movablelimits" )
if limitsTruthy (attr ) || limitsTruthy (prop ) {
applySourceObject (op , mjSourceObject {{Name : "movablelimits" , Value : false }})
}
return nodes , nil
}
func limitsTruthy(value any ) bool {
switch v := value .(type ) {
case nil :
return false
case bool :
return v
case string :
return v != ""
case int :
return v != 0
case int64 :
return v != 0
case float64 :
return v != 0 && v == v
default :
return true
}
}
func limitsSelection(value any , exists bool ) float64 {
return mml .MactionSelectionNumber (value , exists )
}
const limitsScriptOrigin = "_texLimitsScriptOrigin"
func (p *parser ) parseLimits (nodes []*mml .Node , name string ) ([]*mml .Node , error ) {
if len (nodes ) != 0 {
op := nodes [len (nodes )-1 ]
if origin , _ := op .Property (limitsScriptOrigin ); origin == true && len (op .Children ) == 2 {
children := []*mml .Node {op .Children [0 ], op .Children [1 ]}
switch op .Kind {
case "msub" , "munder" :
children = append (children , nil )
case "msup" , "mover" :
children = []*mml .Node {op .Children [0 ], nil , op .Children [1 ]}
default :
children = nil
}
if children != nil {
if op .Kind == "msub" || op .Kind == "msup" {
op .Kind = "msubsup"
} else {
op .Kind = "munderover"
}
op .Flags .Arity = 3
op .SetChildren (children )
refreshDynamicFlags (op )
}
}
}
result , err := p .setLimits (nodes , name )
if err != nil {
return nil , err
}
op := result [len (result )-1 ]
if op .Kind == "msubsup" || op .Kind == "munderover" {
var under , over *mml .Node
if len (op .Children ) > 1 {
under = op .Children [1 ]
}
if len (op .Children ) > 2 {
over = op .Children [2 ]
}
if len (op .Children ) > 0 && (under == nil || over == nil ) && (under != nil || over != nil ) {
mark := under
if under == nil {
mark = over
}
kind := "msub"
if op .Kind == "munderover" {
kind = "munder"
}
if under == nil {
if kind == "msub" {
kind = "msup"
} else {
kind = "mover"
}
}
op .Kind = kind
op .Flags .Arity = 2
op .SetChildren ([]*mml .Node {op .Children [0 ], mark })
refreshDynamicFlags (op )
op .SetProperty (limitsScriptOrigin , true )
}
}
return result , nil
}
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 .