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

41
vendor/github.com/go-latex/latex/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,41 @@
sudo: false
go_import_path: github.com/go-latex/latex
language: go
go:
- 1.14.x
- 1.13.x
- master
os:
- linux
arch:
- amd64
env:
global:
- GO111MODULE=on
- GOFLAGS="-mod=readonly"
cache:
directories:
- $HOME/.cache/go-build
- $HOME/gopath/pkg/mod
git:
depth: 1
autocrlf: input
matrix:
fast_finish: true
allow_failures:
- go: master
script:
- go install -v ./...
- go run ./ci/run-tests.go -coverpkg=github.com/go-latex/latex/... -race
after_success:
- bash <(curl -s https://codecov.io/bash)

12
vendor/github.com/go-latex/latex/AUTHORS generated vendored Normal file
View File

@@ -0,0 +1,12 @@
# This is the official list of go-latex authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as
# Name or Organization <email address>
# The email address is not required for organizations.
# Please keep the list sorted.
Google Inc
Sebastien Binet <seb.binet@gmail.com>

19
vendor/github.com/go-latex/latex/CONTRIBUTORS generated vendored Normal file
View File

@@ -0,0 +1,19 @@
# This is the official list of people who can contribute
# (and typically have contributed) code to the go-latex
# project.
#
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees would be listed here
# but not in AUTHORS, because Google would hold the copyright.
#
# When adding J Random Contributor's name to this file,
# either J's name or J's organization's name should be
# added to the AUTHORS file.
#
# Names should be added to this file like so:
# Name <email address>
#
# Please keep the list sorted.
Dan Lorenc <lorenc.d@gmail.com>
Sebastien Binet <seb.binet@gmail.com>

23
vendor/github.com/go-latex/latex/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,23 @@
Copyright ©2020 The go-latex Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the go-latex project nor the names of its authors and
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

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

@@ -0,0 +1,74 @@
# latex
[![go.dev reference](https://pkg.go.dev/badge/github.com/go-latex/latex)](https://pkg.go.dev/github.com/go-latex/latex)
[![GitHub release](https://img.shields.io/github/release/go-latex/latex.svg)](https://github.com/go-latex/latex/releases)
[![CI](https://github.com/go-latex/latex/workflows/CI/badge.svg)](https://github.com/go-latex/latex/actions)
[![codecov](https://codecov.io/gh/go-latex/latex/branch/master/graph/badge.svg)](https://codecov.io/gh/go-latex/latex)
[![GoDoc](https://godoc.org/github.com/go-latex/latex?status.svg)](https://godoc.org/github.com/go-latex/latex)
[![License](https://img.shields.io/badge/License-BSD--3-blue.svg)](https://github.com/go-latex/latex/raw/master/LICENSE)
`latex` is a package holding Go tools for [LaTeX](https://www.latex-project.org/).
`latex` is supposed to provide features akin to `MathJax` or `matplotlib`'s `TeX` capabilities.
_ie:_ it is supposed to be able to draw mathematical equations, in pure-Go.
`latex` is *NOT SUPPOSED* to be a complete typesetting system like `LaTeX` or `TeX`.
For this, please take look at:
- [Star-TeX](https://star-tex.org)
- [Star-TeX (git repo)](https://git.sr.ht/~sbinet/star-tex)
Eventually, `go-latex/latex` might just use `star-tex.org/...` to provide the `MathJax`-like capabilities.
(once `star-tex.org/...` is ready and exports a nice Go API.)
## Installation
```
$> go get github.com/go-latex/latex/...
```
## Documentation
Documentation is served by [godoc](https://godoc.org), here:
- [godoc.org/github.com/go-latex/latex](https://godoc.org/github.com/go-latex/latex)
The main use case for `go-latex/latex` is to draw a mathematical equation.
This is typically achieved via the `latex/mtex.Render` function that knows how to render mathematical `TeX` equations to a renderer interface.
### Example
```go
package main
import (
"os"
"github.com/go-latex/latex/drawtex/drawimg"
"github.com/go-latex/latex/mtex"
)
func main() {
f, err := os.Create("output.png")
if err != nil {
panic(err)
}
defer f.Close()
dst := drawimg.NewRenderer(f)
err = mtex.Render(dst, `$f(x) = \frac{\sqrt{x +20}}{2\pi} +\hbar \sum y\partial y$`, 12, 72, nil)
if err != nil {
panic(err)
}
err = f.Close()
if err != nil {
panic(err)
}
}
```
## LICENSE
BSD-3.

266
vendor/github.com/go-latex/latex/ast/ast.go generated vendored Normal file
View File

@@ -0,0 +1,266 @@
// 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 ast declares the types used to represent syntax trees for
// LaTeX documents.
package ast // import "github.com/go-latex/latex/ast"
import (
"fmt"
"io"
"github.com/go-latex/latex/token"
)
// Node is a node in a LaTeX document.
type Node interface {
Pos() token.Pos // position of first character belonging to the node.
End() token.Pos // position of first character immediately after the node.
isNode()
}
// List is a collection of nodes.
type List []Node
func (x List) isNode() {}
func (x List) Pos() token.Pos {
if len(x) == 0 {
return -1
}
return x[0].Pos()
}
func (x List) End() token.Pos {
if len(x) == 0 {
return -1
}
return x[len(x)-1].End()
}
// Macro is a LaTeX macro.
// ex:
// \sqrt{a}
// \frac{num}{den}
type Macro struct {
Name *Ident
Args List
}
func (x *Macro) isNode() {}
func (x *Macro) Pos() token.Pos { return x.Name.Pos() }
func (x *Macro) End() token.Pos {
if len(x.Args) > 0 {
return x.Args[len(x.Args)-1].End()
}
return x.Name.End()
}
// Arg is an argument of a macro.
// ex:
// {a} in \sqrt{a}
type Arg struct {
Lbrace token.Pos // position of '{'
List List // or stmt?
Rbrace token.Pos // position of '}'
}
func (x *Arg) Pos() token.Pos { return x.Lbrace }
func (x *Arg) End() token.Pos { return x.Rbrace }
func (x *Arg) isNode() {}
// OptArg is an optional argument of a macro
// ex:
// [n] in \sqrt[n]{a}
type OptArg struct {
Lbrack token.Pos // position of '['
List List
Rbrack token.Pos // position of ']'
}
func (x *OptArg) Pos() token.Pos { return x.Lbrack }
func (x *OptArg) End() token.Pos { return x.Rbrack }
func (x *OptArg) isNode() {}
type Ident struct {
NamePos token.Pos // identifier position
Name string // identifier name
}
func (x *Ident) Pos() token.Pos { return x.NamePos }
func (x *Ident) End() token.Pos { return token.Pos(int(x.NamePos) + len(x.Name)) }
func (x *Ident) isNode() {}
// MathExpr is a math expression.
// ex:
// $f(x) \doteq \sqrt[n]{x}$
// \[ x^n + y^n = z^n \]
type MathExpr struct {
Delim string // delimiter used for this math expression.
Left token.Pos // position of opening '$', '\(', '\[' or '\begin{math}'
List List
Right token.Pos // position of closing '$', '\)', '\]' or '\end{math}'
}
func (x *MathExpr) isNode() {}
func (x *MathExpr) Pos() token.Pos { return x.Left }
func (x *MathExpr) End() token.Pos { return x.Right }
type Word struct {
WordPos token.Pos
Text string
}
func (x *Word) isNode() {}
func (x *Word) Pos() token.Pos { return x.WordPos }
func (x *Word) End() token.Pos { return token.Pos(int(x.WordPos) + len(x.Text)) }
type Literal struct {
LitPos token.Pos
Text string
}
func (x *Literal) isNode() {}
func (x *Literal) Pos() token.Pos { return x.LitPos }
func (x *Literal) End() token.Pos { return token.Pos(int(x.LitPos) + len(x.Text)) }
type Symbol struct {
SymPos token.Pos
Text string
}
func (x *Symbol) isNode() {}
func (x *Symbol) Pos() token.Pos { return x.SymPos }
func (x *Symbol) End() token.Pos { return token.Pos(int(x.SymPos) + len(x.Text)) }
// Sub is a subscript node.
//
// e.g.: \sum_{i=0}
type Sub struct {
UnderPos token.Pos
Node Node
}
func (x *Sub) isNode() {}
func (x *Sub) Pos() token.Pos { return x.UnderPos }
func (x *Sub) End() token.Pos { return x.Node.End() }
// Sup is a superscript node.
//
// e.g.: \sum^{n}
type Sup struct {
HatPos token.Pos
Node Node
}
func (x *Sup) isNode() {}
func (x *Sup) Pos() token.Pos { return x.HatPos }
func (x *Sup) End() token.Pos { return x.Node.End() }
// Print prints node to w.
func Print(o io.Writer, node Node) {
switch node := node.(type) {
case *Arg:
fmt.Fprintf(o, "{")
for i, n := range node.List {
if i > 0 {
fmt.Fprintf(o, ", ")
}
Print(o, n)
}
fmt.Fprintf(o, "}")
case *Ident:
fmt.Fprintf(o, "ast.Ident{%q}", node.Name)
case *Macro:
fmt.Fprintf(o, "ast.Macro{%q", node.Name.Name)
switch len(node.Args) {
case 0:
// no-op
default:
fmt.Fprintf(o, ", Args:")
for i, n := range node.Args {
if i > 0 {
fmt.Fprintf(o, ", ")
}
Print(o, n)
}
}
fmt.Fprintf(o, "}")
case *MathExpr:
fmt.Fprintf(o, "ast.MathExpr{")
switch len(node.List) {
case 0:
// no-op
default:
fmt.Fprintf(o, "List:")
for i, n := range node.List {
if i > 0 {
fmt.Fprintf(o, ", ")
}
Print(o, n)
}
}
fmt.Fprintf(o, "}")
case *OptArg:
fmt.Fprintf(o, "[")
for i, n := range node.List {
if i > 0 {
fmt.Fprintf(o, ", ")
}
Print(o, n)
}
fmt.Fprintf(o, "]")
case *Word:
fmt.Fprintf(o, "ast.Word{%q}", node.Text)
case *Literal:
fmt.Fprintf(o, "ast.Lit{%q}", node.Text)
case List:
fmt.Fprintf(o, "ast.List{")
for i, n := range node {
if i > 0 {
fmt.Fprintf(o, ", ")
}
Print(o, n)
}
fmt.Fprintf(o, "}")
case *Sub:
fmt.Fprintf(o, "ast.Sub{")
Print(o, node.Node)
fmt.Fprintf(o, "}")
case *Sup:
fmt.Fprintf(o, "ast.Sup{")
Print(o, node.Node)
fmt.Fprintf(o, "}")
case *Symbol:
fmt.Fprintf(o, "ast.Symbol{%q}", node.Text)
// case *Op:
// fmt.Fprintf(o, "ast.Op{%q}", node.Text)
case nil:
fmt.Fprintf(o, "<nil>")
default:
panic(fmt.Errorf("unknown node %T", node))
}
}
var (
_ Node = (*List)(nil)
_ Node = (*Arg)(nil)
_ Node = (*Ident)(nil)
_ Node = (*Macro)(nil)
_ Node = (*MathExpr)(nil)
_ Node = (*OptArg)(nil)
_ Node = (*Word)(nil)
_ Node = (*Literal)(nil)
_ Node = (*Sup)(nil)
_ Node = (*Sub)(nil)
_ Node = (*Symbol)(nil)
)

88
vendor/github.com/go-latex/latex/ast/walk.go generated vendored Normal file
View File

@@ -0,0 +1,88 @@
// 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 ast
import "fmt"
// A Visitor's Visit method is invoked for each node encountered by Walk.
// If the result visitor w is not nil, Walk visits each of the children
// of node with the visitor w, followed by a call of w.Visit(nil).
type Visitor interface {
Visit(node Node) (w Visitor)
}
// Walk traverses an AST in depth-first order: It starts by calling
// v.Visit(node); node must not be nil. If the visitor w returned by
// v.Visit(node) is not nil, Walk is invoked recursively with visitor
// w for each of the non-nil children of node, followed by a call of
// w.Visit(nil).
func Walk(v Visitor, node Node) {
if v = v.Visit(node); v == nil {
return
}
switch n := node.(type) {
case List:
for _, x := range n {
Walk(v, x)
}
case *Macro:
if n.Name != nil {
Walk(v, n.Name)
}
walkNodes(v, n.Args)
case *Arg:
walkNodes(v, n.List)
case *OptArg:
walkNodes(v, n.List)
case *Ident:
// nothing to do.
case *MathExpr:
walkNodes(v, n.List)
case *Word, *Literal, *Symbol:
// nothing to do.
case *Sub:
Walk(v, n.Node)
case *Sup:
Walk(v, n.Node)
default:
panic(fmt.Errorf("unknown ast node %#v (type=%T)", n, n))
}
v.Visit(nil)
}
func walkNodes(v Visitor, nodes []Node) {
for _, x := range nodes {
Walk(v, x)
}
}
type inspector func(Node) bool
func (f inspector) Visit(node Node) Visitor {
if f(node) {
return f
}
return nil
}
// Inspect traverses an AST in depth-first order: It starts by calling
// f(node); node must not be nil. If f returns true, Inspect invokes f
// recursively for each of the non-nil children of node, followed by a
// call of f(nil).
//
func Inspect(node Node, f func(Node) bool) {
Walk(inspector(f), node)
}

62
vendor/github.com/go-latex/latex/drawtex/canvas.go generated vendored Normal file
View File

@@ -0,0 +1,62 @@
// 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 drawtex describes the graphics interface for drawing LaTeX.
package drawtex // import "github.com/go-latex/latex/drawtex"
import (
"github.com/go-latex/latex/font"
"golang.org/x/image/font/sfnt"
)
type Canvas struct {
ops []Op
}
func New() *Canvas {
return &Canvas{}
}
func (c *Canvas) RenderGlyph(x, y float64, infos Glyph) {
c.ops = append(c.ops, GlyphOp{x, y, infos})
}
func (c *Canvas) RenderRectFilled(x1, y1, x2, y2 float64) {
c.ops = append(c.ops, RectOp{x1, y1, x2, y2})
}
func (c *Canvas) Ops() []Op { return c.ops }
type Op interface {
isOp()
}
type GlyphOp struct {
X, Y float64
Glyph Glyph
}
func (GlyphOp) isOp() {}
type RectOp struct {
X1, Y1 float64
X2, Y2 float64
}
func (RectOp) isOp() {}
type Glyph struct {
Font *sfnt.Font
Size float64
Postscript string
Metrics font.Metrics
Symbol string
Num sfnt.GlyphIndex
Offset float64
}
var (
_ Op = (*GlyphOp)(nil)
_ Op = (*RectOp)(nil)
)

52
vendor/github.com/go-latex/latex/font/font.go generated vendored Normal file
View File

@@ -0,0 +1,52 @@
// 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 font holds types to handle and abstract away font management.
package font
// Font represents a font.
type Font struct {
Name string // Name is the LaTeX name of the font (regular, default, it, ...)
Type string // Type is the LaTeX class of the font (it, rm, ...)
Size float64 // Size is the font size in points.
}
// Backend is the interface that allows to render math expressions.
type Backend interface {
// RenderGlyphs renders the glyph g at the reference point (x,y).
RenderGlyph(x, y float64, font Font, symbol string, dpi float64)
// RenderRectFilled draws a filled black rectangle from (x1,y1) to (x2,y2).
RenderRectFilled(x1, y1, x2, y2 float64)
// Kern returns the kerning distance between two symbols.
Kern(ft1 Font, sym1 string, ft2 Font, sym2 string, dpi float64) float64
// Metrics returns the metrics.
Metrics(symbol string, font Font, dpi float64, math bool) Metrics
// XHeight returns the xheight for the given font and dpi.
XHeight(font Font, dpi float64) float64
// UnderlineThickness returns the line thickness that matches the given font.
// It is used as a base unit for drawing lines such as in a fraction or radical.
UnderlineThickness(font Font, dpi float64) float64
}
// Metrics represents the metrics of a glyph in a given font.
type Metrics struct {
Advance float64 // Advance distance of the glyph, in points.
Height float64 // Height of the glyph in points.
Width float64 // Width of the glyph in points.
// Ink rectangle of the glyph.
XMin, XMax, YMin, YMax float64
// Iceberg is the distance from the baseline to the top of the glyph.
// Iceberg corresponds to TeX's definition of "height".
Iceberg float64
// Slanted indicates whether the glyph is slanted.
Slanted bool
}

308
vendor/github.com/go-latex/latex/font/ttf/ttf.go generated vendored Normal file
View File

@@ -0,0 +1,308 @@
// 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 ttf provides a truetype font Backend
package ttf // import "github.com/go-latex/latex/font/ttf"
import (
"errors"
"fmt"
"unicode"
"github.com/go-latex/latex/drawtex"
"github.com/go-latex/latex/font"
"github.com/go-latex/latex/internal/tex2unicode"
stdfont "golang.org/x/image/font"
"golang.org/x/image/font/gofont/gobold"
"golang.org/x/image/font/gofont/gobolditalic"
"golang.org/x/image/font/gofont/goitalic"
"golang.org/x/image/font/gofont/goregular"
"golang.org/x/image/font/opentype"
"golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed"
)
type Fonts struct {
Default *sfnt.Font
Rm *sfnt.Font
It *sfnt.Font
Bf *sfnt.Font
BfIt *sfnt.Font
}
type Backend struct {
canvas *drawtex.Canvas
glyphs map[ttfKey]ttfVal
fonts map[string]*sfnt.Font
}
func New(cnv *drawtex.Canvas) *Backend {
return NewFrom(cnv, &defaultFonts)
}
func NewFrom(cnv *drawtex.Canvas, fnts *Fonts) *Backend {
be := &Backend{
canvas: cnv,
glyphs: make(map[ttfKey]ttfVal),
fonts: make(map[string]*sfnt.Font),
}
be.fonts["default"] = fnts.Default
be.fonts["regular"] = fnts.Rm
be.fonts["rm"] = fnts.Rm
be.fonts["it"] = fnts.It
be.fonts["bf"] = fnts.Bf
return be
}
// RenderGlyphs renders the glyph g at the reference point (x,y).
func (be *Backend) RenderGlyph(x, y float64, font font.Font, symbol string, dpi float64) {
glyph := be.getInfo(symbol, font, dpi, true)
be.canvas.RenderGlyph(x, y, drawtex.Glyph{
Font: glyph.font,
Size: glyph.size,
Postscript: glyph.postscript,
Metrics: glyph.metrics,
Symbol: string(glyph.rune),
Num: glyph.glyph,
Offset: glyph.offset,
})
}
// RenderRectFilled draws a filled black rectangle from (x1,y1) to (x2,y2).
func (be *Backend) RenderRectFilled(x1, y1, x2, y2 float64) {
be.canvas.RenderRectFilled(x1, y1, x2, y2)
}
// Metrics returns the metrics.
func (be *Backend) Metrics(symbol string, fnt font.Font, dpi float64, math bool) font.Metrics {
return be.getInfo(symbol, fnt, dpi, math).metrics
}
func (be *Backend) getInfo(symbol string, fnt font.Font, dpi float64, math bool) ttfVal {
key := ttfKey{symbol, fnt, dpi}
val, ok := be.glyphs[key]
if ok {
return val
}
var (
buf sfnt.Buffer
hinting = hintingNone
)
ft, rn, _ /*symbol*/, fontSize, slanted := be.getGlyph(symbol, fnt, math)
postscript, err := ft.Name(&buf, sfnt.NameIDPostScript)
if err != nil {
panic(fmt.Errorf("could not retrieve postscript name of font: %+v", err))
}
idx, err := ft.GlyphIndex(&buf, rn)
if err != nil {
panic(fmt.Errorf("could not retrieve glyph index for %q: %+v", rn, err))
}
symName, err := ft.GlyphName(&buf, idx)
if err != nil {
panic(fmt.Errorf("could not retrieve glyph name of %q: %+v", rn, err))
}
var ppem = int(ft.UnitsPerEm() * 6)
_, err = ft.LoadGlyph(&buf, idx, fixed.I(ppem), nil)
if err != nil {
panic(fmt.Errorf("could not load glyph %q: %+v", rn, err))
}
adv, err := ft.GlyphAdvance(&buf, idx, fixed.I(ppem), hinting)
if err != nil {
panic(fmt.Errorf("could not retrieve glyph advance for %q: %+v", rn, err))
}
fupe := fixed.Int26_6(ft.UnitsPerEm())
_, err = ft.LoadGlyph(&buf, idx, fupe, nil)
if err != nil {
panic(fmt.Errorf("could not load glyph %q: %+v", rn, err))
}
bnds, _, err := ft.GlyphBounds(&buf, idx, fixed.I(12), hinting)
if err != nil {
panic(err)
}
var (
scale = fontSize / 12
xmin = scale * float64(bnds.Min.X) / 64
xmax = scale * float64(bnds.Max.X) / 64
ymin = scale * float64(-bnds.Max.Y) / 64 // FIXME
ymax = scale * float64(-bnds.Min.Y) / 64 // FIXME
width = xmax - xmin
height = ymax - ymin
)
offset := 0.0
if postscript == "Cmex10" {
offset = height/2 + (fnt.Size / 3 * dpi / 72)
}
me := font.Metrics{
Advance: float64(adv) / 65536 * fnt.Size / 12,
Height: height,
Width: width,
XMin: xmin,
XMax: xmax,
YMin: ymin + offset,
YMax: ymax + offset,
Iceberg: ymax + offset,
Slanted: slanted,
}
be.glyphs[key] = ttfVal{
font: ft,
size: fnt.Size,
postscript: postscript,
metrics: me,
symbolName: symName,
rune: rn,
glyph: idx,
offset: offset,
}
return be.glyphs[key]
}
// XHeight returns the xheight for the given font and dpi.
func (be *Backend) XHeight(fnt font.Font, dpi float64) float64 {
ft := be.getFont(fnt.Type)
face, err := opentype.NewFace(ft, &opentype.FaceOptions{
DPI: dpi,
Size: fnt.Size,
Hinting: stdfont.HintingNone,
})
if err != nil {
panic(fmt.Errorf("could not open font face for font=%s,%g,%s: %+v",
fnt.Name, fnt.Size, fnt.Type, err,
))
}
defer face.Close()
return float64(-face.Metrics().XHeight) / 64
}
const (
hintingNone = stdfont.HintingNone
//hintingFull = stdfont.HintingFull
)
func (be *Backend) getGlyph(symbol string, font font.Font, math bool) (*sfnt.Font, rune, string, float64, bool) {
var (
fontType = font.Type
idx = tex2unicode.Index(symbol, math)
)
// only characters in the "Letter" class should be italicized in "it" mode.
// Greek capital letters should be roman.
if font.Type == "it" && idx < 0x10000 {
if !unicode.Is(unicode.L, idx) {
fontType = "rm"
}
}
slanted := (fontType == "it") || be.isSlanted(symbol)
ft := be.getFont(fontType)
if ft == nil {
panic("could not find TTF font for [" + fontType + "]")
}
// FIXME(sbinet):
// \sigma -> sigma, A->A, \infty->infinity, \nabla->gradient
// etc...
symbolName := symbol
return ft, idx, symbolName, font.Size, slanted
}
func (*Backend) isSlanted(symbol string) bool {
switch symbol {
case `\int`, `\oint`:
return true
default:
return false
}
}
func (be *Backend) getFont(fontType string) *sfnt.Font {
return be.fonts[fontType]
}
// UnderlineThickness returns the line thickness that matches the given font.
// It is used as a base unit for drawing lines such as in a fraction or radical.
func (*Backend) UnderlineThickness(font font.Font, dpi float64) float64 {
// theoretically, we could grab the underline thickness from the font
// metrics.
// but that information is just too un-reliable.
// so, it is hardcoded.
return (0.75 / 12 * font.Size * dpi) / 72
}
// Kern returns the kerning distance between two symbols.
func (be *Backend) Kern(ft1 font.Font, sym1 string, ft2 font.Font, sym2 string, dpi float64) float64 {
if ft1.Name == ft2.Name && ft1.Size == ft2.Size {
const math = true
info1 := be.getInfo(sym1, ft1, dpi, math)
info2 := be.getInfo(sym2, ft2, dpi, math)
scale := fixed.Int26_6(info1.font.UnitsPerEm())
var buf sfnt.Buffer
k, err := info1.font.Kern(&buf, info1.glyph, info2.glyph, scale, hintingNone)
if err != nil {
if errors.Is(err, sfnt.ErrNotFound) {
return 0
}
panic(fmt.Errorf("could not compute kerning for %q/%q: %+v",
sym1, sym2, err,
))
}
return float64(k) / 64
}
return 0
}
type ttfKey struct {
symbol string
font font.Font
dpi float64
}
type ttfVal struct {
font *sfnt.Font
size float64
postscript string
metrics font.Metrics
symbolName string
rune rune
glyph sfnt.GlyphIndex
offset float64
}
var defaultFonts = Fonts{
Rm: mustParseTTF(goregular.TTF),
It: mustParseTTF(goitalic.TTF),
Bf: mustParseTTF(gobold.TTF),
BfIt: mustParseTTF(gobolditalic.TTF),
}
func mustParseTTF(raw []byte) *sfnt.Font {
ft, err := sfnt.Parse(raw)
if err != nil {
panic(fmt.Errorf("could not parse raw TTF data: %+v", err))
}
return ft
}
func init() {
defaultFonts.Default = defaultFonts.Rm
}
var (
_ font.Backend = (*Backend)(nil)
)

View File

@@ -0,0 +1,634 @@
// 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 tex2unicode provides tools for associating TeX symbols to UTF-8.
package tex2unicode // import "github.com/go-latex/latex/internal/tex2unicode"
import (
"fmt"
"strings"
"unicode/utf8"
)
// Index associates a LaTeX symbol or unicode letter to a unicode rune.
func Index(v string, math bool) rune {
if !math {
r, _ := utf8.DecodeRune([]byte(v))
if r == utf8.RuneError {
panic(fmt.Errorf("tex: invalid rune %q", v))
}
return r
}
// From UTF #25: U+2212 minus sign is the preferred
// representation of the unary and binary minus sign rather than
// the ASCII-derived U+002D hyphen-minus, because minus sign is
// unambiguous and because it is rendered with a more desirable
// length, usually longer than a hyphen.
if v == "-" {
return 0x2212
}
if len(v) == 1 {
r, _ := utf8.DecodeRune([]byte(v))
if r != utf8.RuneError {
return r
}
}
r, ok := tex2uni[strings.Replace(v, `\`, "", 1)]
if ok {
return r
}
panic(fmt.Errorf("%q is not a valid unicode character nor a known TeX symbol", v))
}
func HasSymbol(v string) bool {
_, ok := tex2uni[v]
return ok
}
func Symbols() []string {
names := make([]string, 0, len(tex2uni))
for k := range tex2uni {
names = append(names, k)
}
return names
}
var (
tex2uni = map[string]rune{
`widehat`: 0x0302,
`widetilde`: 0x0303,
`widebar`: 0x0305,
`langle`: 0x27e8,
`rangle`: 0x27e9,
`perp`: 0x27c2,
`neq`: 0x2260,
`Join`: 0x2a1d,
`leqslant`: 0x2a7d,
`geqslant`: 0x2a7e,
`lessapprox`: 0x2a85,
`gtrapprox`: 0x2a86,
`lesseqqgtr`: 0x2a8b,
`gtreqqless`: 0x2a8c,
`triangleeq`: 0x225c,
`eqslantless`: 0x2a95,
`eqslantgtr`: 0x2a96,
`backepsilon`: 0x03f6,
`precapprox`: 0x2ab7,
`succapprox`: 0x2ab8,
`fallingdotseq`: 0x2252,
`subseteqq`: 0x2ac5,
`supseteqq`: 0x2ac6,
`varpropto`: 0x221d,
`precnapprox`: 0x2ab9,
`succnapprox`: 0x2aba,
`subsetneqq`: 0x2acb,
`supsetneqq`: 0x2acc,
`lnapprox`: 0x2ab9,
`gnapprox`: 0x2aba,
`longleftarrow`: 0x27f5,
`longrightarrow`: 0x27f6,
`longleftrightarrow`: 0x27f7,
`Longleftarrow`: 0x27f8,
`Longrightarrow`: 0x27f9,
`Longleftrightarrow`: 0x27fa,
`longmapsto`: 0x27fc,
`leadsto`: 0x21dd,
`dashleftarrow`: 0x290e,
`dashrightarrow`: 0x290f,
`circlearrowleft`: 0x21ba,
`circlearrowright`: 0x21bb,
`leftrightsquigarrow`: 0x21ad,
`leftsquigarrow`: 0x219c,
`rightsquigarrow`: 0x219d,
`Game`: 0x2141,
`hbar`: 0x0127,
`hslash`: 0x210f,
`ldots`: 0x2026,
`vdots`: 0x22ee,
`doteqdot`: 0x2251,
`doteq`: 8784,
`partial`: 8706,
`gg`: 8811,
`asymp`: 8781,
`blacktriangledown`: 9662,
`otimes`: 8855,
`nearrow`: 8599,
`varpi`: 982,
`vee`: 8744,
`vec`: 8407,
`smile`: 8995,
`succnsim`: 8937,
`gimel`: 8503,
`vert`: 124,
`|`: 124,
`varrho`: 1009,
`P`: 182,
`approxident`: 8779,
`Swarrow`: 8665,
`textasciicircum`: 94,
`imageof`: 8887,
`ntriangleleft`: 8938,
`nleq`: 8816,
`div`: 247,
`nparallel`: 8742,
`Leftarrow`: 8656,
`lll`: 8920,
`oiint`: 8751,
`ngeq`: 8817,
`Theta`: 920,
`origof`: 8886,
`blacksquare`: 9632,
`solbar`: 9023,
`neg`: 172,
`sum`: 8721,
`Vdash`: 8873,
`coloneq`: 8788,
`degree`: 176,
`bowtie`: 8904,
`blacktriangleright`: 9654,
`varsigma`: 962,
`leq`: 8804,
`ggg`: 8921,
`lneqq`: 8808,
`scurel`: 8881,
`stareq`: 8795,
`BbbN`: 8469,
`nLeftarrow`: 8653,
`nLeftrightarrow`: 8654,
`k`: 808,
`bot`: 8869,
`BbbC`: 8450,
`Lsh`: 8624,
`leftleftarrows`: 8647,
`BbbZ`: 8484,
`digamma`: 989,
`BbbR`: 8477,
`BbbP`: 8473,
`BbbQ`: 8474,
`vartriangleright`: 8883,
`succsim`: 8831,
`wedge`: 8743,
`lessgtr`: 8822,
`veebar`: 8891,
`mapsdown`: 8615,
`Rsh`: 8625,
`chi`: 967,
`prec`: 8826,
`nsubseteq`: 8840,
`therefore`: 8756,
`eqcirc`: 8790,
`textexclamdown`: 161,
`nRightarrow`: 8655,
`flat`: 9837,
`notin`: 8713,
`llcorner`: 8990,
`varepsilon`: 949,
`bigtriangleup`: 9651,
`aleph`: 8501,
`dotminus`: 8760,
`upsilon`: 965,
`Lambda`: 923,
`cap`: 8745,
`barleftarrow`: 8676,
`mu`: 956,
`boxplus`: 8862,
`mp`: 8723,
`circledast`: 8859,
`tau`: 964,
`in`: 8712,
`backslash`: 92,
`varnothing`: 8709,
`sharp`: 9839,
`eqsim`: 8770,
`gnsim`: 8935,
`Searrow`: 8664,
`updownarrows`: 8645,
`heartsuit`: 9825,
`trianglelefteq`: 8884,
`ddag`: 8225,
`sqsubseteq`: 8849,
`mapsfrom`: 8612,
`boxbar`: 9707,
`sim`: 8764,
`Nwarrow`: 8662,
`nequiv`: 8802,
`succ`: 8827,
`vdash`: 8866,
`Leftrightarrow`: 8660,
`parallel`: 8741,
`invnot`: 8976,
`natural`: 9838,
`ss`: 223,
`uparrow`: 8593,
`nsim`: 8769,
`hookrightarrow`: 8618,
`Equiv`: 8803,
`approx`: 8776,
`Vvdash`: 8874,
`nsucc`: 8833,
`leftrightharpoons`: 8651,
`Re`: 8476,
`boxminus`: 8863,
`equiv`: 8801,
`Lleftarrow`: 8666,
`ll`: 8810,
`Cup`: 8915,
`measeq`: 8798,
`upharpoonleft`: 8639,
`lq`: 8216,
`Upsilon`: 933,
`subsetneq`: 8842,
`greater`: 62,
`supsetneq`: 8843,
`Cap`: 8914,
`L`: 321,
`spadesuit`: 9824,
`lrcorner`: 8991,
`not`: 824,
`bar`: 772,
`rightharpoonaccent`: 8401,
`boxdot`: 8865,
`l`: 322,
`leftharpoondown`: 8637,
`bigcup`: 8899,
`iint`: 8748,
`bigwedge`: 8896,
`downharpoonleft`: 8643,
`textasciitilde`: 126,
`subset`: 8834,
`leqq`: 8806,
`mapsup`: 8613,
`nvDash`: 8877,
`looparrowleft`: 8619,
`nless`: 8814,
`rightarrowbar`: 8677,
`Vert`: 8214,
`downdownarrows`: 8650,
`uplus`: 8846,
`simeq`: 8771,
`napprox`: 8777,
`ast`: 8727,
`twoheaduparrow`: 8607,
`doublebarwedge`: 8966,
`Sigma`: 931,
`leftharpoonaccent`: 8400,
`ntrianglelefteq`: 8940,
`nexists`: 8708,
`times`: 215,
`measuredangle`: 8737,
`bumpeq`: 8783,
`carriagereturn`: 8629,
`adots`: 8944,
`checkmark`: 10003,
`lambda`: 955,
`xi`: 958,
`rbrace`: 125,
`rbrack`: 93,
`Nearrow`: 8663,
`maltese`: 10016,
`clubsuit`: 9827,
`top`: 8868,
`overarc`: 785,
`varphi`: 966,
`Delta`: 916,
`iota`: 953,
`nleftarrow`: 8602,
`candra`: 784,
`supset`: 8835,
`triangleleft`: 9665,
`gtreqless`: 8923,
`ntrianglerighteq`: 8941,
`quad`: 8195,
`Xi`: 926,
`gtrdot`: 8919,
`leftthreetimes`: 8907,
`minus`: 8722,
`preccurlyeq`: 8828,
`nleftrightarrow`: 8622,
`lambdabar`: 411,
`blacktriangle`: 9652,
`kernelcontraction`: 8763,
`Phi`: 934,
`angle`: 8736,
`spadesuitopen`: 9828,
`eqless`: 8924,
`mid`: 8739,
`varkappa`: 1008,
`Ldsh`: 8626,
`updownarrow`: 8597,
`beta`: 946,
`textquotedblleft`: 8220,
`rho`: 961,
`alpha`: 945,
`intercal`: 8890,
`beth`: 8502,
`grave`: 768,
`acwopencirclearrow`: 8634,
`nmid`: 8740,
`nsupset`: 8837,
`sigma`: 963,
`dot`: 775,
`Rightarrow`: 8658,
`turnednot`: 8985,
`backsimeq`: 8909,
`leftarrowtail`: 8610,
`approxeq`: 8778,
`curlyeqsucc`: 8927,
`rightarrowtail`: 8611,
`Psi`: 936,
`copyright`: 169,
`yen`: 165,
`vartriangleleft`: 8882,
`rasp`: 700,
`triangleright`: 9655,
`precsim`: 8830,
`infty`: 8734,
`geq`: 8805,
`updownarrowbar`: 8616,
`precnsim`: 8936,
`H`: 779,
`ulcorner`: 8988,
`looparrowright`: 8620,
`ncong`: 8775,
`downarrow`: 8595,
`circeq`: 8791,
`subseteq`: 8838,
`bigstar`: 9733,
`prime`: 8242,
`lceil`: 8968,
`Rrightarrow`: 8667,
`oiiint`: 8752,
`curlywedge`: 8911,
`vDash`: 8872,
`lfloor`: 8970,
`ddots`: 8945,
`exists`: 8707,
`underbar`: 817,
`Pi`: 928,
`leftrightarrows`: 8646,
`sphericalangle`: 8738,
`coprod`: 8720,
`circledcirc`: 8858,
`gtrsim`: 8819,
`gneqq`: 8809,
`between`: 8812,
`theta`: 952,
`complement`: 8705,
`arceq`: 8792,
`nVdash`: 8878,
`S`: 167,
`wr`: 8768,
`wp`: 8472,
`backcong`: 8780,
`lasp`: 701,
`c`: 807,
`nabla`: 8711,
`dotplus`: 8724,
`eta`: 951,
`forall`: 8704,
`eth`: 240,
`colon`: 58,
`sqcup`: 8852,
`rightrightarrows`: 8649,
`sqsupset`: 8848,
`mapsto`: 8614,
`bigtriangledown`: 9661,
`sqsupseteq`: 8850,
`propto`: 8733,
`pi`: 960,
`pm`: 177,
`dots`: 0x2026,
`nrightarrow`: 8603,
`textasciiacute`: 180,
`Doteq`: 8785,
`breve`: 774,
`sqcap`: 8851,
`twoheadrightarrow`: 8608,
`kappa`: 954,
`vartriangle`: 9653,
`diamondsuit`: 9826,
`pitchfork`: 8916,
`blacktriangleleft`: 9664,
`nprec`: 8832,
`curvearrowright`: 8631,
`barwedge`: 8892,
`multimap`: 8888,
`textquestiondown`: 191,
`cong`: 8773,
`rtimes`: 8906,
`rightzigzagarrow`: 8669,
`rightarrow`: 8594,
`leftarrow`: 8592,
`__sqrt__`: 8730,
`twoheaddownarrow`: 8609,
`oint`: 8750,
`bigvee`: 8897,
`eqdef`: 8797,
`sterling`: 163,
`phi`: 981,
`Updownarrow`: 8661,
`backprime`: 8245,
`emdash`: 8212,
`Gamma`: 915,
`i`: 305,
`rceil`: 8969,
`leftharpoonup`: 8636,
`Im`: 8465,
`curvearrowleft`: 8630,
`wedgeq`: 8793,
`curlyeqprec`: 8926,
`questeq`: 8799,
`less`: 60,
`upuparrows`: 8648,
`tilde`: 771,
`textasciigrave`: 96,
`smallsetminus`: 8726,
`ell`: 8467,
`cup`: 8746,
`danger`: 9761,
`nVDash`: 8879,
`cdotp`: 183,
`cdots`: 8943,
`hat`: 770,
`eqgtr`: 8925,
`psi`: 968,
`frown`: 8994,
`acute`: 769,
`downzigzagarrow`: 8623,
`ntriangleright`: 8939,
`cupdot`: 8845,
`circleddash`: 8861,
`oslash`: 8856,
`mho`: 8487,
`d`: 803,
`sqsubset`: 8847,
`cdot`: 8901,
`Omega`: 937,
`OE`: 338,
`veeeq`: 8794,
`Finv`: 8498,
`t`: 865,
`leftrightarrow`: 8596,
`swarrow`: 8601,
`rightthreetimes`: 8908,
`rightleftharpoons`: 8652,
`lesssim`: 8818,
`searrow`: 8600,
`because`: 8757,
`gtrless`: 8823,
`star`: 8902,
`nsubset`: 8836,
`zeta`: 950,
`dddot`: 8411,
`bigcirc`: 9675,
`Supset`: 8913,
`circ`: 8728,
`slash`: 8725,
`ocirc`: 778,
`prod`: 8719,
`twoheadleftarrow`: 8606,
`daleth`: 8504,
`upharpoonright`: 8638,
`odot`: 8857,
`Uparrow`: 8657,
`O`: 216,
`hookleftarrow`: 8617,
`trianglerighteq`: 8885,
`nsime`: 8772,
`oe`: 339,
`nwarrow`: 8598,
`o`: 248,
`ddddot`: 8412,
`downharpoonright`: 8642,
`succcurlyeq`: 8829,
`gamma`: 947,
`scrR`: 8475,
`dag`: 8224,
`thickspace`: 8197,
`frakZ`: 8488,
`lessdot`: 8918,
`triangledown`: 9663,
`ltimes`: 8905,
`scrB`: 8492,
`endash`: 8211,
`scrE`: 8496,
`scrF`: 8497,
`scrH`: 8459,
`scrI`: 8464,
`rightharpoondown`: 8641,
`scrL`: 8466,
`scrM`: 8499,
`frakC`: 8493,
`nsupseteq`: 8841,
`circledR`: 174,
`circledS`: 9416,
`ngtr`: 8815,
`bigcap`: 8898,
`scre`: 8495,
`Downarrow`: 8659,
`scrg`: 8458,
`overleftrightarrow`: 8417,
`scro`: 8500,
`lnsim`: 8934,
`eqcolon`: 8789,
`curlyvee`: 8910,
`urcorner`: 8989,
`lbrace`: 123,
`Bumpeq`: 8782,
`delta`: 948,
`boxtimes`: 8864,
`overleftarrow`: 8406,
`prurel`: 8880,
`clubsuitopen`: 9831,
`cwopencirclearrow`: 8635,
`geqq`: 8807,
`rightleftarrows`: 8644,
`ac`: 8766,
`ae`: 230,
`int`: 8747,
`rfloor`: 8971,
`risingdotseq`: 8787,
`nvdash`: 8876,
`diamond`: 8900,
`ddot`: 776,
`backsim`: 8765,
`oplus`: 8853,
`triangleq`: 8796,
`check`: 780,
`ni`: 8715,
`iiint`: 8749,
`ne`: 8800,
`lesseqgtr`: 8922,
`obar`: 9021,
`supseteq`: 8839,
`nu`: 957,
`AA`: 197,
`AE`: 198,
`models`: 8871,
`ominus`: 8854,
`dashv`: 8867,
`omega`: 969,
`rq`: 8217,
`Subset`: 8912,
`rightharpoonup`: 8640,
`Rdsh`: 8627,
`bullet`: 8729,
`divideontimes`: 8903,
`lbrack`: 91,
`textquotedblright`: 8221,
`Colon`: 8759,
`%`: 37,
`$`: 36,
`{`: 123,
`}`: 125,
`_`: 95,
`#`: 35,
`imath`: 0x131,
`circumflexaccent`: 770,
`combiningbreve`: 774,
`combiningoverline`: 772,
`combininggraveaccent`: 768,
`combiningacuteaccent`: 769,
`combiningdiaeresis`: 776,
`combiningtilde`: 771,
`combiningrightarrowabove`: 8407,
`combiningdotabove`: 775,
`to`: 8594,
`succeq`: 8829,
`emptyset`: 8709,
`(`: 40,
`)`: 41,
`leftparen`: 40,
`rightparen`: 41,
`bigoplus`: 10753,
`leftangle`: 10216,
`rightangle`: 10217,
`leftbrace`: 124,
`rightbrace`: 125,
`jmath`: 567,
`bigodot`: 10752,
`preceq`: 8828,
`biguplus`: 10756,
`epsilon`: 949,
`vartheta`: 977,
`bigotimes`: 10754,
`guillemotleft`: 171,
`ring`: 730,
`Thorn`: 222,
`guilsinglright`: 8250,
`perthousand`: 8240,
`macron`: 175,
`cent`: 162,
`guillemotright`: 187,
`equal`: 61,
`asterisk`: 42,
`guilsinglleft`: 8249,
`plus`: 43,
`thorn`: 254,
`dagger`: 8224,
}
)

6
vendor/github.com/go-latex/latex/latex.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 latex provides types and functions to work with LaTeX.
package latex // import "github.com/go-latex/latex"

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

@@ -0,0 +1,361 @@
// 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 latex
import (
"strings"
"github.com/go-latex/latex/ast"
"github.com/go-latex/latex/internal/tex2unicode"
)
type macroParser interface {
parseMacro(p *parser) ast.Node
}
func (p *parser) addBuiltinMacros() {
p.macros = map[string]macroParser{
// 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(""),
`\langle`: builtinMacro(""),
`\lceil`: builtinMacro(""),
`\lfloor`: builtinMacro(""),
// right delim
`\}`: 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"),
}
// add all known UTF-8 symbols
for _, k := range tex2unicode.Symbols() {
_, ok := p.macros[`\`+k]
if ok {
continue
}
p.macros[`\`+k] = builtinMacro("")
}
}
type builtinMacro string
func (m builtinMacro) parseMacro(p *parser) ast.Node {
node := &ast.Macro{
Name: &ast.Ident{
NamePos: p.s.tok.Pos,
Name: p.s.tok.Text,
},
}
for _, typ := range strings.ToLower(string(m)) {
switch typ {
case 'a':
p.parseMacroArg(node)
case 'o':
p.parseOptMacroArg(node)
case 'v':
p.parseVerbatimMacroArg(node)
}
}
return node
}

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",
")",
)
)

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

@@ -0,0 +1,337 @@
// 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 latex // import "github.com/go-latex/latex"
import (
"fmt"
"strings"
"github.com/go-latex/latex/ast"
"github.com/go-latex/latex/token"
)
// ParseExpr parses a simple LaTeX expression.
func ParseExpr(x string) (ast.Node, error) {
p := newParser(x)
return p.parse()
}
type state int
const (
normalState state = iota
mathState
)
type parser struct {
s *texScanner
state state
macros map[string]macroParser
}
func newParser(x string) *parser {
p := &parser{
s: newScanner(strings.NewReader(x)),
state: normalState,
}
p.addBuiltinMacros()
return p
}
func (p *parser) parse() (ast.Node, error) {
var nodes ast.List
for p.s.Next() {
tok := p.s.Token()
node := p.parseNode(tok)
if node == nil {
continue
}
nodes = append(nodes, node)
}
return nodes, nil
}
func (p *parser) next() token.Token {
if !p.s.Next() {
return token.Token{Kind: token.EOF}
}
return p.s.tok
}
func (p *parser) expect(v rune) {
p.next()
if p.s.tok.Text != string(v) {
panic(fmt.Errorf("expected %q, got %q", v, p.s.tok.Text))
}
}
func (p *parser) parseNode(tok token.Token) ast.Node {
switch tok.Kind {
case token.Comment:
return nil
case token.Macro:
return p.parseMacro(tok)
case token.Word:
return p.parseWord(tok)
case token.Number:
return p.parseNumber(tok)
case token.Symbol:
switch tok.Text {
case "$":
return p.parseMathExpr(tok)
case "^":
return p.parseSup(tok)
case "_":
return p.parseSub(tok)
default:
return p.parseSymbol(tok)
}
case token.Lbrace:
switch p.state {
case mathState:
return p.parseMathLbrace(tok)
default:
panic("not implemented")
}
case token.Other:
switch tok.Text {
default:
panic("not implemented: " + tok.String())
}
case token.Space:
switch p.state {
case mathState:
return nil
default:
return p.parseSymbol(tok)
}
case token.Lparen, token.Rparen,
token.Lbrack, token.Rbrack:
return p.parseSymbol(tok)
default:
panic(fmt.Errorf("impossible: %v (%v)", tok, tok.Kind))
}
}
func (p *parser) parseMathExpr(tok token.Token) ast.Node {
state := p.state
p.state = mathState
defer func() {
p.state = state
}()
math := &ast.MathExpr{
Delim: tok.Text,
Left: tok.Pos,
}
var end string
switch tok.Text {
case "$":
end = "$"
case `\(`:
end = `\)`
case `\[`:
end = `\]`
case `\begin`:
panic("not implemented")
default:
panic(fmt.Errorf("opening math-expression delimiter %q not supported", tok.Text))
}
loop:
for p.s.Next() {
switch p.s.tok.Text {
case end:
math.Right = p.s.tok.Pos
break loop
default:
node := p.parseNode(p.s.tok)
if node == nil {
continue
}
math.List = append(math.List, node)
}
}
return math
}
func (p *parser) parseMacro(tok token.Token) ast.Node {
name := tok.Text
macro, ok := p.macros[name]
if !ok {
panic("unknown macro " + name)
//return nil
}
return macro.parseMacro(p)
}
func (p *parser) parseWord(tok token.Token) ast.Node {
return &ast.Word{
WordPos: tok.Pos,
Text: tok.Text,
}
}
func (p *parser) parseNumber(tok token.Token) ast.Node {
return &ast.Literal{
LitPos: tok.Pos,
Text: tok.Text,
}
}
func (p *parser) parseMacroArg(macro *ast.Macro) {
var arg ast.Arg
p.expect('{')
arg.Lbrace = p.s.tok.Pos
loop:
for p.s.Next() {
switch p.s.tok.Kind {
case token.Rbrace:
arg.Rbrace = p.s.tok.Pos
break loop
default:
node := p.parseNode(p.s.tok)
if node == nil {
continue
}
arg.List = append(arg.List, node)
}
}
macro.Args = append(macro.Args, &arg)
}
func (p *parser) parseOptMacroArg(macro *ast.Macro) {
nxt := p.s.sc.Peek()
if nxt != '[' {
return
}
var opt ast.OptArg
p.expect('[')
opt.Lbrack = p.s.tok.Pos
loop:
for p.s.Next() {
switch p.s.tok.Kind {
case token.Rbrack:
opt.Rbrack = p.s.tok.Pos
break loop
default:
node := p.parseNode(p.s.tok)
if node == nil {
continue
}
opt.List = append(opt.List, node)
}
}
macro.Args = append(macro.Args, &opt)
}
func (p *parser) parseVerbatimMacroArg(macro *ast.Macro) {
}
func (p *parser) parseSup(tok token.Token) ast.Node {
hat := &ast.Sup{
HatPos: tok.Pos,
}
switch next := p.s.sc.Peek(); next {
case '{':
p.expect('{')
var list ast.List
loop:
for p.s.Next() {
switch p.s.tok.Kind {
case token.Rbrace:
break loop
default:
node := p.parseNode(p.s.tok)
if node == nil {
continue
}
list = append(list, node)
}
}
hat.Node = list
default:
hat.Node = p.parseNode(p.next())
}
return hat
}
func (p *parser) parseSub(tok token.Token) ast.Node {
sub := &ast.Sub{
UnderPos: tok.Pos,
}
switch next := p.s.sc.Peek(); next {
case '{':
p.expect('{')
var list ast.List
loop:
for p.s.Next() {
switch p.s.tok.Kind {
case token.Rbrace:
break loop
default:
node := p.parseNode(p.s.tok)
if node == nil {
continue
}
list = append(list, node)
}
}
sub.Node = list
default:
sub.Node = p.parseNode(p.next())
}
return sub
}
func (p *parser) parseSymbol(tok token.Token) ast.Node {
return &ast.Symbol{
SymPos: tok.Pos,
Text: tok.Text,
}
}
func (p *parser) parseMathLbrace(tok token.Token) ast.Node {
var (
lst ast.List
ldelim = tok.Kind
rdelim = map[token.Kind]token.Kind{
token.Lbrace: token.Rbrace,
token.Lparen: token.Rparen,
}[ldelim]
)
if rdelim == token.Invalid {
panic("impossible: no matching right-delim for: " + tok.String())
}
loop:
for p.s.Next() {
switch p.s.tok.Kind {
case rdelim:
break loop
default:
node := p.parseNode(p.s.tok)
if node == nil {
continue
}
lst = append(lst, node)
}
}
return lst
}

205
vendor/github.com/go-latex/latex/scanner.go generated vendored Normal file
View File

@@ -0,0 +1,205 @@
// 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 latex
import (
"fmt"
"io"
"strings"
"text/scanner"
"unicode"
"github.com/go-latex/latex/token"
)
type texScanner struct {
sc scanner.Scanner
r rune
tok token.Token
}
func newScanner(r io.Reader) *texScanner {
sc := &texScanner{}
sc.sc.Init(r)
sc.sc.Mode = (scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats)
sc.sc.Mode |= scanner.ScanStrings
//scanner.ScanRawStrings)
// sc.sc.Error = func(s *scanner.Scanner, msg string) {}
sc.sc.IsIdentRune = func(ch rune, i int) bool {
return unicode.IsLetter(ch) //|| unicode.IsDigit(ch) && i > 0
}
sc.sc.Whitespace = 1<<'\t' | 1<<'\n' | 1<<'\r'
return sc
}
// Token returns the most recently parsed token
func (s *texScanner) Token() token.Token {
return s.tok
}
// Next iterates over all tokens.
// Next retrieves the most recent token with Token().
// It returns false once it reaches token.EOF.
func (s *texScanner) Next() bool {
s.tok = s.scan()
return s.tok.Kind != token.EOF
}
func (s *texScanner) scan() token.Token {
s.next()
pos := s.pos()
switch s.r {
case scanner.Ident:
return token.Token{
Kind: token.Word,
Pos: pos,
Text: s.sc.TokenText(),
}
case '\\':
nxt := s.sc.Peek()
switch nxt {
case ' ':
s.next()
return token.Token{
Kind: token.Space,
Pos: pos,
Text: `\ `,
}
default:
return s.scanMacro()
}
case ' ':
return token.Token{
Kind: token.Space,
Pos: pos,
Text: ` `,
}
case '%':
line := s.scanComment()
return token.Token{
Kind: token.Comment,
Pos: pos,
Text: line,
}
case '$', '_', '=', '<', '>', '^', '/', '*', '-', '+',
'!', '?', '\'', ':', ',', ';', '.':
return token.Token{
Kind: token.Symbol,
Pos: pos,
Text: s.sc.TokenText(),
}
case '[':
return token.Token{
Kind: token.Lbrack,
Pos: pos,
Text: s.sc.TokenText(),
}
case ']':
return token.Token{
Kind: token.Rbrack,
Pos: pos,
Text: s.sc.TokenText(),
}
case '{':
return token.Token{
Kind: token.Lbrace,
Pos: pos,
Text: s.sc.TokenText(),
}
case '}':
return token.Token{
Kind: token.Rbrace,
Pos: pos,
Text: s.sc.TokenText(),
}
case '(':
return token.Token{
Kind: token.Lparen,
Pos: pos,
Text: s.sc.TokenText(),
}
case ')':
return token.Token{
Kind: token.Rparen,
Pos: pos,
Text: s.sc.TokenText(),
}
case scanner.Int, scanner.Float:
return token.Token{
Kind: token.Number,
Pos: pos,
Text: s.sc.TokenText(),
}
case scanner.String, scanner.Char:
return token.Token{
Kind: token.Other,
Pos: pos,
Text: s.sc.TokenText(),
}
case scanner.EOF:
return token.Token{
Kind: token.EOF,
Pos: pos,
}
default:
panic(fmt.Errorf("unhandled token: %v %v", scanner.TokenString(s.r), s.r))
}
}
func (s *texScanner) next() {
s.r = s.sc.Scan()
}
func (s *texScanner) scanMacro() token.Token {
var (
macro = new(strings.Builder)
pos = s.pos()
)
s.next()
macro.WriteString(`\` + s.sc.TokenText())
return token.Token{
Kind: token.Macro,
Pos: pos,
Text: macro.String(),
}
}
func (s *texScanner) scanComment() string {
comment := new(strings.Builder)
comment.WriteString("%")
wsp := s.sc.Whitespace
defer func() {
s.sc.Whitespace = wsp
}()
s.sc.Whitespace = 0
for {
s.next()
if s.r == '\r' {
continue
}
if s.r == '\n' || s.r == scanner.EOF {
break
}
comment.WriteString(s.sc.TokenText())
}
return comment.String()
}
// func (s *texScanner) expect(want rune) {
// s.next()
// if s.r != want {
// panic(fmt.Errorf("invalid rune: got=%q, want=%q", s.r, want))
// }
// }
func (s *texScanner) pos() token.Pos {
return token.Pos(s.sc.Position.Offset)
}

1226
vendor/github.com/go-latex/latex/tex/box.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

25
vendor/github.com/go-latex/latex/tex/state.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
// 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 tex
import (
"github.com/go-latex/latex/font"
)
type State struct {
be font.Backend
Font font.Font
DPI float64
}
func NewState(be font.Backend, font font.Font, dpi float64) State {
return State{
be: be,
Font: font,
DPI: dpi,
}
}
func (state State) Backend() font.Backend { return state.be }

30
vendor/github.com/go-latex/latex/tex/tex.go generated vendored Normal file
View File

@@ -0,0 +1,30 @@
// 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 tex provides a TeX-like box model.
//
// The following is based directly on the document 'woven' from the
// TeX82 source code. This information is also available in printed
// form:
//
// Knuth, Donald E.. 1986. Computers and Typesetting, Volume B:
// TeX: The Program. Addison-Wesley Professional.
//
// An electronic version is also available from:
//
// http://brokestream.com/tex.pdf
//
// The most relevant "chapters" are:
// Data structures for boxes and their friends
// Shipping pages out (Ship class)
// Packaging (hpack and vpack)
// Data structures for math mode
// Subroutines for math mode
// Typesetting math formulas
//
// Many of the docstrings below refer to a numbered "node" in that
// book, e.g., node123
//
// Note that (as TeX) y increases downward.
package tex // import "github.com/go-latex/latex/tex"

26
vendor/github.com/go-latex/latex/tex/utils.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
// 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 tex
func maxInt(a, b int) int {
if a > b {
return a
}
return b
}
func clamp(v float64) float64 {
const (
min = -1000000000.
max = +1000000000.
)
switch {
case v < min:
return min
case v > max:
return max
}
return v
}

43
vendor/github.com/go-latex/latex/token/kind_string.go generated vendored Normal file
View File

@@ -0,0 +1,43 @@
// Code generated by "stringer -type Kind"; DO NOT EDIT.
// 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 token
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Invalid-0]
_ = x[Macro-1]
_ = x[EmptyLine-2]
_ = x[Comment-3]
_ = x[Space-4]
_ = x[Word-5]
_ = x[Number-6]
_ = x[Symbol-7]
_ = x[Lbrace-8]
_ = x[Rbrace-9]
_ = x[Lbrack-10]
_ = x[Rbrack-11]
_ = x[Lparen-12]
_ = x[Rparen-13]
_ = x[Other-14]
_ = x[Verbatim-15]
_ = x[EOF-16]
}
const _Kind_name = "InvalidMacroEmptyLineCommentSpaceWordNumberSymbolLbraceRbraceLbrackRbrackLparenRparenOtherVerbatimEOF"
var _Kind_index = [...]uint8{0, 7, 12, 21, 28, 33, 37, 43, 49, 55, 61, 67, 73, 79, 85, 90, 98, 101}
func (i Kind) String() string {
if i < 0 || i >= Kind(len(_Kind_index)-1) {
return "Kind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
}

50
vendor/github.com/go-latex/latex/token/token.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 token defines constants representing the lexical tokens of
// LaTeX documents.
package token // import "github.com/go-latex/latex/token"
//go:generate stringer -type Kind
import (
"go/token"
)
// Kind is a kind of LaTeX token.
type Kind int
const (
Invalid Kind = iota
Macro
EmptyLine
Comment
Space
Word
Number
Symbol // +,-,?,>,>=,...
Lbrace
Rbrace
Lbrack
Rbrack
Lparen
Rparen
Other
Verbatim
EOF
)
// Token holds informations about a token.
type Token struct {
Kind Kind // Kind is the kind of token.
Pos Pos // Pos is the position of a token.
Text string
}
func (t Token) String() string { return t.Text }
// Pos is a compact encoding of a source position within a file set.
//
// Aliased from go/token.Pos
type Pos = token.Pos