fixed dependencies

This commit is contained in:
nuknal
2024-10-24 15:46:01 +08:00
parent d16a5bd9c0
commit 1161e8d054
2005 changed files with 690883 additions and 0 deletions

11
vendor/github.com/go-latex/latex/mtex/README.md generated vendored Normal file
View File

@@ -0,0 +1,11 @@
# mtex
`mtex` provides a Go implementation of a naive LaTeX-like math expression parser and renderer.
## Example
```
$> mtex-render -font-size=48 -dpi=100 "$\sum\sqrt{\frac{a+b}{2\pi}}\cos\omega\binom{a+b}{\beta}\prod \alpha x\int\frac{\partial x}{x}\hbar$"
```
![mtex-example](https://github.com/go-latex/latex/raw/master/mtex/testdata/mtex-example.png)

358
vendor/github.com/go-latex/latex/mtex/macros.go generated vendored Normal file
View File

@@ -0,0 +1,358 @@
// Copyright ©2020 The go-latex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mtex
import (
"strings"
"github.com/go-latex/latex/ast"
"github.com/go-latex/latex/tex"
)
type handlerFunc func(p *parser, node ast.Node, state tex.State, math bool) tex.Node
func (h handlerFunc) Handle(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
return h(p, node, state, math)
}
type handler interface {
Handle(p *parser, node ast.Node, state tex.State, math bool) tex.Node
}
var (
builtinMacros = map[string]handler{
// binary operators
`\amalg`: builtinMacro(""),
`\ast`: builtinMacro(""),
`\bigcirc`: builtinMacro(""),
`\bigtriangledown`: builtinMacro(""),
`\bigtriangleup`: builtinMacro(""),
`\bullet`: builtinMacro(""),
`\cdot`: builtinMacro(""),
`\circ`: builtinMacro(""),
`\cap`: builtinMacro(""),
`\cup`: builtinMacro(""),
`\dagger`: builtinMacro(""),
`\ddagger`: builtinMacro(""),
`\diamond`: builtinMacro(""),
`\div`: builtinMacro(""),
`\lhd`: builtinMacro(""),
`\mp`: builtinMacro(""),
`\odot`: builtinMacro(""),
`\ominus`: builtinMacro(""),
`\oplus`: builtinMacro(""),
`\oslash`: builtinMacro(""),
`\otimes`: builtinMacro(""),
`\pm`: builtinMacro(""),
`\rhd`: builtinMacro(""),
`\setminus`: builtinMacro(""),
`\sqcap`: builtinMacro(""),
`\sqcup`: builtinMacro(""),
`\star`: builtinMacro(""),
`\times`: builtinMacro(""),
`\triangleleft`: builtinMacro(""),
`\triangleright`: builtinMacro(""),
`\uplus`: builtinMacro(""),
`\unlhd`: builtinMacro(""),
`\unrhd`: builtinMacro(""),
`\vee`: builtinMacro(""),
`\wedge`: builtinMacro(""),
`\wr`: builtinMacro(""),
// arithmetic operators
`\binom`: builtinMacro("AA"),
`\dfrac`: builtinMacro("AA"),
`\frac`: builtinMacro("AA"),
`\stackrel`: builtinMacro("AA"),
`\tfrac`: builtinMacro("AA"),
`\genfrac`: nil, // FIXME(sbinet)
// relation symbols
`\approx`: builtinMacro(""),
`\asymp`: builtinMacro(""),
`\bowtie`: builtinMacro(""),
`\cong`: builtinMacro(""),
`\dashv`: builtinMacro(""),
`\doteq`: builtinMacro(""),
`\doteqdot`: builtinMacro(""),
`\dotplus`: builtinMacro(""),
`\dots`: builtinMacro(""),
`\equiv`: builtinMacro(""),
`\frown`: builtinMacro(""),
`\geq`: builtinMacro(""),
`\gg`: builtinMacro(""),
`\in`: builtinMacro(""),
`\leq`: builtinMacro(""),
`\ll`: builtinMacro(""),
`\mid`: builtinMacro(""),
`\models`: builtinMacro(""),
`\neq`: builtinMacro(""),
`\ni`: builtinMacro(""),
`\parallel`: builtinMacro(""),
`\perp`: builtinMacro(""),
`\prec`: builtinMacro(""),
`\preceq`: builtinMacro(""),
`\propto`: builtinMacro(""),
`\sim`: builtinMacro(""),
`\simeq`: builtinMacro(""),
`\smile`: builtinMacro(""),
`\sqsubset`: builtinMacro(""),
`\sqsubseteq`: builtinMacro(""),
`\sqsupset`: builtinMacro(""),
`\sqsupseteq`: builtinMacro(""),
`\subset`: builtinMacro(""),
`\subseteq`: builtinMacro(""),
`\succ`: builtinMacro(""),
`\succeq`: builtinMacro(""),
`\supset`: builtinMacro(""),
`\supseteq`: builtinMacro(""),
`\vdash`: builtinMacro(""),
`\Join`: builtinMacro(""),
// arrow symbols
`\downarrow`: builtinMacro(""),
`\hookleftarrow`: builtinMacro(""),
`\hookrightarrow`: builtinMacro(""),
`\leadsto`: builtinMacro(""),
`\leftarrow`: builtinMacro(""),
`\leftharpoondown`: builtinMacro(""),
`\leftharpoonup`: builtinMacro(""),
`\leftrightarrow`: builtinMacro(""),
`\longleftarrow`: builtinMacro(""),
`\longleftrightarrow`: builtinMacro(""),
`\longmapsto`: builtinMacro(""),
`\longrightarrow`: builtinMacro(""),
`\rightarrow`: builtinMacro(""),
`\mapsto`: builtinMacro(""),
`\nearrow`: builtinMacro(""),
`\nwarrow`: builtinMacro(""),
`\rightharpoondown`: builtinMacro(""),
`\rightharpoonup`: builtinMacro(""),
`\rightleftharpoons`: builtinMacro(""),
`\searrow`: builtinMacro(""),
`\swarrow`: builtinMacro(""),
`\uparrow`: builtinMacro(""),
`\updownarrow`: builtinMacro(""),
`\Downarrow`: builtinMacro(""),
`\Leftarrow`: builtinMacro(""),
`\Leftrightarrow`: builtinMacro(""),
`\Longleftarrow`: builtinMacro(""),
`\Longleftrightarrow`: builtinMacro(""),
`\Longrightarrow`: builtinMacro(""),
`\Rightarrow`: builtinMacro(""),
`\Uparrow`: builtinMacro(""),
`\Updownarrow`: builtinMacro(""),
// punctuation symbols
`\ldotp`: builtinMacro(""),
`\cdotp`: builtinMacro(""),
// over-under symbols
`\bigcap`: builtinMacro(""),
`\bigcup`: builtinMacro(""),
`\bigodot`: builtinMacro(""),
`\bigoplus`: builtinMacro(""),
`\bigotimes`: builtinMacro(""),
`\bigsqcup`: builtinMacro(""),
`\biguplus`: builtinMacro(""),
`\bigvee`: builtinMacro(""),
`\bigwedge`: builtinMacro(""),
`\coprod`: builtinMacro(""),
`\prod`: builtinMacro(""),
`\sum`: builtinMacro(""),
// over-under functions
`\lim`: builtinMacro(""),
`\liminf`: builtinMacro(""),
`\limsup`: builtinMacro(""),
`\max`: builtinMacro(""),
`\min`: builtinMacro(""),
`\sup`: builtinMacro(""),
// dropsub symbols
`\int`: builtinMacro(""),
`\oint`: builtinMacro(""),
// font names
`\rm`: builtinMacro(""),
`\cal`: builtinMacro(""),
`\it`: builtinMacro(""),
`\tt`: builtinMacro(""),
`\sf`: builtinMacro(""),
`\bf`: builtinMacro(""),
`\default`: builtinMacro(""),
`\bb`: builtinMacro(""),
`\frak`: builtinMacro(""),
`\scr`: builtinMacro(""),
`\regular`: builtinMacro(""),
// function names
`\arccos`: builtinMacro(""),
`\arcsin`: builtinMacro(""),
`\arctan`: builtinMacro(""),
`\arg`: builtinMacro(""),
`\cos`: builtinMacro(""),
`\cosh`: builtinMacro(""),
`\cot`: builtinMacro(""),
`\coth`: builtinMacro(""),
`\csc`: builtinMacro(""),
`\deg`: builtinMacro(""),
`\det`: builtinMacro(""),
`\dim`: builtinMacro(""),
`\exp`: builtinMacro("A"),
`\gcd`: builtinMacro(""),
`\hom`: builtinMacro(""),
`\inf`: builtinMacro(""),
`\ker`: builtinMacro(""),
`\lg`: builtinMacro(""),
`\ln`: builtinMacro(""),
`\log`: builtinMacro(""),
`\sec`: builtinMacro(""),
`\sin`: builtinMacro(""),
`\sinh`: builtinMacro(""),
`\sqrt`: builtinMacro("OA"),
`\tan`: builtinMacro(""),
`\tanh`: builtinMacro(""),
`\Pr`: builtinMacro(""),
// ambi delim
`\backslash`: builtinMacro(""),
`\vert`: builtinMacro(""),
`\Vert`: builtinMacro(""),
// left delim
`\{`: builtinMacro(""),
`\(`: builtinMacro(""),
`(`: builtinMacro(""),
`\langle`: builtinMacro(""),
`\lceil`: builtinMacro(""),
`\lfloor`: builtinMacro(""),
// right delim
`\}`: builtinMacro(""),
`\)`: builtinMacro(""),
`)`: builtinMacro(""),
`\rangle`: builtinMacro(""),
`\rceil`: builtinMacro(""),
`\rfloor`: builtinMacro(""),
// symbols
`\alpha`: builtinMacro(""),
`\beta`: builtinMacro(""),
`\gamma`: builtinMacro(""),
`\delta`: builtinMacro(""),
`\iota`: builtinMacro(""),
`\epsilon`: builtinMacro(""),
`\eta`: builtinMacro(""),
`\kappa`: builtinMacro(""),
`\lambda`: builtinMacro(""),
`\mu`: builtinMacro(""),
`\nu`: builtinMacro(""),
`\omicron`: builtinMacro(""),
`\pi`: builtinMacro(""),
`\theta`: builtinMacro(""),
`\xi`: builtinMacro(""),
`\rho`: builtinMacro(""),
`\sigma`: builtinMacro(""),
`\tau`: builtinMacro(""),
`\upsilon`: builtinMacro(""),
`\phi`: builtinMacro(""),
`\chi`: builtinMacro(""),
`\psi`: builtinMacro(""),
`\omega`: builtinMacro(""),
`\zeta`: builtinMacro(""),
`\Alpha`: builtinMacro(""),
`\Beta`: builtinMacro(""),
`\Gamma`: builtinMacro(""),
`\Delta`: builtinMacro(""),
`\Epsilon`: builtinMacro(""),
`\Zeta`: builtinMacro(""),
`\Eta`: builtinMacro(""),
`\Theta`: builtinMacro(""),
`\Iota`: builtinMacro(""),
`\Kappa`: builtinMacro(""),
`\Lambda`: builtinMacro(""),
`\Mu`: builtinMacro(""),
`\Nu`: builtinMacro(""),
`\Xi`: builtinMacro(""),
`\Omicron`: builtinMacro(""),
`\Pi`: builtinMacro(""),
`\Rho`: builtinMacro(""),
`\Sigma`: builtinMacro(""),
`\Tau`: builtinMacro(""),
`\Upsilon`: builtinMacro(""),
`\Phi`: builtinMacro(""),
`\Chi`: builtinMacro(""),
`\Psi`: builtinMacro(""),
`\Omega`: builtinMacro(""),
`\hbar`: builtinMacro(""),
`\nabla`: builtinMacro(""),
// math font
`\mathbf`: builtinMacro("A"),
`\mathit`: builtinMacro("A"),
`\mathsf`: builtinMacro("A"),
`\mathtt`: builtinMacro("A"),
`\mathcal`: builtinMacro("A"),
`\mathdefault`: builtinMacro("A"),
`\mathbb`: builtinMacro("A"),
`\mathfrak`: builtinMacro("A"),
`\mathscr`: builtinMacro("A"),
`\mathregular`: builtinMacro("A"),
// text
`\textbf`: builtinMacro("A"),
`\textit`: builtinMacro("A"),
`\textsf`: builtinMacro("A"),
`\texttt`: builtinMacro("A"),
`\textcal`: builtinMacro("A"),
`\textdefault`: builtinMacro("A"),
`\textbb`: builtinMacro("A"),
`\textfrak`: builtinMacro("A"),
`\textscr`: builtinMacro("A"),
`\textregular`: builtinMacro("A"),
// space, symbols
`\ `: builtinMacro(""),
`\,`: builtinMacro(""),
`\;`: builtinMacro(""),
`\!`: builtinMacro(""),
`\quad`: builtinMacro(""),
`\qquad`: builtinMacro(""),
`\:`: builtinMacro(""),
`\cdots`: builtinMacro(""),
`\ddots`: builtinMacro(""),
`\ldots`: builtinMacro(""),
`\vdots`: builtinMacro(""),
`\hspace`: builtinMacro("A"),
// catch-all
//
`\overline`: builtinMacro("A"),
`\operatorname`: builtinMacro("A"),
}
)
type builtinMacro string
func (m builtinMacro) Handle(p *parser, n ast.Node, state tex.State, math bool) tex.Node {
node := n.(*ast.Macro)
if m == "" {
return tex.NewChar(node.Name.Name, state, math)
}
for _, typ := range strings.ToLower(string(m)) {
switch typ {
case 'a':
panic("not implemented")
case 'o':
panic("not implemented")
case 'v':
panic("not implemented")
}
}
return nil
}

6
vendor/github.com/go-latex/latex/mtex/mtex.go generated vendored Normal file
View File

@@ -0,0 +1,6 @@
// Copyright ©2020 The go-latex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package mtex provides tools to render LaTeX math expressions.
package mtex

573
vendor/github.com/go-latex/latex/mtex/parser.go generated vendored Normal file
View File

@@ -0,0 +1,573 @@
// Copyright ©2020 The go-latex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mtex
import (
"fmt"
"math"
"strconv"
"strings"
"github.com/go-latex/latex"
"github.com/go-latex/latex/ast"
"github.com/go-latex/latex/font"
"github.com/go-latex/latex/internal/tex2unicode"
"github.com/go-latex/latex/mtex/symbols"
"github.com/go-latex/latex/tex"
)
// Parse parses a LaTeX math expression and returns the TeX-like box model
// and an error if any.
func Parse(expr string, fontSize, DPI float64, backend font.Backend) (tex.Node, error) {
p := newParser(backend)
return p.parse(expr, fontSize, DPI)
}
type parser struct {
be font.Backend
expr string
macros map[string]handler
}
func newParser(be font.Backend) *parser {
p := &parser{
be: be,
macros: make(map[string]handler),
}
p.init()
return p
}
func (p *parser) parse(x string, size, dpi float64) (tex.Node, error) {
p.expr = x
node, err := latex.ParseExpr(x)
if err != nil {
return nil, fmt.Errorf("could not parse latex expression %q: %w", x, err)
}
state := tex.NewState(p.be, font.Font{
Name: "default",
Size: size,
Type: "rm",
}, dpi)
v := visitor{p: p, state: state}
ast.Walk(&v, node)
nodes := tex.HListOf(v.nodes, true)
return nodes, nil
}
type visitor struct {
p *parser
nodes []tex.Node
state tex.State
math bool
}
func (v *visitor) Visit(n ast.Node) ast.Visitor {
switch n := n.(type) {
case ast.List:
case *ast.Symbol:
switch {
case v.math:
h := v.p.handler(n.Text)
if h == nil {
panic("no handler for symbol [" + n.Text + "]")
}
v.nodes = append(v.nodes, h.Handle(v.p, n, v.state, v.math))
default:
v.nodes = append(v.nodes, tex.NewChar(string(n.Text), v.state, v.math))
}
case *ast.Word:
var nodes []tex.Node
for _, x := range n.Text {
nodes = append(nodes, tex.NewChar(string(x), v.state, v.math))
}
v.nodes = append(v.nodes, tex.HListOf(nodes, true))
case *ast.Literal:
h := handlerFunc(handleSymbol)
for _, c := range n.Text {
n := &ast.Literal{Text: string(c)}
v.nodes = append(v.nodes, h.Handle(v.p, n, v.state, v.math))
}
case *ast.MathExpr:
oldm := v.math
oldt := v.state.Font.Type
v.math = true
v.state.Font.Type = rcparams("mathtext.default").(string)
for _, x := range n.List {
v.Visit(x)
}
v.math = oldm
v.state.Font.Type = oldt
return nil
case *ast.Macro:
if n.Name == nil {
panic("macro with nil identifier")
}
macro := n.Name.Name
h := v.p.handler(macro)
if h == nil {
panic(fmt.Errorf("unknown macro %q", macro))
}
v.nodes = append(v.nodes, h.Handle(v.p, n, v.state, v.math))
return nil
case nil:
return v
default:
panic(fmt.Errorf("unknown ast node %T", n))
}
return v
}
func (p *parser) handleNode(node ast.Node, state tex.State, math bool) tex.Node {
v := visitor{p: p, state: state, math: math}
ast.Walk(&v, node)
return tex.HListOf(v.nodes, true)
}
func (p *parser) handler(name string) handler {
if _, ok := spaceWidth[name]; ok {
return handlerFunc(handleSpace)
}
if symbols.IsSpaced(name) || symbols.PunctuationSymbols.Has(name) {
return handlerFunc(handleSymbol)
}
if name == `\hspace` {
return handlerFunc(handleCustomSpace)
}
if symbols.FunctionNames.Has(name[1:]) { // drop leading `\`
return handlerFunc(handleFunction)
}
switch name {
case `\frac`:
return handlerFunc(handleFrac)
case `\dfrac`:
return handlerFunc(handleDFrac)
case `\tfrac`:
return handlerFunc(handleTFrac)
case `\binom`:
return handlerFunc(handleBinom)
// case `\genfrac`:
// return handlerFunc(handleGenFrac)
case `\sqrt`:
return handlerFunc(handleSqrt)
case `\overline`:
return handlerFunc(handleOverline)
}
_, ok := p.macros[name]
if ok {
return handlerFunc(handleSymbol)
}
return nil
}
func (p *parser) init() {
for _, k := range tex2unicode.Symbols() {
p.macros[`\`+k] = builtinMacro("")
}
for k, v := range builtinMacros {
p.macros[k] = v
}
}
func handleSymbol(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
pos := int(node.Pos())
sym := ""
switch node := node.(type) {
case *ast.Macro:
sym = node.Name.Name
case *ast.Symbol:
sym = node.Text
case *ast.Word:
sym = node.Text
case *ast.Literal:
sym = node.Text
default:
panic("invalid ast Node")
}
ch := tex.NewChar(sym, state, math)
switch {
case symbols.IsSpaced(sym):
i := strings.LastIndexFunc(p.expr[:pos], func(r rune) bool {
return r != ' '
})
prev := ""
if i >= 0 {
prev = string(p.expr[i])
}
switch {
case symbols.BinaryOperators.Has(sym) && (len(strings.Split(p.expr[:pos], " ")) == 0 ||
prev == "{" ||
symbols.LeftDelim.Has(prev)):
// binary operators at start of string should not be spaced
return ch
default:
return tex.HListOf([]tex.Node{
p.makeSpace(state, 0.2),
ch,
p.makeSpace(state, 0.2),
}, true)
}
case symbols.PunctuationSymbols.Has(sym):
switch sym {
case ".":
pos := strings.Index(p.expr[pos:], sym)
if (pos > 0 && isdigit(p.expr[pos-1])) &&
(pos < len(p.expr)-1 && isdigit(p.expr[pos+1])) {
// do not space dots as decimal separators.
return ch
}
return tex.HListOf([]tex.Node{
ch,
p.makeSpace(state, 0.2),
}, true)
}
panic("not implemented")
}
return ch
}
var spaceWidth = map[string]float64{
`\,`: 0.16667, // 3/18 em = 3 mu
`\thinspace`: 0.16667, // 3/18 em = 3 mu
`\/`: 0.16667, // 3/18 em = 3 mu
`\>`: 0.22222, // 4/18 em = 4 mu
`\:`: 0.22222, // 4/18 em = 4 mu
`\;`: 0.27778, // 5/18 em = 5 mu
`\ `: 0.33333, // 6/18 em = 6 mu
`~`: 0.33333, // 6/18 em = 6 mu, nonbreakable
`\enspace`: 0.5, // 9/18 em = 9 mu
`\quad`: 1, // 1 em = 18 mu
`\qquad`: 2, // 2 em = 36 mu
`\!`: -0.16667, // -3/18 em = -3 mu
}
func handleSpace(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
var (
width float64
ok bool
)
switch node := node.(type) {
case *ast.Symbol:
width, ok = spaceWidth[node.Text]
case *ast.Macro:
width, ok = spaceWidth[node.Name.Name]
default:
panic(fmt.Errorf("invalid ast node %#v (%T)", node, node))
}
if !ok {
panic(fmt.Errorf("could not find a width for %#v (%T)", node, node))
}
return p.makeSpace(state, width)
}
func handleCustomSpace(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
macro := node.(*ast.Macro)
arg := macro.Args[0].(*ast.Arg).List[0].(*ast.Literal).Text
val, err := strconv.ParseFloat(arg, 64)
if err != nil {
panic(fmt.Errorf("could not parse customspace: %+v", err))
}
return p.makeSpace(state, val)
}
func handleFunction(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
macro := node.(*ast.Macro)
state.Font.Type = "rm"
fun := macro.Name.Name[1:] // drop leading `\`
nodes := make([]tex.Node, 0, len(fun))
for _, c := range fun {
nodes = append(nodes, tex.NewChar(string(c), state, math))
}
return tex.HListOf(nodes, true)
}
func handleFrac(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
var (
macro = node.(*ast.Macro)
thickness = state.Backend().UnderlineThickness(state.Font, state.DPI)
numNode = ast.List(macro.Args[0].(*ast.Arg).List)
denNode = ast.List(macro.Args[1].(*ast.Arg).List)
)
num := p.handleNode(numNode, state, math)
den := p.handleNode(denNode, state, math)
// FIXME(sbinet): this should be infered from the context.
// ie: textStyle when in $ $ environment.
// displayStyle when in \[\] environment.
sty := textStyle
return p.genfrac("", "", thickness, sty, num, den, state)
}
func handleDFrac(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
var (
macro = node.(*ast.Macro)
thickness = state.Backend().UnderlineThickness(state.Font, state.DPI)
numNode = ast.List(macro.Args[0].(*ast.Arg).List)
denNode = ast.List(macro.Args[1].(*ast.Arg).List)
)
num := p.handleNode(numNode, state, math)
den := p.handleNode(denNode, state, math)
return p.genfrac("", "", thickness, displayStyle, num, den, state)
}
func handleTFrac(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
var (
macro = node.(*ast.Macro)
thickness = state.Backend().UnderlineThickness(state.Font, state.DPI)
numNode = ast.List(macro.Args[0].(*ast.Arg).List)
denNode = ast.List(macro.Args[1].(*ast.Arg).List)
)
num := p.handleNode(numNode, state, math)
den := p.handleNode(denNode, state, math)
return p.genfrac("", "", thickness, textStyle, num, den, state)
}
func handleBinom(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
var (
macro = node.(*ast.Macro)
numNode = ast.List(macro.Args[0].(*ast.Arg).List)
denNode = ast.List(macro.Args[1].(*ast.Arg).List)
)
num := p.handleNode(numNode, state, math)
den := p.handleNode(denNode, state, math)
return p.genfrac("(", ")", 0, textStyle, num, den, state)
}
func (p *parser) genfrac(ldelim, rdelim string, rule float64, style mathStyleKind, num, den tex.Node, state tex.State) tex.Node {
thickness := state.Backend().UnderlineThickness(state.Font, state.DPI)
if style != displayStyle {
num.Shrink()
den.Shrink()
}
cnum := tex.HCentered([]tex.Node{num})
cden := tex.HCentered([]tex.Node{den})
width := math.Max(num.Width(), den.Width())
const additional = false // i.e.: exactly
cnum.HPack(width, additional)
cden.HPack(width, additional)
vlist := tex.VListOf([]tex.Node{
cnum, // numerator
tex.VBox(0, thickness*2), // space
tex.HRule(state, rule), // rule
tex.VBox(0, thickness*2), // space
cden, // denominator
})
// shift so the fraction line sits in the middle of the '=' sign
fnt := state.Font
fnt.Type = rcparams("mathtext.default").(string)
metrics := state.Backend().Metrics("=", fnt, state.DPI, true)
shift := cden.Height() - ((metrics.YMax+metrics.YMin)/2 - 3*thickness)
vlist.SetShift(shift)
box := tex.HListOf([]tex.Node{vlist, tex.HBox(2 * thickness)}, true)
if ldelim != "" || rdelim != "" {
if ldelim == "" {
ldelim = "."
}
if rdelim == "" {
rdelim = "."
}
return p.autoSizedDelimiter(ldelim, []tex.Node{box}, rdelim, state)
}
return box
}
func handleSqrt(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
var (
macro = node.(*ast.Macro)
root tex.Node
body *tex.HList
)
switch len(macro.Args) {
case 2:
root = p.handleNode(
ast.List(macro.Args[0].(*ast.OptArg).List),
state, math,
)
body = p.handleNode(
ast.List(macro.Args[1].(*ast.Arg).List),
state, math,
).(*tex.HList)
case 1:
// ok
body = p.handleNode(
ast.List(macro.Args[0].(*ast.Arg).List),
state, math,
).(*tex.HList)
default:
panic("invalid sqrt")
}
thickness := state.Backend().UnderlineThickness(state.Font, state.DPI)
// determine the height of the body, add a little extra to it so
// it doesn't seem too cramped.
height := body.Height() - body.Shift() + 5*thickness
depth := body.Depth() + body.Shift()
check := tex.AutoHeightChar(`\__sqrt__`, height, depth, state, 0)
height = check.Height() - check.Shift()
depth = check.Depth() + check.Shift()
// put a little extra space to the left and right of the body
padded := tex.HListOf([]tex.Node{
tex.HBox(2 * thickness),
body,
tex.HBox(2 * thickness),
}, true)
rhs := tex.VListOf([]tex.Node{
tex.HRule(state, -1),
tex.NewGlue("fill"),
padded,
})
// stretch the glue between the HRule and the body
const additional = false
rhs.VPack(height+(state.Font.Size*state.DPI)/(100*12), additional, depth)
// add the root and shift it upward so it is above the tick.
switch root {
case nil:
root = tex.HBox(check.Width() * 0.5)
default:
root.Shrink()
root.Shrink()
}
vl := tex.VListOf([]tex.Node{
tex.HListOf([]tex.Node{
root,
}, true),
})
vl.SetShift(-height * 0.6)
hl := tex.HListOf([]tex.Node{
vl, // root
// negative kerning to put root over tick
tex.NewKern(-check.Width() * 0.5),
check,
rhs,
}, true)
return hl
}
func handleOverline(p *parser, node ast.Node, state tex.State, math bool) tex.Node {
macro := node.(*ast.Macro)
body := p.handleNode(
ast.List(macro.Args[0].(*ast.Arg).List),
state, math,
).(*tex.HList)
thickness := state.Backend().UnderlineThickness(state.Font, state.DPI)
height := body.Height() - body.Shift() + 3*thickness
depth := body.Depth() + body.Shift()
// place overline above body
rhs := tex.VListOf([]tex.Node{
tex.HRule(state, -1),
tex.NewGlue("fill"),
tex.HListOf([]tex.Node{body}, true),
})
// stretch the glue between the HRule and the body
const additional = false
rhs.VPack(height+(state.Font.Size*state.DPI)/(100*12), additional, depth)
hl := tex.HListOf([]tex.Node{rhs}, true)
return hl
}
func (p *parser) makeSpace(state tex.State, percentage float64) *tex.Kern {
const math = true
fnt := state.Font
fnt.Name = "it"
fnt.Type = rcparams("mathtext.default").(string)
width := p.be.Metrics("m", fnt, state.DPI, math).Advance
return tex.NewKern(width * percentage)
}
func (p *parser) autoSizedDelimiter(left string, middle []tex.Node, right string, state tex.State) tex.Node {
var (
height float64
depth float64
factor float64 = 1
)
if len(middle) > 0 {
for _, node := range middle {
height = math.Max(height, node.Height())
depth = math.Max(depth, node.Depth())
}
factor = 0
}
var parts []tex.Node
if left != "." {
// \left. isn't supposed to produce any symbol
ahc := tex.AutoHeightChar(left, height, depth, state, factor)
parts = append(parts, ahc)
}
parts = append(parts, middle...)
if right != "." {
// \right. isn't supposed to produce any symbol
ahc := tex.AutoHeightChar(right, height, depth, state, factor)
parts = append(parts, ahc)
}
return tex.HListOf(parts, true)
}
type mathStyleKind int
const (
displayStyle mathStyleKind = iota
textStyle
//scriptStyle // FIXME
//scriptScriptStyle // FIXME
)
func rcparams(k string) interface{} {
switch k {
case "mathtext.default":
return "it"
default:
panic("unknown rc.params key [" + k + "]")
}
}
func isdigit(v byte) bool {
switch v {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return true
}
return false
}

50
vendor/github.com/go-latex/latex/mtex/render.go generated vendored Normal file
View File

@@ -0,0 +1,50 @@
// Copyright ©2020 The go-latex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mtex
import (
"fmt"
"math"
"github.com/go-latex/latex/drawtex"
"github.com/go-latex/latex/font/ttf"
"github.com/go-latex/latex/tex"
)
type Renderer interface {
Render(w, h, dpi float64, cnv *drawtex.Canvas) error
}
func Render(dst Renderer, expr string, size, dpi float64, fonts *ttf.Fonts) error {
var (
canvas = drawtex.New()
backend *ttf.Backend
)
switch fonts {
case nil:
backend = ttf.New(canvas)
default:
backend = ttf.NewFrom(canvas, fonts)
}
box, err := Parse(expr, size, 72, backend)
if err != nil {
return fmt.Errorf("could not parse math expression: %w", err)
}
var sh tex.Ship
sh.Call(0, 0, box.(tex.Tree))
w := box.Width()
h := box.Height()
d := box.Depth()
err = dst.Render(w/72, math.Ceil(h+math.Max(d, 0))/72, dpi, canvas)
if err != nil {
return fmt.Errorf("could not render math expression: %w", err)
}
return nil
}

43
vendor/github.com/go-latex/latex/mtex/symbols/set.go generated vendored Normal file
View File

@@ -0,0 +1,43 @@
// Copyright ©2020 The go-latex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package symbols
import (
"sort"
)
type Set map[string]struct{}
func NewSet(vs ...string) Set {
o := make(Set, len(vs))
for _, k := range vs {
o[k] = struct{}{}
}
return o
}
func (set Set) Has(k string) bool {
_, ok := set[k]
return ok
}
func (set Set) Keys() []string {
keys := make([]string, 0, len(set))
for k := range set {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
func UnionOf(sets ...Set) Set {
o := make(Set, len(sets))
for _, set := range sets {
for k := range set {
o[k] = struct{}{}
}
}
return o
}

View File

@@ -0,0 +1,16 @@
// Copyright ©2020 The go-latex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package symbols contains logic about TeX symbols.
package symbols // import "github.com/go-latex/latex/mtex/symbols"
//go:generate go run ./gen-symbols.go
var (
SpacedSymbols = UnionOf(BinaryOperators, RelationSymbols, ArrowSymbols)
)
func IsSpaced(s string) bool {
return SpacedSymbols.Has(s)
}

View File

@@ -0,0 +1,254 @@
// Autogenerated. DO NOT EDIT.
package symbols
var (
AmbiDelim = NewSet(
"\\downarrow",
"\\Uparrow",
"\\|",
"\\updownarrow",
"\\vert",
"\\Vert",
"\\backslash",
".",
"\\Updownarrow",
"/",
"\\Downarrow",
"|",
"\\\\|",
"\\uparrow",
)
ArrowSymbols = NewSet(
"\\Uparrow",
"\\searrow",
"\\hookleftarrow",
"\\longleftrightarrow",
"\\longrightarrow",
"\\rightarrow",
"\\leadsto",
"\\nearrow",
"\\Updownarrow",
"\\rightharpoonup",
"\\Longrightarrow",
"\\leftrightarrow",
"\\downarrow",
"\\nwarrow",
"\\leftarrow",
"\\leftharpoondown",
"\\swarrow",
"\\Longleftarrow",
"\\Leftarrow",
"\\Longleftrightarrow",
"\\uparrow",
"\\hookrightarrow",
"\\rightleftharpoons",
"\\mapsto",
"\\Leftrightarrow",
"\\leftharpoonup",
"\\rightharpoondown",
"\\updownarrow",
"\\Rightarrow",
"\\longleftarrow",
"\\Downarrow",
"\\longmapsto",
)
BinaryOperators = NewSet(
"\\triangleleft",
"\\cup",
"+",
"\\oplus",
"*",
"\\bullet",
"\\star",
"\\diamond",
"\\div",
"\\bigtriangledown",
"\\unrhd",
"\\wr",
"\\bigtriangleup",
"\\sqcup",
"\\vee",
"\\sqcap",
"\\dagger",
"\\cdot",
"\\unlhd",
"\\triangleright",
"\\ddagger",
"\\amalg",
"\\circ",
"\\odot",
"\\cap",
"\\bigcirc",
"\\lhd",
"\\times",
"-",
"\\wedge",
"\\mp",
"\\otimes",
"\\ominus",
"\\ast",
"\\pm",
"\\oslash",
"\\rhd",
"\\setminus",
"\\uplus",
)
DropSubSymbols = NewSet(
"\\oint",
"\\int",
)
FontNames = NewSet(
"circled",
"default",
"cal",
"bf",
"regular",
"tt",
"scr",
"sf",
"frak",
"rm",
"it",
"bb",
)
FunctionNames = NewSet(
"lim",
"arccos",
"min",
"arcsin",
"gcd",
"arctan",
"sup",
"sec",
"max",
"cos",
"deg",
"arg",
"sin",
"log",
"sinh",
"ker",
"liminf",
"coth",
"exp",
"det",
"ln",
"lg",
"Pr",
"tan",
"tanh",
"csc",
"hom",
"cosh",
"cot",
"dim",
"limsup",
"inf",
)
LeftDelim = NewSet(
"\\lfloor",
"<",
"\\{",
"\\langle",
"[",
"(",
"\\lceil",
)
OverUnderFunctions = NewSet(
"sup",
"max",
"lim",
"limsup",
"min",
"liminf",
)
OverUnderSymbols = NewSet(
"\\biguplus",
"\\bigoplus",
"\\prod",
"\\bigcap",
"\\bigsqcup",
"\\bigodot",
"\\bigvee",
"\\bigwedge",
"\\sum",
"\\bigcup",
"\\coprod",
"\\bigotimes",
)
PunctuationSymbols = NewSet(
"!",
";",
"\\cdotp",
",",
".",
"\\ldotp",
)
RelationSymbols = NewSet(
"\\ni",
"\\leq",
"\\ll",
"\\supseteq",
"\\succ",
"=",
"\\neq",
"\\parallel",
"\\geq",
"\\prec",
"\\frown",
"\\in",
"\\Join",
"\\sqsubset",
"\\dashv",
"\\vdash",
"\\dots",
"\\asymp",
"\\subset",
"\\subseteq",
"\\sqsupseteq",
"<",
"\\models",
"\\bowtie",
"\\equiv",
":",
"\\sqsupset",
"\\smile",
"\\propto",
"\\dotplus",
"\\preceq",
"\\cong",
"\\simeq",
">",
"\\mid",
"\\approx",
"\\supset",
"\\gg",
"\\doteq",
"\\sqsubseteq",
"\\doteqdot",
"\\succeq",
"\\perp",
"\\sim",
)
RightDelim = NewSet(
"\\rceil",
"]",
"\\rangle",
">",
"\\}",
"\\rfloor",
")",
)
)